All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine
@ 2018-06-08 20:05 Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 01/13] hw/m68k: add via support Laurent Vivier
                   ` (15 more replies)
  0 siblings, 16 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

I'm rebasing some of these patches for seven years now,
too many years...

It's an RFC because things have changed in QEMU in seven years,
for instance the VIA has a new implementation (mos6522) introduced
by Mark Cave-Ayland and I didn't rework my implementation to
fit into this new one (any volunteers?), display has some glitches,
ADB devices are not identified correctly.

if you want to test the machine, I'm sorry, it doesn't boot
a MacROM, but you can boot a linux kernel from the command line.

You can install your own disk using debian-installer, with:

    ...
    -M q800 \
    -serial none -serial mon:stdio \
    -m 1000M -drive file=m68k.qcow2,format=qcow2 \
    -net nic,model=dp83932,addr=09:00:07:12:34:57 \
    -append "console=ttyS0 vga=off" \
    -kernel vmlinux-4.15.0-2-m68k \
    -initrd initrd.gz \
    -drive file=debian-9.0-m68k-NETINST-1.iso \
    -drive file=m68k.qcow2,format=qcow2 \
    -nographic

If you use a graphic adapter instead of "-nographic", you can use "-g" to set the
size of the display (I use "-g 1600x800x24").

You can get the ISO from:

https://cdimage.debian.org/mirror/cdimage/ports/9.0/m68k/iso-cd/debian-9.0-m68k-NETINST-1.iso

and extract the kernel and initrd.gz:

guestfish --add debian-9.0-m68k-NETINST-1.iso --ro \
          --mount /dev/sda:/ <<_EOF_
copy-out /install/cdrom/initrd.gz .
copy-out /install/kernels/vmlinux-4.15.0-2-m68k .
_EOF_

The mirror to use is: http://ftp.ports.debian.org/debian-ports/
when it fails, continue without boot loader.

In the same way, you can extract the kernel and the initramfs from the qcow2
image to use it with "-kernel" and "-initrd":

guestfish --add m68k.qcow2 --mount /dev/sda2:/ <<_EOF_
copy-out /boot/vmlinux-4.15.0-2-m68k .
copy-out /boot/initrd.img-4.15.0-2-m68k .
_EOF_

and boot with:

   ...
   -append "root=/dev/sda2 rw console=ttyS0 console=tty \
   -kernel vmlinux-4.15.0-2-m68k \
   -initrd initrd.img-4.15.0-2-m68k

Laurent Vivier (13):
  hw/m68k: add via support
  ADB: VIA probes ADB bus when it is idle
  escc: introduce a selector for the register bit
  hw/m68k: add video card
  hw/m68k: Apple Sound Chip (ASC) emulation
  ESP: add pseudo-DMA as used by Macintosh
  hw/m68k: add Nubus support
  hw/m68k: add a dummy SWIM floppy controller
  hw/m68k: define Macintosh Quadra 800
  dp8393x: fix dp8393x_receive
  dp8393x: manage big endian bus
  dp8393x: put DMA temp buffer in the state, not in the stack
  dp8393x: fix receiving buffer exhaustion

 arch_init.c                      |   4 +
 default-configs/m68k-softmmu.mak |  12 +
 hw/Makefile.objs                 |   1 +
 hw/audio/Makefile.objs           |   1 +
 hw/audio/asc.c                   | 492 ++++++++++++++++++++
 hw/block/Makefile.objs           |   1 +
 hw/block/swim.c                  | 325 +++++++++++++
 hw/char/escc.c                   |  30 +-
 hw/display/Makefile.objs         |   1 +
 hw/display/macfb-template.h      | 158 +++++++
 hw/display/macfb.c               | 335 ++++++++++++++
 hw/input/adb-kbd.c               |   4 +
 hw/input/adb-mouse.c             |   4 +
 hw/input/adb.c                   | 116 ++++-
 hw/m68k/Makefile.objs            |   6 +-
 hw/m68k/bootinfo.h               |  99 ++++
 hw/m68k/mac.c                    | 384 ++++++++++++++++
 hw/mips/mips_jazz.c              |   2 +-
 hw/misc/Makefile.objs            |   1 +
 hw/misc/mac_via.c                | 965 +++++++++++++++++++++++++++++++++++++++
 hw/net/dp8393x.c                 | 169 ++++---
 hw/nubus/Makefile.objs           |   4 +
 hw/nubus/mac.c                   | 112 +++++
 hw/nubus/nubus-bridge.c          |  34 ++
 hw/nubus/nubus-bus.c             |  60 +++
 hw/nubus/nubus-device.c          | 262 +++++++++++
 hw/scsi/esp.c                    | 330 +++++++++++--
 include/hw/audio/asc.h           |  21 +
 include/hw/char/escc.h           |   1 +
 include/hw/input/adb.h           |   9 +
 include/hw/misc/mac_via.h        |  45 ++
 include/hw/nubus/mac.h           |  24 +
 include/hw/nubus/nubus.h         |  89 ++++
 include/hw/scsi/esp.h            |  15 +-
 include/qemu/typedefs.h          |   2 +
 qemu-options.hx                  |   2 +-
 tests/qom-test.c                 |   5 +
 tests/test-hmp.c                 |   3 +-
 vl.c                             |   3 +-
 39 files changed, 4019 insertions(+), 112 deletions(-)
 create mode 100644 hw/audio/asc.c
 create mode 100644 hw/block/swim.c
 create mode 100644 hw/display/macfb-template.h
 create mode 100644 hw/display/macfb.c
 create mode 100644 hw/m68k/bootinfo.h
 create mode 100644 hw/m68k/mac.c
 create mode 100644 hw/misc/mac_via.c
 create mode 100644 hw/nubus/Makefile.objs
 create mode 100644 hw/nubus/mac.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/audio/asc.h
 create mode 100644 include/hw/misc/mac_via.h
 create mode 100644 include/hw/nubus/mac.h
 create mode 100644 include/hw/nubus/nubus.h

-- 
2.14.4

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 01/13] hw/m68k: add via support
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09 10:01   ` Mark Cave-Ayland
  2018-06-08 20:05 ` [Qemu-devel] [RFC 02/13] ADB: VIA probes ADB bus when it is idle Laurent Vivier
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/input/adb.c            |  99 ++++-
 hw/misc/Makefile.objs     |   1 +
 hw/misc/mac_via.c         | 940 ++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/input/adb.h    |   8 +
 include/hw/misc/mac_via.h |  45 +++
 5 files changed, 1092 insertions(+), 1 deletion(-)
 create mode 100644 hw/misc/mac_via.c
 create mode 100644 include/hw/misc/mac_via.h

diff --git a/hw/input/adb.c b/hw/input/adb.c
index 23ae6f0d75..2e5460730c 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)
 
@@ -57,7 +68,6 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
     return ADB_RET_NOTPRESENT;
 }
 
-/* XXX: move that to cuda ? */
 int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
 {
     ADBDevice *d;
@@ -84,6 +94,93 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
     return olen;
 }
 
+int adb_send(ADBBusState *adb, int state, uint8_t data)
+{
+    switch (state) {
+    case STATE_NEW:
+        adb->data_out[0] = data;
+        adb->data_out_index = 1;
+        break;
+    case STATE_EVEN:
+        if ((adb->data_out_index & 1) == 0) {
+            return 0;
+        }
+        adb->data_out[adb->data_out_index++] = data;
+        break;
+    case STATE_ODD:
+        if (adb->data_out_index & 1) {
+            return 0;
+        }
+        adb->data_out[adb->data_out_index++] = data;
+        break;
+    case STATE_IDLE:
+        return 0;
+    }
+    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;
+        }
+        *data = adb->data_in[adb->data_in_index++];
+        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;
+        }
+        *data = adb->data_in[adb->data_in_index++];
+        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;
+        if (adb->data_in_size < 0) {
+            *data = 0xff;
+            qemu_irq_raise(adb->data_ready);
+            return -1;
+        }
+        if (adb->data_in_size == 0) {
+            return 0;
+        }
+        *data = adb->data_in[0];
+        adb->data_in_index = 1;
+        break;
+    }
+    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/Makefile.objs b/hw/misc/Makefile.objs
index 00e834d0f0..2cd8941faa 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -68,5 +68,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..a6a11c5b3d
--- /dev/null
+++ b/hw/misc/mac_via.c
@@ -0,0 +1,940 @@
+/*
+ * 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/input/adb.h"
+#include "sysemu/sysemu.h"
+#include "qemu/cutils.h"
+
+/* debug VIA */
+#undef DEBUG_VIA
+
+#ifdef DEBUG_VIA
+#define VIA_DPRINTF(fmt, ...)                                  \
+    do { printf("VIA%d: " fmt , via, ## __VA_ARGS__); } while (0)
+#else
+#define VIA_DPRINTF(fmt, ...)
+#endif
+
+/*
+ * 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
+
+typedef struct VIATimer {
+    int index;
+    uint16_t counter; /* Timer counter */
+    uint16_t latch;   /* Timer latch */
+    int64_t next_irq_time;
+    QEMUTimer *timer;
+} VIATimer;
+
+typedef struct VIAState {
+    /* VIA registers */
+    uint8_t a;    /* data register A */
+    uint8_t b;    /* data register B */
+    uint8_t dira; /* data direction register A (1 = output) */
+    uint8_t dirb; /* data direction register B (1 = output) */
+    uint8_t pcr;  /* peripheral control register */
+    uint8_t acr;  /* auxiliary control register */
+    uint8_t ifr;  /* interrupt flag register */
+    uint8_t ier;  /* interrupt enable register */
+    uint8_t sr;   /* shift register */
+
+    uint8_t last_b;
+
+    /* Timers */
+
+    VIATimer timers[2];
+
+    /* IRQs */
+
+    qemu_irq out_irq;
+
+} VIAState;
+
+typedef struct MacVIAState {
+    SysBusDevice busdev;
+
+    /* MMIO */
+
+    MemoryRegion mmio;
+
+    /* VIAs */
+
+    VIAState via[2];
+
+    /* 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;
+
+#define VIA_TIMER_FREQ (783360)
+
+static int64_t get_next_irq_time(VIATimer *s, int64_t current_time)
+{
+    int64_t d, next_time;
+
+    /* current counter value */
+    d = muldiv64(current_time, VIA_TIMER_FREQ, NANOSECONDS_PER_SECOND);
+    next_time = d + s->counter;
+    next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, VIA_TIMER_FREQ);
+    if (next_time <= current_time) {
+        next_time = current_time + 1;
+    }
+    return next_time;
+}
+
+#define T1MODE      0xc0
+#define T1MODE_CONT 0x40
+
+static void via_arm_timer(VIATimer *ti, int64_t current_time)
+{
+    if (!ti->timer) {
+        return;
+    }
+    ti->next_irq_time = get_next_irq_time(ti, current_time);
+    timer_mod(ti->timer, ti->next_irq_time);
+}
+
+static void via_timer_update(VIAState *s, VIATimer *ti,
+                             int64_t current_time)
+{
+    if (!ti->timer) {
+        return;
+    }
+    if (!(s->ier & VIA_IRQ_TIMER1) &&
+        (s->acr & T1MODE) != T1MODE_CONT) {
+        timer_del(ti->timer);
+    } else {
+        ti->counter = ti->latch;
+        via_arm_timer(ti, current_time);
+    }
+}
+
+static void via_update_irq(VIAState *s)
+{
+    if (s->ifr & s->ier) {
+        qemu_irq_raise(s->out_irq);
+    } else {
+        qemu_irq_lower(s->out_irq);
+    }
+}
+
+static void via_timer1(void *opaque)
+{
+    VIAState *s = opaque;
+    VIATimer *ti = &s->timers[0];
+
+    via_timer_update(s, ti, ti->next_irq_time);
+    s->ifr |= VIA_IRQ_TIMER1;
+    via_update_irq(s);
+}
+
+static void via1_VBL_update(MacVIAState *m)
+{
+    if (m->via[0].ifr & m->via[0].ier & VIA1_IRQ_VBLANK) { /* 60 Hz irq */
+        timer_mod(m->VBL_timer, (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16630)
+                  / 16630 * 16630);
+    } else {
+        timer_del(m->VBL_timer);
+    }
+}
+
+static void via1_VBL(void *opaque)
+{
+    MacVIAState *m = opaque;
+    via1_VBL_update(m);
+    m->via[0].ifr |= VIA1_IRQ_VBLANK;
+    via_update_irq(&m->via[0]);
+}
+
+static void via1_irq_request(VIAState *s, int irq, int level)
+{
+    if (level) {
+        s->ifr |= 1 << irq;
+    } else {
+        s->ifr &= ~(1 << irq);
+    }
+    via_update_irq(s);
+}
+
+static void via2_irq_request(VIAState *s, int irq, int level)
+{
+    if (level) {
+        s->ifr |= 1 << irq;
+    } else {
+        s->ifr &= ~(1 << irq);
+    }
+    via_update_irq(s);
+}
+
+static void via_irq_request(void *opaque, int irq, int level)
+{
+    MacVIAState *s = opaque;
+    if (irq < VIA1_IRQ_NB) {
+        via1_irq_request(&s->via[0], irq, level);
+        return;
+    }
+    irq -= VIA1_IRQ_NB;
+    if (irq < VIA2_IRQ_NB) {
+        via2_irq_request(&s->via[1], irq, level);
+        return;
+    }
+}
+
+static void via1_one_second_update(MacVIAState *m)
+{
+    if (m->via[0].ifr & m->via[0].ier & VIA1_IRQ_ONE_SECOND) {
+        timer_mod(m->one_second_timer, (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
+                  + 1000) / 1000 * 1000);
+    } else {
+        timer_del(m->one_second_timer);
+    }
+}
+
+static void via1_one_second(void *opaque)
+{
+    MacVIAState *m = opaque;
+    via1_one_second_update(m);
+    m->via[0].ifr |= VIA1_IRQ_ONE_SECOND;
+    via_update_irq(&m->via[0]);
+}
+
+static void via_irq_update(MacVIAState *m, int via)
+{
+    switch (via) {
+    case 0:
+        via1_one_second_update(m);
+        via1_VBL(m);
+        break;
+    case 1:
+        break;
+    }
+}
+
+#define RTC_OFFSET 2082844800
+static uint8_t PRAM[256];
+
+static void via1_rtc_update(MacVIAState *m)
+{
+    VIAState *s = &m->via[0];
+
+    if (s->b & VIA1B_vRTCEnb) {
+        return;
+    }
+
+    if (s->dirb & VIA1B_vRTCData) {
+        /* send bits to the RTC */
+        if (!(s->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 ((s->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 void via1_adb_update(MacVIAState *m)
+{
+    VIAState *s = &m->via[0];
+    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->b &= ~VIA1B_vADBInt;
+        } else {
+            s->b |= VIA1B_vADBInt;
+        }
+    }
+}
+
+static void via_write(void *opaque, hwaddr addr,
+                       uint64_t val, unsigned int size)
+{
+    MacVIAState *m = opaque;
+    VIAState *s;
+    int via;
+
+    via = addr / VIA_SIZE;
+    addr &= VIA_SIZE - 1;
+
+    s = &m->via[via];
+
+    switch (addr) {
+    case vBufA: /* Buffer A */
+        VIA_DPRINTF("writeb: vBufA = %02"PRIx64"\n", val);
+        s->a = (s->a & ~s->dira) | (val & s->dira);
+        break;
+    case vBufB:  /* Register B */
+        VIA_DPRINTF("writeb: vBufB = %02"PRIx64"\n", val);
+        s->b = (s->b & ~s->dirb) | (val & s->dirb);
+        switch (via) {
+        case 0:
+            via1_rtc_update(m);
+            via1_adb_update(m);
+            s->last_b = s->b;
+            break;
+        case 1:
+            if (s->dirb & VIA2B_vPower &&
+                (val & VIA2B_vPower) == 0) {
+                /* shutdown */
+                qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+            }
+            break;
+        }
+        break;
+    case vDirA:  /* Data Direction Register A. */
+        VIA_DPRINTF("writeb: vDirA = %02"PRIx64"\n", val);
+        s->dira = val;
+        break;
+    case vDirB:  /* Data Direction Register B. */
+        VIA_DPRINTF("writeb: vDirB = %02"PRIx64"\n", val);
+        s->dirb = val;
+        break;
+    case vT1CL:  /* Timer one counter low. */
+        VIA_DPRINTF("writeb: vT1CL = %02"PRIx64"\n", val);
+        s->timers[0].counter = (s->timers[0].counter & 0xff00) | val;
+        break;
+    case vT1CH:  /* Timer one counter high. */
+        VIA_DPRINTF("writeb: vT1CH = %02"PRIx64"\n", val);
+        s->timers[0].counter = (s->timers[0].counter & 0x00ff) | (val << 8);
+        via_arm_timer(&s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+        break;
+    case vT1LL:  /* Timer one latches low. */
+        VIA_DPRINTF("writeb: vT1LL = %02"PRIx64"\n", val);
+        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
+        break;
+    case vT1LH:  /* Timer one latches high. */
+        VIA_DPRINTF("writeb: vT1LH = %02"PRIx64"\n", val);
+        s->timers[0].latch = (s->timers[0].latch & 0x00ff) | (val << 8);
+        via_arm_timer(&s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+        break;
+    case vT2CL:  /* Timer two counter low. */
+        VIA_DPRINTF("writeb: vT2CL = %02"PRIx64"\n", val);
+        s->timers[1].counter = (s->timers[1].counter & 0xff00) | val;
+        break;
+    case vT2CH:  /* Timer two counter high. */
+        VIA_DPRINTF("writeb: vT2CH = %02"PRIx64"\n", val);
+        s->timers[1].counter = (s->timers[1].counter & 0x00ff) | (val << 8);
+        via_arm_timer(&s->timers[1], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+        break;
+    case vSR:    /* Shift register. */
+        VIA_DPRINTF("writeb: vSR = %02"PRIx64"\n", val);
+        s->sr = val;
+        break;
+    case vACR:   /* Auxilary control register. */
+        VIA_DPRINTF("writeb: vACR = %02"PRIx64"\n", val);
+        s->acr = val;
+        via_timer_update(s, &s->timers[0],
+                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+        break;
+    case vPCR:   /* Peripheral control register. */
+        VIA_DPRINTF("writeb: vPCR = %02"PRIx64"\n", val);
+        s->pcr = val;
+        break;
+    case vIFR:   /* Interrupt flag register. */
+        VIA_DPRINTF("writeb: vIFR = %02"PRIx64"\n", val);
+        if (val & IRQ_SET) {
+            /* set bits */
+            s->ifr |= val & 0x7f;
+        } else {
+            /* clear bits */
+            s->ifr &= ~val;
+        }
+        VIA_DPRINTF("            -> %02x\n", s->ifr);
+        via_timer_update(s, &s->timers[0],
+                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+        via_irq_update(m, via);
+        break;
+    case vIER:   /* Interrupt enable register. */
+        VIA_DPRINTF("writeb: vIER = %02"PRIx64"\n", val);
+        if (val & IRQ_SET) {
+            /* set bits */
+            s->ier |= val & 0x7f;
+        } else {
+            /* clear bits */
+            s->ier &= ~val;
+        }
+        VIA_DPRINTF("            -> %02x\n", s->ier);
+        via_timer_update(s, &s->timers[0],
+                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+        via_irq_update(m, via);
+        break;
+    default:
+        VIA_DPRINTF("writeb: addr 0x%08lx val %02"PRIx64"\n", (long)addr, val);
+        break;
+    }
+}
+
+static uint64_t via_read(void *opaque, hwaddr addr,
+                         unsigned int size)
+{
+    MacVIAState *m = opaque;
+    VIAState *s;
+    uint32_t val;
+    int via;
+
+    via = addr / VIA_SIZE;
+    addr &= VIA_SIZE - 1;
+
+    s = &m->via[via];
+
+    switch (addr) {
+    case vBufA: /* Buffer A */
+        val = s->a;
+        VIA_DPRINTF("readb:  vBufA = %02x\n", val);
+        break;
+    case vBufB:  /* Register B */
+        val = s->b;
+        VIA_DPRINTF("readb:  vBufB = %02x\n", val);
+        break;
+    case vDirA:  /* Data Direction Register A. */
+        val = s->dira;
+        VIA_DPRINTF("readb:  vDirA = %02x\n", val);
+        break;
+    case vDirB:  /* Data Direction Register B. */
+        val = s->dirb;
+        VIA_DPRINTF("readb:  vDirB = %02x\n", val);
+        break;
+    case vT1CL:  /* Timer one counter low. */
+        val = s->timers[0].counter & 0x00ff;
+        VIA_DPRINTF("readb:  vT1CL = %02x\n", val);
+        break;
+    case vT1CH:  /* Timer one counter high. */
+        val = (s->timers[0].counter >> 8) & 0x00ff;
+        VIA_DPRINTF("readb:  vT1CH = %02x\n", val);
+        break;
+    case vT1LL:  /* Timer one latches low. */
+        val = s->timers[0].latch & 0x00ff;
+        VIA_DPRINTF("readb:  vT1LL = %02x\n", val);
+        break;
+    case vT1LH:  /* Timer one latches high. */
+        val = (s->timers[0].latch >> 8) & 0x00ff;
+        VIA_DPRINTF("readb:  vT1LH = %02x\n", val);
+        break;
+    case vT2CL:  /* Timer two counter low. */
+        val = s->timers[1].counter & 0x00ff;
+        VIA_DPRINTF("readb:  vT2CL = %02x\n", val);
+        break;
+    case vT2CH:  /* Timer two counter high. */
+        val = (s->timers[1].counter >> 8) & 0x00ff;
+        VIA_DPRINTF("readb:  vT2CH = %02x\n", val);
+        break;
+    case vSR:    /* Shift register. */
+        val = s->sr;
+        VIA_DPRINTF("readb:  vSR = %02x\n", val);
+        break;
+    case vACR:   /* Auxilary control register. */
+        val = s->acr;
+        VIA_DPRINTF("readb:  vACR = %02x\n", val);
+        break;
+    case vPCR:   /* Peripheral control register. */
+        val = s->pcr;
+        VIA_DPRINTF("readb:  vPCR = %02x\n", val);
+        break;
+    case vIFR:   /* Interrupt flag register. */
+        val = s->ifr | ((s->ifr & 0x7f) ? IRQ_SET : 0);
+        VIA_DPRINTF("readb:  vIFR = %02x\n", val);
+        break;
+    case vIER:   /* Interrupt enable register. */
+        val = s->ier | IRQ_SET;
+        VIA_DPRINTF("readb:  vIER = %02x\n", val);
+        break;
+    default:
+        val = 0;
+        VIA_DPRINTF("readb:  addr 0x%08lx val ??\n", (long)addr);
+        break;
+    }
+    return val;
+}
+
+static const MemoryRegionOps via_ops = {
+    .read = via_read,
+    .write = via_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void mac_via_reset(DeviceState *dev)
+{
+    MacVIAState *m = MAC_VIA(dev);
+
+    m->via[0].a = 0;
+    /* 1 = disabled */
+    m->via[0].b = VIA1B_vADB_StateMask | VIA1B_vADBInt | VIA1B_vRTCEnb;
+    m->via[0].dira = 0;
+    m->via[0].dirb = 0;
+    m->via[0].pcr = 0;
+    m->via[0].acr = 0;
+    m->via[0].ifr = 0;
+    m->via[0].ier = 0;
+    m->via[0].sr = 0;
+    m->via[0].last_b = 0;
+
+    m->via[0].timers[0].counter = 0;
+    m->via[0].timers[0].latch = 0;
+    m->via[0].timers[1].counter = 0;
+    m->via[0].timers[1].latch = 0;
+
+    m->via[1].a = 0;
+    m->via[1].b = 0;
+    m->via[1].dira = 0;
+    m->via[1].dirb = 0;
+    m->via[1].pcr = 0;
+    m->via[1].acr = 0;
+    m->via[1].ifr = 0;
+    m->via[1].ier = 0;
+    m->via[1].sr = 0;
+    m->via[1].last_b = 0;
+
+    m->via[1].timers[0].counter = 0;
+    m->via[1].timers[0].latch = 0;
+    m->via[1].timers[1].counter = 0;
+    m->via[1].timers[1].latch = 0;
+
+    m->data_out = 0;
+    m->data_out_cnt = 0;
+    m->data_in = 0;
+    m->data_in_cnt = 0;
+    m->cmd = 0;
+    m->wprotect = 0;
+    m->alt = 0;
+}
+
+static void mac_via_realizefn(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;
+
+    /* ouput IRQs */
+
+    m->via[0].timers[0].index = 0;
+    m->via[0].timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                             via_timer1, &m->via[0]);
+    m->via[0].timers[1].index = 1;
+
+    /* VIA 2 */
+
+    /* output IRQs */
+
+    m->via[1].timers[0].index = 0;
+    m->via[1].timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                             via_timer1, &m->via[1]);
+    m->via[1].timers[1].index = 1;
+}
+
+static void mac_via_initfn(Object *obj)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    MacVIAState *m = MAC_VIA(obj);
+
+    memory_region_init_io(&m->mmio, NULL, &via_ops, m, "via", 2 * VIA_SIZE);
+    sysbus_init_mmio(d, &m->mmio);
+
+    /* input IRQs */
+
+    qdev_init_gpio_in(DEVICE(d), via_irq_request, VIA1_IRQ_NB + VIA2_IRQ_NB);
+
+    /* ouput IRQs */
+
+    sysbus_init_irq(d, &m->via[0].out_irq);
+    sysbus_init_irq(d, &m->via[1].out_irq);
+
+    /* ABD */
+
+    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(DEVICE(d),
+                                             VIA1_IRQ_ADB_READY_BIT);
+}
+
+static void mac_via_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = mac_via_realizefn;
+    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_initfn,
+    .class_init = mac_via_class_init,
+};
+
+static void mac_via_register_types(void)
+{
+    type_register_static(&mac_via_info);
+}
+
+type_init(mac_via_register_types);
diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h
index 3ae8445e95..ce393004eb 100644
--- a/include/hw/input/adb.h
+++ b/include/hw/input/adb.h
@@ -75,6 +75,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,
@@ -84,4 +90,6 @@ 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_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
new file mode 100644
index 0000000000..e106133c2a
--- /dev/null
+++ b/include/hw/misc/mac_via.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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
+#define TYPE_MAC_VIA "mac_via"
+#define MAC_VIA(obj)   OBJECT_CHECK(MacVIAState, (obj), TYPE_MAC_VIA)
+
+/* VIA1 */
+
+#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)
+
+/* VIA2 */
+
+#define VIA2_IRQ_SCSI_DATA_BIT  (VIA1_IRQ_NB + 0)
+#define VIA2_IRQ_SLOT_BIT       (VIA1_IRQ_NB + 1)
+#define VIA2_IRQ_UNUSED_BIT     (VIA1_IRQ_NB + 2)
+#define VIA2_IRQ_SCSI_BIT       (VIA1_IRQ_NB + 3)
+#define VIA2_IRQ_ASC_BIT        (VIA1_IRQ_NB + 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)
+#endif
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 02/13] ADB: VIA probes ADB bus when it is idle
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 01/13] hw/m68k: add via support Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 03/13] escc: introduce a selector for the register bit Laurent Vivier
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/input/adb-kbd.c     |  4 ++++
 hw/input/adb-mouse.c   |  4 ++++
 hw/input/adb.c         | 33 +++++++++++++++++++++++++--------
 hw/misc/mac_via.c      | 27 ++++++++++++++++++++++++++-
 include/hw/input/adb.h |  1 +
 5 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 50b62712c8..7de92935b8 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 3ba6027d33..a3f0b74dd1 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 2e5460730c..756122ac09 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -94,28 +94,47 @@ 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[0] = data;
-        adb->data_out_index = 1;
+        adb->data_out_index = 0;
         break;
     case STATE_EVEN:
         if ((adb->data_out_index & 1) == 0) {
             return 0;
         }
-        adb->data_out[adb->data_out_index++] = data;
         break;
     case STATE_ODD:
         if (adb->data_out_index & 1) {
             return 0;
         }
-        adb->data_out[adb->data_out_index++] = data;
         break;
     case STATE_IDLE:
         return 0;
     }
+    adb->data_out[adb->data_out_index++] = data;
     qemu_irq_raise(adb->data_ready);
     return 1;
 }
@@ -138,7 +157,6 @@ int adb_receive(ADBBusState *adb, int state, uint8_t *data)
         if ((adb->data_in_index & 1) == 0) {
             return 0;
         }
-        *data = adb->data_in[adb->data_in_index++];
         break;
     case STATE_ODD:
         if (adb->data_in_size <= 0) {
@@ -153,7 +171,6 @@ int adb_receive(ADBBusState *adb, int state, uint8_t *data)
         if (adb->data_in_index & 1) {
             return 0;
         }
-        *data = adb->data_in[adb->data_in_index++];
         break;
     case STATE_IDLE:
         if (adb->data_out_index == 0) {
@@ -162,6 +179,7 @@ int adb_receive(ADBBusState *adb, int state, uint8_t *data)
         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);
@@ -170,10 +188,9 @@ int adb_receive(ADBBusState *adb, int state, uint8_t *data)
         if (adb->data_in_size == 0) {
             return 0;
         }
-        *data = adb->data_in[0];
-        adb->data_in_index = 1;
         break;
     }
+    *data = adb->data_in[adb->data_in_index++];
     qemu_irq_raise(adb->data_ready);
     if (*data == 0xff || *data == 0) {
         return 0;
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index a6a11c5b3d..055091535f 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -247,6 +247,8 @@
 #define VIA1B_vADB_StateMask    (VIA1B_vADBS1 | VIA1B_vADBS2)
 #define VIA1B_vADB_StateShift   4
 
+#define VIA_ADB_POLL_FREQ 50 /* XXX: not real */
+
 typedef struct VIATimer {
     int index;
     uint16_t counter; /* Timer counter */
@@ -305,6 +307,7 @@ typedef struct MacVIAState {
     /* ADB */
 
     ADBBusState adb_bus;
+    QEMUTimer *adb_poll_timer;
 
     /* external timers */
 
@@ -596,7 +599,7 @@ static void via1_adb_update(MacVIAState *m)
     } else {
         /* input mode */
         ret = adb_receive(&m->adb_bus, state, &s->sr);
-        if (ret > 0) {
+        if (ret > 0 && s->sr != 0xff) {
             s->b &= ~VIA1B_vADBInt;
         } else {
             s->b |= VIA1B_vADBInt;
@@ -604,6 +607,23 @@ static void via1_adb_update(MacVIAState *m)
     }
 }
 
+static void via_adb_poll(void *opaque)
+{
+    MacVIAState *m = opaque;
+    VIAState *s = &m->via[0];
+    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 void via_write(void *opaque, hwaddr addr,
                        uint64_t val, unsigned int size)
 {
@@ -858,6 +878,10 @@ static void mac_via_reset(DeviceState *dev)
     m->cmd = 0;
     m->wprotect = 0;
     m->alt = 0;
+
+    timer_mod(m->adb_poll_timer,
+              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+              (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ));
 }
 
 static void mac_via_realizefn(DeviceState *dev, Error **errp)
@@ -872,6 +896,7 @@ static void mac_via_realizefn(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);
 
     /* ouput IRQs */
 
diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h
index ce393004eb..9ef7fa2f0e 100644
--- a/include/hw/input/adb.h
+++ b/include/hw/input/adb.h
@@ -90,6 +90,7 @@ 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 */
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 03/13] escc: introduce a selector for the register bit
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 01/13] hw/m68k: add via support Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 02/13] ADB: VIA probes ADB bus when it is idle Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09 10:05   ` Mark Cave-Ayland
  2018-06-08 20:05 ` [Qemu-devel] [RFC 04/13] hw/m68k: add video card Laurent Vivier
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier, Laurent Vivier

From: Laurent Vivier <Laurent@Vivier.EU>

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 <laurent@vivier.eu>
---
 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;
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 04/13] hw/m68k: add video card
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (2 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 03/13] escc: introduce a selector for the register bit Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09 10:14   ` Mark Cave-Ayland
  2018-06-08 20:05 ` [Qemu-devel] [RFC 05/13] hw/m68k: Apple Sound Chip (ASC) emulation Laurent Vivier
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

From: Laurent Vivier <Laurent@Vivier.EU>

Signed-off-by: Laurent Vivier <Laurent@Vivier.EU>
---
 arch_init.c                 |   4 +
 hw/display/Makefile.objs    |   1 +
 hw/display/macfb-template.h | 158 +++++++++++++++++++++++++
 hw/display/macfb.c          | 283 ++++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx             |   2 +-
 vl.c                        |   3 +-
 6 files changed, 449 insertions(+), 2 deletions(-)
 create mode 100644 hw/display/macfb-template.h
 create mode 100644 hw/display/macfb.c

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 b5d97ab26d..925d5b848f 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -19,6 +19,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..b2dd300a80
--- /dev/null
+++ b/hw/display/macfb.c
@@ -0,0 +1,283 @@
+/*
+ * 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"
+
+struct MacfbState {
+    SysBusDevice busdev;
+    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;
+};
+typedef struct MacfbState MacfbState;
+
+#define TYPE_MACFB "sysbus-macfb"
+#define MACFB(obj) \
+    OBJECT_CHECK(MacfbSysBusState, (obj), TYPE_MACFB)
+
+#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 inline void reset_dirty(MacfbState *s,
+                               ram_addr_t page_min, ram_addr_t page_max)
+{
+    memory_region_reset_dirty(&s->mem_vram,
+                              page_min,
+                              page_max + MACFB_PAGE_SIZE - page_min - 1,
+                              DIRTY_MEMORY_VGA);
+}
+
+static void macfb_draw_graphic(MacfbState *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    ram_addr_t page, page_min, page_max;
+    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;
+    }
+
+    page_min = (ram_addr_t)-1;
+    page_max = 0;
+    ymin = -1;
+    page = 0;
+    for (y = 0; y < s->height; y++) {
+        int update;
+
+        update = memory_region_get_dirty(&s->mem_vram, page, macfb_stride,
+                                         DIRTY_MEMORY_VGA);
+
+        if (update) {
+            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;
+            }
+            if (page_min == (ram_addr_t)-1) {
+                page_min = page;
+            }
+            page_max = page + macfb_stride - 1;
+        } else {
+            if (ymin >= 0) {
+                dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
+                ymin = -1;
+            }
+        }
+        page += macfb_stride;
+    }
+    if (ymin >= 0) {
+        dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
+    }
+    if (page_min != (ram_addr_t)-1) {
+        reset_dirty(s, page_min, page_max);
+    }
+}
+
+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_init(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, "ctrl",
+                          0x1000);
+    memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram", MACFB_VRAM_SIZE,
+                               s->vram);
+    vmstate_register_ram(&s->mem_vram, dev);
+    memory_region_set_coalescing(&s->mem_vram);
+}
+
+typedef struct {
+    SysBusDevice busdev;
+    MacfbState macfb;
+} MacfbSysBusState;
+
+static int macfb_sysbus_init(SysBusDevice *dev)
+{
+    MacfbState *s =  &MACFB(dev)->macfb;
+
+    macfb_init(DEVICE(dev), s);
+    sysbus_init_mmio(dev, &s->mem_ctrl);
+    sysbus_init_mmio(dev, &s->mem_vram);
+
+    return 0;
+}
+
+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);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = macfb_sysbus_init;
+    dc->desc = "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/qemu-options.hx b/qemu-options.hx
index c0d3951e9f..c1181561e1 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1551,7 +1551,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 06031715ac..ac8e50ee92 100644
--- a/vl.c
+++ b/vl.c
@@ -3308,7 +3308,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') {
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 05/13] hw/m68k: Apple Sound Chip (ASC) emulation
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (3 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 04/13] hw/m68k: add video card Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh Laurent Vivier
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

From: Laurent Vivier <Laurent@Vivier.EU>

This is broken as the linux driver seems broken too...

Signed-off-by: Laurent Vivier <Laurent@Vivier.EU>
---
 hw/audio/Makefile.objs |   1 +
 hw/audio/asc.c         | 492 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/audio/asc.h |  21 +++
 3 files changed, 514 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..3c07d4fa91
--- /dev/null
+++ b/hw/audio/asc.c
@@ -0,0 +1,492 @@
+/*
+ *  QEMU Apple Sound Chip emulation
+ *
+ *  Apple Sound Chip (ASC) 344S0063
+ *  Enhanced Apple Sound Chip (EASC) 343S1063
+ *
+ *  Copyright (c) 2012-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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
+};
+
+struct ASCState {
+    SysBusDevice busdev;
+    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];
+};
+typedef struct ASCState ASCState;
+
+#define TYPE_ASC  "apple-sound-chip"
+#define ASC(obj) OBJECT_CHECK(ASCSysBusState, (obj), TYPE_ASC)
+
+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()
+    }
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    ASCState asc;
+} ASCSysBusState;
+
+static int asc_sysbus_init(SysBusDevice *dev)
+{
+    ASCState *s = &ASC(dev)->asc;
+    struct audsettings as;
+
+    s->fifo = g_malloc0(ASC_BUF_SIZE);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    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);
+
+    memory_region_init_io(&s->mem_regs, NULL, &asc_mmio_ops, s, "asc",
+                          ASC_LENGTH);
+    sysbus_init_mmio(dev, &s->mem_regs);
+
+    return 0;
+}
+
+static void asc_sysbus_reset(DeviceState *d)
+{
+    ASCSysBusState *s = ASC(d);
+
+    AUD_set_active_out(s->asc.channel, 0);
+
+    memset(s->asc.regs, 0, sizeof(s->asc.regs));
+    s->asc.a_wptr = 0;
+    s->asc.a_rptr = 0;
+    s->asc.a_cnt = 0;
+    s->asc.b_wptr = 0;
+    s->asc.b_rptr = 0;
+    s->asc.b_cnt = 0;
+}
+
+static Property asc_sysbus_properties[] = {
+    DEFINE_PROP_UINT8("asctype", ASCSysBusState, asc.type, ASC_TYPE_ASC),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void asc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = asc_sysbus_init;
+    dc->reset = asc_sysbus_reset;
+    dc->vmsd = &vmstate_asc;
+    dc->props = asc_sysbus_properties;
+}
+
+static TypeInfo asc_sysbus_info = {
+    .name = TYPE_ASC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ASCSysBusState),
+    .class_init = asc_class_init,
+};
+
+static void asc_register_types(void)
+{
+    type_register_static(&asc_sysbus_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..f2a292bbb0
--- /dev/null
+++ b/include/hw/audio/asc.h
@@ -0,0 +1,21 @@
+/*
+ *  Copyright (c) 2012-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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
+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) */
+};
+#endif
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (4 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 05/13] hw/m68k: Apple Sound Chip (ASC) emulation Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09  8:57   ` Hervé Poussineau
  2018-06-09 10:19   ` Mark Cave-Ayland
  2018-06-08 20:05 ` [Qemu-devel] [RFC 07/13] hw/m68k: add Nubus support Laurent Vivier
                   ` (9 subsequent siblings)
  15 siblings, 2 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

From: Laurent Vivier <Laurent@Vivier.EU>

Signed-off-by: Laurent Vivier <Laurent@Vivier.EU>
---
 hw/mips/mips_jazz.c   |   2 +-
 hw/scsi/esp.c         | 330 +++++++++++++++++++++++++++++++++++++++++++++-----
 include/hw/scsi/esp.h |  15 ++-
 3 files changed, 313 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..4d7fa71309 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,10 +872,44 @@ 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);
+
+    return esp;
+}
+
+ESPState *esp_init_pdma(hwaddr espaddr, int it_shift,
+                        hwaddr pdmaaddr,
+                        qemu_irq irq, qemu_irq irq_data,
+                        qemu_irq *reset, qemu_irq *dma_enable)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    SysBusESPState *sysbus;
+    ESPState *esp;
+
+    dev = qdev_create(NULL, "esp");
+    sysbus = ESP_STATE(dev);
+    esp = &sysbus->esp;
+    esp->dma_memory_read = NULL;
+    esp->dma_memory_write = NULL;
+    esp->dma_opaque = NULL;
+    sysbus->it_shift = it_shift;
+    /* XXX for now until rc4030 has been changed to use DMA enable signal */
+    esp->dma_enabled = 1;
+    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);
+    sysbus_mmio_map(s, 1, pdmaaddr);
     *reset = qdev_get_gpio_in(dev, 0);
     *dma_enable = qdev_get_gpio_in(dev, 1);
 
+    scsi_bus_legacy_handle_cmdline(&esp->bus);
+
     return esp;
 }
 
@@ -681,12 +945,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..de6c490acd 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,12 @@ 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);
+ESPState *esp_init_pdma(hwaddr espaddr, int it_shift,
+                   hwaddr pdmaaddr,
+                   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);
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 07/13] hw/m68k: add Nubus support
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (5 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 08/13] hw/m68k: add a dummy SWIM floppy controller Laurent Vivier
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/Makefile.objs         |   1 +
 hw/display/macfb.c       |  67 +++++++++++-
 hw/nubus/Makefile.objs   |   4 +
 hw/nubus/mac.c           | 112 +++++++++++++++++++
 hw/nubus/nubus-bridge.c  |  34 ++++++
 hw/nubus/nubus-bus.c     |  60 +++++++++++
 hw/nubus/nubus-device.c  | 275 +++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/nubus/mac.h   |  24 +++++
 include/hw/nubus/nubus.h |  89 +++++++++++++++
 include/qemu/typedefs.h  |   2 +
 10 files changed, 663 insertions(+), 5 deletions(-)
 create mode 100644 hw/nubus/Makefile.objs
 create mode 100644 hw/nubus/mac.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.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 b2dd300a80..295fd0fc8a 100644
--- a/hw/display/macfb.c
+++ b/hw/display/macfb.c
@@ -14,9 +14,12 @@
 #include "hw/sysbus.h"
 #include "ui/console.h"
 #include "ui/pixel_ops.h"
+#include "hw/nubus/nubus.h"
+
+#define VIDEO_BASE 0x00001000
+#define DAFB_BASE  0x00800000
 
 struct MacfbState {
-    SysBusDevice busdev;
     MemoryRegion mem_vram;
     MemoryRegion mem_ctrl;
     QemuConsole *con;
@@ -219,10 +222,10 @@ static void macfb_init(DeviceState *dev, MacfbState *s)
 
     s->con = graphic_console_init(dev, 0, &macfb_ops, s);
 
-    memory_region_init_io(&s->mem_ctrl, NULL, &macfb_ctrl_ops, s, "ctrl",
+    memory_region_init_io(&s->mem_ctrl, NULL, &macfb_ctrl_ops, s, "macfb-ctrl",
                           0x1000);
-    memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram", MACFB_VRAM_SIZE,
-                               s->vram);
+    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);
 }
@@ -232,6 +235,11 @@ typedef struct {
     MacfbState macfb;
 } MacfbSysBusState;
 
+typedef struct {
+    NubusDevice busdev;
+    MacfbState macfb;
+} MacfbNubusState;
+
 static int macfb_sysbus_init(SysBusDevice *dev)
 {
     MacfbState *s =  &MACFB(dev)->macfb;
@@ -243,12 +251,34 @@ static int macfb_sysbus_init(SysBusDevice *dev)
     return 0;
 }
 
+const uint8_t macfb_rom[] = {
+    255, 0, 0, 0,
+};
+
+static int macfb_nubus_init(NubusDevice *dev)
+{
+    MacfbState *s = &DO_UPCAST(MacfbNubusState, busdev, dev)->macfb;
+
+    macfb_init(DEVICE(dev), s);
+    nubus_add_slot_mmio(dev, DAFB_BASE, &s->mem_ctrl);
+    nubus_add_slot_mmio(dev, VIDEO_BASE, &s->mem_vram);
+    nubus_register_rom(dev, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
+
+    return 0;
+}
+
 static void macfb_sysbus_reset(DeviceState *d)
 {
     MacfbSysBusState *s = MACFB(d);
     macfb_reset(&s->macfb);
 }
 
+static void macfb_nubus_reset(DeviceState *d)
+{
+    MacfbNubusState *s = DO_UPCAST(MacfbNubusState, busdev.qdev, 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),
@@ -256,18 +286,37 @@ 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);
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
     k->init = macfb_sysbus_init;
-    dc->desc = "Macintosh framebuffer";
+    dc->desc = "SysBus Macintosh framebuffer";
     dc->reset = macfb_sysbus_reset;
     dc->vmsd = &vmstate_macfb;
     dc->props = macfb_sysbus_properties;
 }
 
+static void macfb_nubus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    NubusDeviceClass *k = NUBUS_DEVICE_CLASS(klass);
+
+    k->init = macfb_nubus_init;
+    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,
@@ -275,9 +324,17 @@ static TypeInfo macfb_sysbus_info = {
     .class_init    = macfb_sysbus_class_init,
 };
 
+static TypeInfo macfb_nubus_info = {
+    .name          = "nubus-macfb",
+    .parent        = TYPE_NUBUS_DEVICE,
+    .instance_size = sizeof(MacfbNubusState),
+    .class_init    = macfb_nubus_class_init,
+};
+
 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..812c8ea92f
--- /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.o
diff --git a/hw/nubus/mac.c b/hw/nubus/mac.c
new file mode 100644
index 0000000000..ba366d3705
--- /dev/null
+++ b/hw/nubus/mac.c
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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.h"
+
+static void mac_nubus_slot_write(void *opaque, hwaddr addr, uint64_t val,
+                                       unsigned int size)
+{
+}
+
+
+static uint64_t mac_nubus_slot_read(void *opaque, hwaddr addr,
+                                    unsigned int size)
+{
+    return 0;
+}
+
+static const MemoryRegionOps mac_nubus_slot_ops = {
+    .read  = mac_nubus_slot_read,
+    .write = mac_nubus_slot_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void mac_nubus_super_slot_write(void *opaque, hwaddr addr, uint64_t val,
+                                       unsigned int size)
+{
+}
+
+static uint64_t mac_nubus_super_slot_read(void *opaque, hwaddr addr,
+                                          unsigned int size)
+{
+    return 0;
+}
+
+static const MemoryRegionOps mac_nubus_super_slot_ops = {
+    .read  = mac_nubus_super_slot_read,
+    .write = mac_nubus_super_slot_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int mac_nubus_initfn(SysBusDevice *dev)
+{
+    MacNubusState *s = DO_UPCAST(MacNubusState, sysbus_dev, dev);
+    MemoryRegion *super_slot_io = g_malloc(sizeof(MemoryRegion));;
+    MemoryRegion *slot_io = g_malloc(sizeof(MemoryRegion));
+
+    memory_region_init_io(super_slot_io, NULL, &mac_nubus_super_slot_ops,
+                          s, "nubus-super-slots",
+                          NUBUS_SUPER_SLOT_NB * NUBUS_SUPER_SLOT_SIZE);
+
+    memory_region_init_io(slot_io, NULL, &mac_nubus_slot_ops,
+                          s, "nubus-slots",
+                          NUBUS_SLOT_NB * NUBUS_SLOT_SIZE);
+
+    sysbus_init_mmio(dev, super_slot_io);
+    sysbus_init_mmio(dev, slot_io);
+
+    s->bus = nubus_bus_new(DEVICE(s), super_slot_io, slot_io);
+
+    return 0;
+}
+
+static void mac_nubus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mac_nubus_initfn;
+    dc->desc = "Nubus bridge";
+}
+
+static const TypeInfo mac_nubus_type_info = {
+    .name          = TYPE_MAC_NUBUS_BRIDGE,
+    .parent        = TYPE_NUBUS_BRIDGE,
+    .instance_size = sizeof(MacNubusState),
+    .class_init    = mac_nubus_class_init,
+};
+
+
+NubusBus *nubus_mac_new(hwaddr super_slot_base, hwaddr slot_base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, TYPE_MAC_NUBUS_BRIDGE);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, super_slot_base);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, slot_base);
+
+    return MAC_NUBUS_BRIDGE(dev)->bus;
+}
+
+static void mac_nubus_register_types(void)
+{
+    type_register_static(&mac_nubus_type_info);
+}
+
+type_init(mac_nubus_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 <laurent@vivier.eu>
+ *
+ * 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..fd1344e554
--- /dev/null
+++ b/hw/nubus/nubus-bus.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU Macintosh Nubus
+ *
+ * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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"
+
+static NubusBus *nubus;
+
+static void nubus_bus_initfn(Object *obj)
+{
+    NubusBus *bus = NUBUS_BUS(obj);;
+    bus->current_slot = NUBUS_FIRST_SLOT;
+}
+
+static void nubus_bus_class_init(ObjectClass *klass, void *data)
+{
+}
+
+static const TypeInfo nubus_bus_info = {
+    .name = TYPE_NUBUS_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(NubusBus),
+    .instance_init = nubus_bus_initfn,
+    .class_init = nubus_bus_class_init,
+};
+
+NubusBus *nubus_bus_new(DeviceState *dev, MemoryRegion *super_slot_io,
+                       MemoryRegion *slot_io)
+{
+    if (nubus) {
+        fprintf(stderr, "Can't create a second Nubus bus\n");
+        return NULL;
+    }
+
+    if (NULL == dev) {
+        dev = qdev_create(NULL, "nubus-bridge");
+        qdev_init_nofail(dev);
+    }
+
+    nubus = NUBUS_BUS(qbus_create(TYPE_NUBUS_BUS, dev, NULL));
+
+    nubus->super_slot_io = super_slot_io;
+    nubus->slot_io = slot_io;
+
+    return nubus;
+}
+
+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..0c8023d46a
--- /dev/null
+++ b/hw/nubus/nubus-device.c
@@ -0,0 +1,275 @@
+/*
+ * QEMU Macintosh Nubus
+ *
+ * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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"
+
+/* 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];
+    NubusBus *bus = nubus_bus_from_device(dev);
+
+    sprintf(fblock_name, "nubus-slot-%d-format-block", dev->slot_nb);
+
+    hwaddr fblock_offset = (dev->slot_nb + 1) * NUBUS_SLOT_SIZE - FBLOCK_SIZE;
+    memory_region_init_io(&dev->fblock_io, NULL, &nubus_format_block_ops,
+                          dev, fblock_name, FBLOCK_SIZE);
+    memory_region_add_subregion(bus->slot_io, fblock_offset,
+                                &dev->fblock_io);
+}
+
+NubusDevice *nubus_create(NubusBus *bus, const char *name)
+{
+    DeviceState *dev;
+    NubusDevice *d;
+
+    if (!bus) {
+        hw_error("Tried to create nubus device %s with no nubus bus present.",
+                 name);
+    }
+
+    if (bus->current_slot < NUBUS_FIRST_SLOT ||
+        bus->current_slot > NUBUS_LAST_SLOT) {
+        fprintf(stderr, "Cannot register nubus card '%s', not enough slot\n",
+                name);
+        return NULL;
+    }
+
+    dev = qdev_create(&bus->qbus, name);
+
+    d = NUBUS_DEVICE(dev);
+    d->slot_nb = bus->current_slot++;
+    nubus_register_format_block(d);
+
+    return d;
+}
+
+NubusDevice *nubus_try_create(NubusBus *bus, const char *name)
+{
+    DeviceState *dev;
+    NubusDevice *d;
+
+    if (!bus) {
+        hw_error("Tried to create nubus device %s with no nubus bus present.",
+                 name);
+    }
+
+    if (bus->current_slot < NUBUS_FIRST_SLOT ||
+        bus->current_slot > NUBUS_LAST_SLOT) {
+        fprintf(stderr, "Cannot register nubus card '%s', not enough slot\n",
+                name);
+        return NULL;
+    }
+
+    dev = qdev_try_create(&bus->qbus, name);
+    if (!dev) {
+        return NULL;
+    }
+
+    d = NUBUS_DEVICE(dev);
+    d->slot_nb = bus->current_slot++;
+    nubus_register_format_block(d);
+
+    return d;
+}
+
+NubusDevice *nubus_create_simple(NubusBus *bus, const char *name)
+{
+    NubusDevice *dev;
+
+    dev = nubus_create(bus, name);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+void nubus_add_slot_mmio(NubusDevice *dev,
+                         hwaddr offset,
+                         MemoryRegion *subregion)
+{
+    NubusBus *bus = nubus_bus_from_device(dev);
+    hwaddr slot_offset = dev->slot_nb * NUBUS_SLOT_SIZE + offset;
+    memory_region_add_subregion(bus->slot_io, slot_offset, subregion);
+}
+
+void nubus_add_super_slot_mmio(NubusDevice *dev,
+                               hwaddr offset,
+                               MemoryRegion *subregion)
+{
+    NubusBus *bus = nubus_bus_from_device(dev);
+    hwaddr slot_offset = (dev->slot_nb - 6) * NUBUS_SUPER_SLOT_SIZE + offset;
+    memory_region_add_subregion(bus->super_slot_io, slot_offset, subregion);
+}
+
+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)
+{
+    NubusBus *bus = nubus_bus_from_device(dev);
+    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 = (dev->slot_nb + 1) * NUBUS_SLOT_SIZE - FBLOCK_SIZE +
+                 dev->directory_offset;
+    memory_region_add_subregion(bus->slot_io, rom_offset, &dev->rom_io);
+
+}
+
+
+static void nubus_device_init(Object *obj)
+{
+}
+
+static int nubus_qdev_init(DeviceState *qdev)
+{
+    NubusDevice *dev = NUBUS_DEVICE(qdev);
+    NubusDeviceClass *klass = NUBUS_DEVICE_GET_CLASS(dev);
+
+    if (klass->init) {
+        return klass->init(dev);
+    }
+
+    return 0;
+}
+
+static void nubus_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = nubus_qdev_init;
+    k->bus_type = TYPE_NUBUS_BUS;
+}
+
+static const TypeInfo nubus_device_type_info = {
+    .name = TYPE_NUBUS_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(NubusDevice),
+    .instance_init = nubus_device_init,
+    .abstract = true,
+    .class_size = sizeof(NubusDeviceClass),
+    .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/nubus/mac.h b/include/hw/nubus/mac.h
new file mode 100644
index 0000000000..502d35ba9d
--- /dev/null
+++ b/include/hw/nubus/mac.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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;
+
+NubusBus *nubus_mac_new(hwaddr super_slot_base, hwaddr slot_base);
+#endif
diff --git a/include/hw/nubus/nubus.h b/include/hw/nubus/nubus.h
new file mode 100644
index 0000000000..c0cbbfea33
--- /dev/null
+++ b/include/hw/nubus/nubus.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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 NUBUS_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(NubusDeviceClass, (klass), TYPE_NUBUS_DEVICE)
+#define NUBUS_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(NubusDeviceClass, (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 NubusDeviceClass {
+    DeviceClass parent_class;
+    int (*init)(NubusDevice *dev);
+} NubusDeviceClass;
+
+struct NubusBus {
+    BusState qbus;
+    int current_slot;
+    MemoryRegion *super_slot_io;
+    MemoryRegion *slot_io;
+    qemu_irq *irqs;
+};
+
+struct NubusDevice {
+    DeviceState qdev;
+
+    int slot_nb;
+
+    /* 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;
+};
+
+NubusBus *nubus_bus_new(DeviceState *dev, MemoryRegion *super_slot_io,
+                       MemoryRegion *slot_io);
+NubusDevice *nubus_try_create(NubusBus *bus, const char *name);
+NubusDevice *nubus_create_simple(NubusBus *bus, const char *name);
+NubusDevice *nubus_create(NubusBus *bus, const char *name);
+void nubus_add_slot_mmio(NubusDevice *dev, hwaddr offset,
+                         MemoryRegion *subregion);
+void nubus_add_super_slot_mmio(NubusDevice *dev, hwaddr offset,
+                               MemoryRegion *subregion);
+void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size,
+                        int revision, int format, uint8_t byte_lanes);
+
+static inline NubusBus *nubus_bus_from_device(NubusDevice *d)
+{
+    return NUBUS_BUS(qdev_get_parent_bus(DEVICE(d)));
+}
+#endif
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 325c72de33..91a50fe954 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -43,6 +43,8 @@ typedef struct I2SCodec I2SCodec;
 typedef struct ISABus ISABus;
 typedef struct ISADevice ISADevice;
 typedef struct IsaDma IsaDma;
+typedef struct NubusBus NubusBus;
+typedef struct NubusDevice NubusDevice;
 typedef struct MACAddr MACAddr;
 typedef struct MachineClass MachineClass;
 typedef struct MachineState MachineState;
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 08/13] hw/m68k: add a dummy SWIM floppy controller
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (6 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 07/13] hw/m68k: add Nubus support Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-08 20:05 ` [Qemu-devel] [RFC 09/13] hw/m68k: define Macintosh Quadra 800 Laurent Vivier
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/block/Makefile.objs |   1 +
 hw/block/swim.c        | 325 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 326 insertions(+)
 create mode 100644 hw/block/swim.c

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..33424ca76f
--- /dev/null
+++ b/hw/block/swim.c
@@ -0,0 +1,325 @@
+/*
+ * QEMU Macintosh floppy disk controller emulator (SWIM)
+ *
+ * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu>
+ *
+ * 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"
+
+/* 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 MAX_FD                  2
+
+typedef struct SWIMCtrl SWIMCtrl;
+
+typedef struct FDrive {
+    SWIMCtrl *swimctrl;
+    BlockBackend *blk;
+} FDrive;
+
+#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
+
+struct SWIMCtrl {
+    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;
+};
+
+#define TYPE_SYSBUS_SWIM "sysbus-swim"
+#define SYSBUS_SWIM(obj) OBJECT_CHECK(SWIMCtrlSysBus, (obj), TYPE_SYSBUS_SWIM)
+
+typedef struct SWIMCtrlSysBus {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    struct SWIMCtrl state;
+} SWIMCtrlSysBus;
+
+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 sysbus_swim_initfn(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    SWIMCtrlSysBus *sys = SYSBUS_SWIM(obj);
+    SWIMCtrl *swimctrl = &sys->state;
+
+    memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl,
+                          "swim", 0x2000);
+    sysbus_init_mmio(sbd, &swimctrl->iomem);
+}
+
+static Property sysbus_swim_properties[] = {
+    DEFINE_PROP_DRIVE("driveA", SWIMCtrlSysBus, state.drives[0].blk),
+    DEFINE_PROP_DRIVE("driveB", SWIMCtrlSysBus, state.drives[1].blk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sysbus_swim_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = sysbus_swim_properties;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+}
+
+static const TypeInfo sysbus_swim_info = {
+    .name          = TYPE_SYSBUS_SWIM,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+     .instance_size = sizeof(SWIMCtrlSysBus),
+    .instance_init = sysbus_swim_initfn,
+    .class_init    = sysbus_swim_class_init,
+};
+
+static void swim_register_types(void)
+{
+    type_register_static(&sysbus_swim_info);
+}
+
+type_init(swim_register_types)
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 09/13] hw/m68k: define Macintosh Quadra 800
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (7 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 08/13] hw/m68k: add a dummy SWIM floppy controller Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09 10:24   ` Mark Cave-Ayland
  2018-06-08 20:05 ` [Qemu-devel] [RFC 10/13] dp8393x: fix dp8393x_receive Laurent Vivier
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier, Laurent Vivier

From: Laurent Vivier <Laurent@Vivier.EU>

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 default-configs/m68k-softmmu.mak |  12 ++
 hw/display/macfb.c               |  31 ++--
 hw/m68k/Makefile.objs            |   6 +-
 hw/m68k/bootinfo.h               |  99 ++++++++++
 hw/m68k/mac.c                    | 384 +++++++++++++++++++++++++++++++++++++++
 hw/nubus/nubus-device.c          |  13 --
 tests/qom-test.c                 |   5 +
 tests/test-hmp.c                 |   3 +-
 8 files changed, 519 insertions(+), 34 deletions(-)
 create mode 100644 hw/m68k/bootinfo.h
 create mode 100644 hw/m68k/mac.c

diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 60f7cdfbf2..1b568be166 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -2,3 +2,15 @@
 
 CONFIG_COLDFIRE=y
 CONFIG_PTIMER=y
+CONFIG_ESCC=y
+CONFIG_FRAMEBUFFER=y
+CONFIG_ADB=y
+CONFIG_MAC_VIA=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/display/macfb.c b/hw/display/macfb.c
index 295fd0fc8a..a3204ab150 100644
--- a/hw/display/macfb.c
+++ b/hw/display/macfb.c
@@ -240,31 +240,28 @@ typedef struct {
     MacfbState macfb;
 } MacfbNubusState;
 
-static int macfb_sysbus_init(SysBusDevice *dev)
+static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
 {
     MacfbState *s =  &MACFB(dev)->macfb;
 
-    macfb_init(DEVICE(dev), s);
-    sysbus_init_mmio(dev, &s->mem_ctrl);
-    sysbus_init_mmio(dev, &s->mem_vram);
-
-    return 0;
+    macfb_init(dev, s);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mem_ctrl);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mem_vram);
 }
 
 const uint8_t macfb_rom[] = {
     255, 0, 0, 0,
 };
 
-static int macfb_nubus_init(NubusDevice *dev)
+static void macfb_nubus_realize(DeviceState *dev, Error **errp)
 {
-    MacfbState *s = &DO_UPCAST(MacfbNubusState, busdev, dev)->macfb;
+    NubusDevice *nubus = NUBUS_DEVICE(dev);
+    MacfbState *s = &DO_UPCAST(MacfbNubusState, busdev, nubus)->macfb;
 
-    macfb_init(DEVICE(dev), s);
-    nubus_add_slot_mmio(dev, DAFB_BASE, &s->mem_ctrl);
-    nubus_add_slot_mmio(dev, VIDEO_BASE, &s->mem_vram);
-    nubus_register_rom(dev, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
-
-    return 0;
+    macfb_init(dev, s);
+    nubus_add_slot_mmio(nubus, DAFB_BASE, &s->mem_ctrl);
+    nubus_add_slot_mmio(nubus, VIDEO_BASE, &s->mem_vram);
+    nubus_register_rom(nubus, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
 }
 
 static void macfb_sysbus_reset(DeviceState *d)
@@ -296,9 +293,8 @@ static Property macfb_nubus_properties[] = {
 static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = macfb_sysbus_init;
+    dc->realize = macfb_sysbus_realize;
     dc->desc = "SysBus Macintosh framebuffer";
     dc->reset = macfb_sysbus_reset;
     dc->vmsd = &vmstate_macfb;
@@ -308,9 +304,8 @@ static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
 static void macfb_nubus_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    NubusDeviceClass *k = NUBUS_DEVICE_CLASS(klass);
 
-    k->init = macfb_nubus_init;
+    dc->realize = macfb_nubus_realize;
     dc->desc = "Nubus Macintosh framebuffer";
     dc->reset = macfb_nubus_reset;
     dc->vmsd = &vmstate_macfb;
diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs
index d1f089c08a..ff739617b2 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) += mac.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..b04153ce1e
--- /dev/null
+++ b/hw/m68k/bootinfo.h
@@ -0,0 +1,99 @@
+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/mac.c b/hw/m68k/mac.c
new file mode 100644
index 0000000000..d573339e66
--- /dev/null
+++ b/hw/m68k/mac.c
@@ -0,0 +1,384 @@
+/*
+ * 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.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
+
+typedef struct {
+    M68kCPU *cpu;
+    uint8_t ipr;
+} q800_glue_state_t;
+
+static void q800_glue_set_irq(void *opaque, int irq, int level)
+{
+    int i;
+
+    q800_glue_state_t *s = opaque;
+
+    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 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;
+    q800_glue_state_t *s;
+    qemu_irq *pic;
+    hwaddr parameters_base;
+    CPUState *cs;
+    DeviceState *dev;
+    DeviceState *via_dev;
+    SysBusDevice *sysbus;
+    BusState *adb_bus;
+    qemu_irq  esp_reset_irq, esp_dma_enable;
+    NubusBus *nubus;
+    NubusDevice *nubus_dev;
+    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);
+
+    /* Glue */
+
+    s = (q800_glue_state_t *)g_malloc0(sizeof(q800_glue_state_t));
+    s->cpu = cpu;
+    pic = qemu_allocate_irqs(q800_glue_set_irq, s, 6);
+
+    /* 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);
+    sysbus_connect_irq(sysbus, 0, pic[0]);
+    sysbus_connect_irq(sysbus, 1, pic[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, pic[2]);
+
+    /* SCC */
+
+    dev = qdev_create(NULL, "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, pic[3]);
+    sysbus_connect_irq(sysbus, 1, pic[3]);
+    sysbus_mmio_map(sysbus, 0, SCC_BASE);
+
+    /* SCSI */
+
+    esp_init_pdma(ESP_BASE, 4, ESP_PDMA,
+                  qdev_get_gpio_in(via_dev, VIA2_IRQ_SCSI_BIT),
+                  qdev_get_gpio_in(via_dev, VIA2_IRQ_SCSI_DATA_BIT),
+                  &esp_reset_irq, &esp_dma_enable);
+
+    /* Apple Sound Chip */
+
+    dev = qdev_create(NULL, "apple-sound-chip");
+    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(via_dev, 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, "sysbus-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 */
+
+    nubus = nubus_mac_new(NUBUS_SUPER_SLOT_BASE, NUBUS_SLOT_BASE);
+
+    /* framebuffer in nubus slot #9 */
+
+    nubus_dev = nubus_create(nubus, "nubus-macfb");
+    qdev_prop_set_uint32(&nubus_dev->qdev, "width", graphic_width);
+    qdev_prop_set_uint32(&nubus_dev->qdev, "height", graphic_height);
+    qdev_prop_set_uint8(&nubus_dev->qdev, "depth", graphic_depth);
+    qdev_init_nofail(&nubus_dev->qdev);
+
+    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/hw/nubus/nubus-device.c b/hw/nubus/nubus-device.c
index 0c8023d46a..7fd1e03909 100644
--- a/hw/nubus/nubus-device.c
+++ b/hw/nubus/nubus-device.c
@@ -238,22 +238,9 @@ static void nubus_device_init(Object *obj)
 {
 }
 
-static int nubus_qdev_init(DeviceState *qdev)
-{
-    NubusDevice *dev = NUBUS_DEVICE(qdev);
-    NubusDeviceClass *klass = NUBUS_DEVICE_GET_CLASS(dev);
-
-    if (klass->init) {
-        return klass->init(dev);
-    }
-
-    return 0;
-}
-
 static void nubus_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
-    k->init = nubus_qdev_init;
     k->bus_type = TYPE_NUBUS_BUS;
 }
 
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;
     }
 
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 10/13] dp8393x: fix dp8393x_receive
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (8 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 09/13] hw/m68k: define Macintosh Quadra 800 Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09  8:47   ` Hervé Poussineau
  2018-06-08 20:05 ` [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus Laurent Vivier
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

address_space_rw() access size must be multiplied by width.
dp8393x_receive() must return the number of bytes read, not the length
of the last memory access.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/net/dp8393x.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index f2d2ce344c..ef5f1eb94f 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -808,9 +808,11 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
         /* EOL detected */
         s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
     } else {
+        size = sizeof(uint16_t) * width;
         data[0 * width] = 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);
+        address_space_rw(&s->as,
+            dp8393x_crda(s) + sizeof(uint16_t) * 6 * width,
+            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
         s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
         s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
         s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
@@ -824,7 +826,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
     /* Done */
     dp8393x_update_irq(s);
 
-    return size;
+    return rx_len;
 }
 
 static void dp8393x_reset(DeviceState *dev)
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (9 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 10/13] dp8393x: fix dp8393x_receive Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09  8:55   ` Hervé Poussineau
  2018-06-09 18:25   ` Thomas Huth
  2018-06-08 20:05 ` [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack Laurent Vivier
                   ` (4 subsequent siblings)
  15 siblings, 2 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

This is needed by Quadra 800, this card can run on little-endian
or big-endian bus.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/net/dp8393x.c | 101 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 70 insertions(+), 31 deletions(-)

diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index ef5f1eb94f..5061474e6b 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;
@@ -174,6 +175,12 @@ typedef struct dp8393xState {
     AddressSpace as;
 } dp8393xState;
 
+#ifdef HOST_WORDS_BIGENDIAN
+static const bool host_big_endian = true;
+#else
+static const bool host_big_endian = false;
+#endif
+
 /* Accessor functions for values which are formed by
  * concatenating two 16 bit device registers. By putting these
  * in their own functions with a uint32_t return type we avoid the
@@ -220,6 +227,36 @@ 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 = base[offset * width + width - 1];
+    } else {
+        val = base[offset * width];
+    }
+    if (s->big_endian != host_big_endian) {
+        val = bswap16(val);
+    }
+    return val;
+}
+
+static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset,
+                        uint16_t val)
+{
+    if (s->big_endian != host_big_endian) {
+        val = bswap16(val);
+    }
+
+    if (s->big_endian) {
+        base[offset * width + width - 1] = val;
+    } else {
+        base[offset * width] = val;
+    }
+}
+
 static void dp8393x_update_irq(dp8393xState *s)
 {
     int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
@@ -251,12 +288,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 +306,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 +327,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 +445,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 +476,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 +505,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 +520,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 +784,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 +828,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,13 +841,13 @@ 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 {
         size = sizeof(uint16_t) * width;
-        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, size, 1);
@@ -923,6 +961,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(),
 };
 
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (10 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09  8:55   ` Hervé Poussineau
  2018-06-09 18:36   ` Thomas Huth
  2018-06-08 20:05 ` [Qemu-devel] [RFC 13/13] dp8393x: fix receiving buffer exhaustion Laurent Vivier
                   ` (3 subsequent siblings)
  15 siblings, 2 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

It's only 32 bytes, and this simplifies the dp8393x_get()/
dp8393x_put() interface.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/net/dp8393x.c | 107 ++++++++++++++++++++++++++-----------------------------
 1 file changed, 51 insertions(+), 56 deletions(-)

diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 5061474e6b..40e5f8257b 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -168,6 +168,7 @@ typedef struct dp8393xState {
 
     /* Temporaries */
     uint8_t tx_buffer[0x10000];
+    uint16_t data[16];
     int loopback_packet;
 
     /* Memory access */
@@ -227,15 +228,14 @@ 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)
+static uint16_t dp8393x_get(dp8393xState *s, int width, int offset)
 {
     uint16_t val;
 
     if (s->big_endian) {
-        val = base[offset * width + width - 1];
+        val = s->data[offset * width + width - 1];
     } else {
-        val = base[offset * width];
+        val = s->data[offset * width];
     }
     if (s->big_endian != host_big_endian) {
         val = bswap16(val);
@@ -243,7 +243,7 @@ static uint16_t dp8393x_get(dp8393xState *s, int width, uint16_t *base,
     return val;
 }
 
-static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset,
+static void dp8393x_put(dp8393xState *s, int width, int offset,
                         uint16_t val)
 {
     if (s->big_endian != host_big_endian) {
@@ -251,9 +251,9 @@ static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset,
     }
 
     if (s->big_endian) {
-        base[offset * width + width - 1] = val;
+        s->data[offset * width + width - 1] = val;
     } else {
-        base[offset * width] = val;
+        s->data[offset * width] = val;
     }
 }
 
@@ -277,7 +277,6 @@ static void dp8393x_update_irq(dp8393xState *s)
 
 static void dp8393x_do_load_cam(dp8393xState *s)
 {
-    uint16_t data[8];
     int width, size;
     uint16_t index = 0;
 
@@ -287,13 +286,13 @@ static void dp8393x_do_load_cam(dp8393xState *s)
     while (s->regs[SONIC_CDC] & 0x1f) {
         /* Fill current entry */
         address_space_rw(&s->as, dp8393x_cdp(s),
-            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
-        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;
+            MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+        s->cam[index][0] = dp8393x_get(s, width, 1) & 0xff;
+        s->cam[index][1] = dp8393x_get(s, width, 1) >> 8;
+        s->cam[index][2] = dp8393x_get(s, width, 2) & 0xff;
+        s->cam[index][3] = dp8393x_get(s, width, 2) >> 8;
+        s->cam[index][4] = dp8393x_get(s, width, 3) & 0xff;
+        s->cam[index][5] = dp8393x_get(s, width, 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]);
@@ -305,8 +304,8 @@ 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] = dp8393x_get(s, width, data, 0);
+        MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+    s->regs[SONIC_CE] = dp8393x_get(s, width, 0);
     DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
 
     /* Done */
@@ -317,20 +316,19 @@ static void dp8393x_do_load_cam(dp8393xState *s)
 
 static void dp8393x_do_read_rra(dp8393xState *s)
 {
-    uint16_t data[8];
     int width, size;
 
     /* Read memory */
     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
     size = sizeof(uint16_t) * 4 * width;
     address_space_rw(&s->as, dp8393x_rrp(s),
-        MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
+        MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
 
     /* Update SONIC registers */
-    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);
+    s->regs[SONIC_CRBA0] = dp8393x_get(s, width, 0);
+    s->regs[SONIC_CRBA1] = dp8393x_get(s, width, 1);
+    s->regs[SONIC_RBWC0] = dp8393x_get(s, width, 2);
+    s->regs[SONIC_RBWC1] = dp8393x_get(s, width, 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]);
@@ -427,7 +425,6 @@ static void dp8393x_do_receiver_disable(dp8393xState *s)
 static void dp8393x_do_transmit_packets(dp8393xState *s)
 {
     NetClientState *nc = qemu_get_queue(s->nic);
-    uint16_t data[12];
     int width, size;
     int tx_len, len;
     uint16_t i;
@@ -436,21 +433,20 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
 
     while (1) {
         /* Read memory */
-        size = sizeof(uint16_t) * 6 * width;
+        size = sizeof(uint16_t) * 7 * width;
         s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
         DPRINTF("Transmit packet at %08x\n", dp8393x_ttda(s));
-        address_space_rw(&s->as,
-            dp8393x_ttda(s) + sizeof(uint16_t) * width,
-            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
+        address_space_rw(&s->as, dp8393x_ttda(s),
+            MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
         tx_len = 0;
 
         /* Update registers */
-        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);
+        s->regs[SONIC_TCR] = dp8393x_get(s, width, 1) & 0xf000;
+        s->regs[SONIC_TPS] = dp8393x_get(s, width, 2);
+        s->regs[SONIC_TFC] = dp8393x_get(s, width, 3);
+        s->regs[SONIC_TSA0] = dp8393x_get(s, width, 4);
+        s->regs[SONIC_TSA1] = dp8393x_get(s, width, 5);
+        s->regs[SONIC_TFS] = dp8393x_get(s, width, 6);
 
         /* Handle programmable interrupt */
         if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
@@ -475,10 +471,10 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
                 size = sizeof(uint16_t) * 3 * width;
                 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] = 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);
+                    MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+                s->regs[SONIC_TSA0] = dp8393x_get(s, width, 0);
+                s->regs[SONIC_TSA1] = dp8393x_get(s, width, 1);
+                s->regs[SONIC_TFS] = dp8393x_get(s, width, 2);
             }
         }
 
@@ -505,12 +501,12 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
         s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
 
         /* Write status */
-        dp8393x_put(s, width, data, 0,
+        dp8393x_put(s, width, 0,
                     s->regs[SONIC_TCR] & 0x0fff); /* status */
         size = sizeof(uint16_t) * width;
         address_space_rw(&s->as,
             dp8393x_ttda(s),
-            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
+            MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 1);
 
         if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
             /* Read footer of packet */
@@ -519,9 +515,9 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
                 dp8393x_ttda(s) +
                              sizeof(uint16_t) *
                              (4 + 3 * s->regs[SONIC_TFC]) * width,
-                MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
-            s->regs[SONIC_CTDA] = dp8393x_get(s, width, data, 0) & ~0x1;
-            if (dp8393x_get(s, width, data, 0) & 0x1) {
+                MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+            s->regs[SONIC_CTDA] = dp8393x_get(s, width, 0) & ~0x1;
+            if (dp8393x_get(s, width, 0) & 0x1) {
                 /* EOL detected */
                 break;
             }
@@ -758,7 +754,6 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
                                size_t size)
 {
     dp8393xState *s = qemu_get_nic_opaque(nc);
-    uint16_t data[10];
     int packet_type;
     uint32_t available, address;
     int width, rx_len = size;
@@ -783,8 +778,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
         size = sizeof(uint16_t) * 1 * width;
         address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width;
         address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
-                         (uint8_t *)data, size, 0);
-        if (dp8393x_get(s, width, data, 0) & 0x1) {
+                         (uint8_t *)s->data, size, 0);
+        if (dp8393x_get(s, width, 0) & 0x1) {
             /* Still EOL ; stop reception */
             return -1;
         } else {
@@ -828,29 +823,29 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
 
     /* Write status to memory */
     DPRINTF("Write status at %08x\n", dp8393x_crda(s));
-    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 */
+    dp8393x_put(s, width, 0, s->regs[SONIC_RCR]); /* status */
+    dp8393x_put(s, width, 1, rx_len); /* byte count */
+    dp8393x_put(s, width, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */
+    dp8393x_put(s, width, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */
+    dp8393x_put(s, width, 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);
+        MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 1);
 
     /* Move to next descriptor */
     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] = dp8393x_get(s, width, data, 0);
+        MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+    s->regs[SONIC_LLFA] = dp8393x_get(s, width, 0);
     if (s->regs[SONIC_LLFA] & 0x1) {
         /* EOL detected */
         s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
     } else {
         size = sizeof(uint16_t) * width;
-        dp8393x_put(s, width, data, 0, 0); /* in_use */
+        dp8393x_put(s, width, 0, 0); /* in_use */
         address_space_rw(&s->as,
             dp8393x_crda(s) + sizeof(uint16_t) * 6 * width,
-            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
+            MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 1);
         s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
         s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
         s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC 13/13] dp8393x: fix receiving buffer exhaustion
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (11 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack Laurent Vivier
@ 2018-06-08 20:05 ` Laurent Vivier
  2018-06-09  8:55   ` Hervé Poussineau
  2018-06-08 20:34 ` [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine no-reply
                   ` (2 subsequent siblings)
  15 siblings, 1 reply; 33+ messages in thread
From: Laurent Vivier @ 2018-06-08 20:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf,
	Hervé Poussineau, Laurent Vivier

The card is not able to exit from exhaustion state, because
while the drive consumes the buffers, the RRP is incremented
(when the driver clears the ISR RBE bit), so it stays equal
to RWP, and while RRP == RWP, the card thinks it is always
in exhaustion state. So the driver consumes all the buffers,
but the card cannot receive new ones.

This patch fixes the problem by not incrementing RRP when
the driver clears the ISR RBE bit.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/net/dp8393x.c | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 40e5f8257b..fd0f6cf2a0 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -314,7 +314,7 @@ static void dp8393x_do_load_cam(dp8393xState *s)
     dp8393x_update_irq(s);
 }
 
-static void dp8393x_do_read_rra(dp8393xState *s)
+static void dp8393x_do_read_rra(dp8393xState *s, int next)
 {
     int width, size;
 
@@ -333,19 +333,20 @@ static void dp8393x_do_read_rra(dp8393xState *s)
         s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
         s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
 
-    /* Go to next entry */
-    s->regs[SONIC_RRP] += size;
+    if (next) {
+        /* Go to next entry */
+        s->regs[SONIC_RRP] += size;
 
-    /* Handle wrap */
-    if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
-        s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
-    }
+        /* Handle wrap */
+        if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
+            s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
+        }
 
-    /* Check resource exhaustion */
-    if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
-    {
-        s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
-        dp8393x_update_irq(s);
+        /* Check resource exhaustion */
+        if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP]) {
+            s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
+            dp8393x_update_irq(s);
+        }
     }
 
     /* Done */
@@ -559,7 +560,7 @@ static void dp8393x_do_command(dp8393xState *s, uint16_t command)
     if (command & SONIC_CR_RST)
         dp8393x_do_software_reset(s);
     if (command & SONIC_CR_RRRA)
-        dp8393x_do_read_rra(s);
+        dp8393x_do_read_rra(s, 1);
     if (command & SONIC_CR_LCAM)
         dp8393x_do_load_cam(s);
 }
@@ -650,7 +651,7 @@ static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
             data &= s->regs[reg];
             s->regs[reg] &= ~data;
             if (data & SONIC_ISR_RBE) {
-                dp8393x_do_read_rra(s);
+                dp8393x_do_read_rra(s, 0);
             }
             dp8393x_update_irq(s);
             if (dp8393x_can_receive(s->nic->ncs)) {
@@ -852,7 +853,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
 
         if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
             /* Read next RRA */
-            dp8393x_do_read_rra(s);
+            dp8393x_do_read_rra(s, 1);
         }
     }
 
-- 
2.14.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (12 preceding siblings ...)
  2018-06-08 20:05 ` [Qemu-devel] [RFC 13/13] dp8393x: fix receiving buffer exhaustion Laurent Vivier
@ 2018-06-08 20:34 ` no-reply
  2018-06-09  3:26 ` Philippe Mathieu-Daudé
  2018-06-09 14:25 ` Philippe Mathieu-Daudé
  15 siblings, 0 replies; 33+ messages in thread
From: no-reply @ 2018-06-08 20:34 UTC (permalink / raw)
  To: laurent; +Cc: famz, qemu-devel, kwolf

Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20180608200558.386-1-laurent@vivier.eu
Subject: [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
30b6069da2 dp8393x: fix receiving buffer exhaustion
a9294684d2 dp8393x: put DMA temp buffer in the state, not in the stack
8f1c639ffd dp8393x: manage big endian bus
7b43df7a43 dp8393x: fix dp8393x_receive
c87eb03bf7 hw/m68k: define Macintosh Quadra 800
742c9c5459 hw/m68k: add a dummy SWIM floppy controller
2d712f9df2 hw/m68k: add Nubus support
6fc4d6d265 ESP: add pseudo-DMA as used by Macintosh
105bc32850 hw/m68k: Apple Sound Chip (ASC) emulation
030037ad0b hw/m68k: add video card
8a99fff7de escc: introduce a selector for the register bit
20944305a6 ADB: VIA probes ADB bus when it is idle
60cce9bbe9 hw/m68k: add via support

=== OUTPUT BEGIN ===
Checking PATCH 1/13: hw/m68k: add via support...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#145: 
new file mode 100644

ERROR: space prohibited after that '&&' (ctx:WxW)
#622: FILE: hw/misc/mac_via.c:473:
+        if (!(s->last_b & VIA1B_vRTCClk) && (s->b & VIA1B_vRTCClk)) {
                                          ^

total: 1 errors, 1 warnings, 1126 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 2/13: ADB: VIA probes ADB bus when it is idle...
Checking PATCH 3/13: escc: introduce a selector for the register bit...
Checking PATCH 4/13: hw/m68k: add video card...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#37: 
new file mode 100644

total: 0 errors, 1 warnings, 475 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 5/13: hw/m68k: Apple Sound Chip (ASC) emulation...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#21: 
new file mode 100644

total: 0 errors, 1 warnings, 517 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 6/13: ESP: add pseudo-DMA as used by Macintosh...
Checking PATCH 7/13: hw/m68k: add Nubus support...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#158: 
new file mode 100644

total: 0 errors, 1 warnings, 739 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 8/13: hw/m68k: add a dummy SWIM floppy controller...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#22: 
new file mode 100644

total: 0 errors, 1 warnings, 332 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 9/13: hw/m68k: define Macintosh Quadra 800...
Argument "m" isn't numeric in numeric eq (==) at ./scripts/checkpatch.pl line 2665.
Argument "m" isn't numeric in numeric eq (==) at ./scripts/checkpatch.pl line 2665.
Use of uninitialized value $1 in concatenation (.) or string at ./scripts/checkpatch.pl line 2666.
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#110: 
new file mode 100644

WARNING: line over 80 characters
#206: FILE: hw/m68k/bootinfo.h:92:
+        stw_phys(as, base, (sizeof(struct bi_record) + strlen(string) + 2) & ~1); \

ERROR: unnecessary cast may hide bugs, use g_new0 instead
#387: FILE: hw/m68k/mac.c:168:
+    s = (q800_glue_state_t *)g_malloc0(sizeof(q800_glue_state_t));

total: 1 errors, 2 warnings, 614 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 10/13: dp8393x: fix dp8393x_receive...
Checking PATCH 11/13: dp8393x: manage big endian bus...
ERROR: do not initialise statics to 0 or NULL
#31: FILE: hw/net/dp8393x.c:181:
+static const bool host_big_endian = false;

total: 1 errors, 0 warnings, 190 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 12/13: dp8393x: put DMA temp buffer in the state, not in the stack...
Checking PATCH 13/13: dp8393x: fix receiving buffer exhaustion...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (13 preceding siblings ...)
  2018-06-08 20:34 ` [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine no-reply
@ 2018-06-09  3:26 ` Philippe Mathieu-Daudé
  2018-06-09  8:34   ` Laurent Vivier
  2018-06-09 14:25 ` Philippe Mathieu-Daudé
  15 siblings, 1 reply; 33+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-06-09  3:26 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, open list:Block layer core
  Cc: Kevin Wolf, Fam Zheng, Jason Wang, Dr. David Alan Gilbert,
	Max Reitz, Hervé Poussineau, Gerd Hoffmann, Paolo Bonzini,
	Yongbok Kim, Andreas Färber, Aurelien Jarno

On 06/08/2018 05:05 PM, Laurent Vivier wrote:
> I'm rebasing some of these patches for seven years now,
> too many years...
> 
> It's an RFC because things have changed in QEMU in seven years,
> for instance the VIA has a new implementation (mos6522) introduced
> by Mark Cave-Ayland and I didn't rework my implementation to
> fit into this new one (any volunteers?), display has some glitches,
> ADB devices are not identified correctly.
> 
> if you want to test the machine, I'm sorry, it doesn't boot
> a MacROM, but you can boot a linux kernel from the command line.
> 
> You can install your own disk using debian-installer, with:
> 
>     ...
>     -M q800 \
>     -serial none -serial mon:stdio \
>     -m 1000M -drive file=m68k.qcow2,format=qcow2 \
>     -net nic,model=dp83932,addr=09:00:07:12:34:57 \
>     -append "console=ttyS0 vga=off" \
>     -kernel vmlinux-4.15.0-2-m68k \
>     -initrd initrd.gz \
>     -drive file=debian-9.0-m68k-NETINST-1.iso \
>     -drive file=m68k.qcow2,format=qcow2 \
>     -nographic

qemu-system-m68k: -drive file=m68k.qcow2,format=qcow2: Failed to get
"write" lock
Is another process using the image?

(two times same file provided in cmdline arguments)

@block-team I found it funny because this is the very same process which
already locked. The error message is enough as it imo.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine
  2018-06-09  3:26 ` Philippe Mathieu-Daudé
@ 2018-06-09  8:34   ` Laurent Vivier
  0 siblings, 0 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-09  8:34 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, open list:Block layer core
  Cc: Kevin Wolf, Fam Zheng, Jason Wang, Dr. David Alan Gilbert,
	Max Reitz, Hervé Poussineau, Gerd Hoffmann, Paolo Bonzini,
	Yongbok Kim, Andreas Färber, Aurelien Jarno

Le 09/06/2018 à 05:26, Philippe Mathieu-Daudé a écrit :
> On 06/08/2018 05:05 PM, Laurent Vivier wrote:
>> I'm rebasing some of these patches for seven years now,
>> too many years...
>>
>> It's an RFC because things have changed in QEMU in seven years,
>> for instance the VIA has a new implementation (mos6522) introduced
>> by Mark Cave-Ayland and I didn't rework my implementation to
>> fit into this new one (any volunteers?), display has some glitches,
>> ADB devices are not identified correctly.
>>
>> if you want to test the machine, I'm sorry, it doesn't boot
>> a MacROM, but you can boot a linux kernel from the command line.
>>
>> You can install your own disk using debian-installer, with:
>>
>>     ...
>>     -M q800 \
>>     -serial none -serial mon:stdio \
>>     -m 1000M -drive file=m68k.qcow2,format=qcow2 \
>>     -net nic,model=dp83932,addr=09:00:07:12:34:57 \
>>     -append "console=ttyS0 vga=off" \
>>     -kernel vmlinux-4.15.0-2-m68k \
>>     -initrd initrd.gz \
>>     -drive file=debian-9.0-m68k-NETINST-1.iso \
>>     -drive file=m68k.qcow2,format=qcow2 \
>>     -nographic
> 
> qemu-system-m68k: -drive file=m68k.qcow2,format=qcow2: Failed to get
> "write" lock
> Is another process using the image?
> 
> (two times same file provided in cmdline arguments)

Yes, you're right. A bad cut'n'paste.

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 10/13] dp8393x: fix dp8393x_receive
  2018-06-08 20:05 ` [Qemu-devel] [RFC 10/13] dp8393x: fix dp8393x_receive Laurent Vivier
@ 2018-06-09  8:47   ` Hervé Poussineau
  0 siblings, 0 replies; 33+ messages in thread
From: Hervé Poussineau @ 2018-06-09  8:47 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf

Le 08/06/2018 à 22:05, Laurent Vivier a écrit :
> address_space_rw() access size must be multiplied by width.
> dp8393x_receive() must return the number of bytes read, not the length
> of the last memory access.
> 
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>   hw/net/dp8393x.c | 8 +++++---
>   1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
> index f2d2ce344c..ef5f1eb94f 100644
> --- a/hw/net/dp8393x.c
> +++ b/hw/net/dp8393x.c
> @@ -808,9 +808,11 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
>           /* EOL detected */
>           s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
>       } else {
> +        size = sizeof(uint16_t) * width;
>           data[0 * width] = 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);
> +        address_space_rw(&s->as,
> +            dp8393x_crda(s) + sizeof(uint16_t) * 6 * width,
> +            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
>           s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
>           s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
>           s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
> @@ -824,7 +826,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
>       /* Done */
>       dp8393x_update_irq(s);
>   
> -    return size;
> +    return rx_len;
>   }
>   
>   static void dp8393x_reset(DeviceState *dev)
> 

NACK. This breaks NetBSD 5.1/arc networking.

This seems to revert the following commit and change the function return value.

commit 409b52bfe199d8106dadf7c5ff3d88d2228e89b5
Author: Hervé Poussineau <hpoussin@reactos.org>
Date:   Wed Jun 3 22:45:48 2015 +0200

     net/dp8393x: correctly reset in_use field

     Don't write more than the field width, which is always 16 bit.
     Fixes network in NetBSD 5.1/arc

     Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
     Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
     Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>

diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 4184045145..ff633f76a0 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -764,7 +764,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
          data[0 * width] = 0; /* in_use */
          address_space_rw(&s->as,
              ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
-            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
+            MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
          s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
          s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
          s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus
  2018-06-08 20:05 ` [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus Laurent Vivier
@ 2018-06-09  8:55   ` Hervé Poussineau
  2018-06-09 18:25   ` Thomas Huth
  1 sibling, 0 replies; 33+ messages in thread
From: Hervé Poussineau @ 2018-06-09  8:55 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf

Le 08/06/2018 à 22:05, Laurent Vivier a écrit :
> This is needed by Quadra 800, this card can run on little-endian
> or big-endian bus.
> 
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>   hw/net/dp8393x.c | 101 ++++++++++++++++++++++++++++++++++++++-----------------
>   1 file changed, 70 insertions(+), 31 deletions(-)
> 

Works OK on NetBSD 5.1/arc on MIPS Magnum.

Tested-by: Hervé Poussineau <hpoussin@reactos.org>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack
  2018-06-08 20:05 ` [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack Laurent Vivier
@ 2018-06-09  8:55   ` Hervé Poussineau
  2018-06-09 18:36   ` Thomas Huth
  1 sibling, 0 replies; 33+ messages in thread
From: Hervé Poussineau @ 2018-06-09  8:55 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf

Le 08/06/2018 à 22:05, Laurent Vivier a écrit :
> It's only 32 bytes, and this simplifies the dp8393x_get()/
> dp8393x_put() interface.
> 
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>   hw/net/dp8393x.c | 107 ++++++++++++++++++++++++++-----------------------------
>   1 file changed, 51 insertions(+), 56 deletions(-)
>

Works OK on NetBSD 5.1/arc on MIPS Magnum.

Tested-by: Hervé Poussineau <hpoussin@reactos.org>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 13/13] dp8393x: fix receiving buffer exhaustion
  2018-06-08 20:05 ` [Qemu-devel] [RFC 13/13] dp8393x: fix receiving buffer exhaustion Laurent Vivier
@ 2018-06-09  8:55   ` Hervé Poussineau
  0 siblings, 0 replies; 33+ messages in thread
From: Hervé Poussineau @ 2018-06-09  8:55 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf

Le 08/06/2018 à 22:05, Laurent Vivier a écrit :
> The card is not able to exit from exhaustion state, because
> while the drive consumes the buffers, the RRP is incremented
> (when the driver clears the ISR RBE bit), so it stays equal
> to RWP, and while RRP == RWP, the card thinks it is always
> in exhaustion state. So the driver consumes all the buffers,
> but the card cannot receive new ones.
> 
> This patch fixes the problem by not incrementing RRP when
> the driver clears the ISR RBE bit.
> 
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>   hw/net/dp8393x.c | 31 ++++++++++++++++---------------
>   1 file changed, 16 insertions(+), 15 deletions(-)
> 

Works OK on NetBSD 5.1/arc on MIPS Magnum.

Tested-by: Hervé Poussineau <hpoussin@reactos.org>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh
  2018-06-08 20:05 ` [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh Laurent Vivier
@ 2018-06-09  8:57   ` Hervé Poussineau
  2018-06-09 10:19   ` Mark Cave-Ayland
  1 sibling, 0 replies; 33+ messages in thread
From: Hervé Poussineau @ 2018-06-09  8:57 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Aurelien Jarno, qemu-block, Gerd Hoffmann,
	Dr. David Alan Gilbert, Andreas Färber, Jason Wang,
	Paolo Bonzini, Yongbok Kim, Fam Zheng, Max Reitz, Kevin Wolf

Le 08/06/2018 à 22:05, Laurent Vivier a écrit :
> From: Laurent Vivier <Laurent@Vivier.EU>
> 
> Signed-off-by: Laurent Vivier <Laurent@Vivier.EU>
> ---
>   hw/mips/mips_jazz.c   |   2 +-
>   hw/scsi/esp.c         | 330 +++++++++++++++++++++++++++++++++++++++++++++-----
>   include/hw/scsi/esp.h |  15 ++-
>   3 files changed, 313 insertions(+), 34 deletions(-)
>
Works OK on NetBSD 5.1/arc on MIPS Magnum.

Tested-by: Hervé Poussineau <hpoussin@reactos.org>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 01/13] hw/m68k: add via support
  2018-06-08 20:05 ` [Qemu-devel] [RFC 01/13] hw/m68k: add via support Laurent Vivier
@ 2018-06-09 10:01   ` Mark Cave-Ayland
  2018-06-09 15:48     ` Mark Cave-Ayland
  0 siblings, 1 reply; 33+ messages in thread
From: Mark Cave-Ayland @ 2018-06-09 10:01 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 08/06/18 21:05, Laurent Vivier wrote:

> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>   hw/input/adb.c            |  99 ++++-
>   hw/misc/Makefile.objs     |   1 +
>   hw/misc/mac_via.c         | 940 ++++++++++++++++++++++++++++++++++++++++++++++
>   include/hw/input/adb.h    |   8 +
>   include/hw/misc/mac_via.h |  45 +++
>   5 files changed, 1092 insertions(+), 1 deletion(-)
>   create mode 100644 hw/misc/mac_via.c
>   create mode 100644 include/hw/misc/mac_via.h
> 
> diff --git a/hw/input/adb.c b/hw/input/adb.c
> index 23ae6f0d75..2e5460730c 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)
>   
> @@ -57,7 +68,6 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
>       return ADB_RET_NOTPRESENT;
>   }
>   
> -/* XXX: move that to cuda ? */
>   int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
>   {
>       ADBDevice *d;
> @@ -84,6 +94,93 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
>       return olen;
>   }
>   
> +int adb_send(ADBBusState *adb, int state, uint8_t data)
> +{
> +    switch (state) {
> +    case STATE_NEW:
> +        adb->data_out[0] = data;
> +        adb->data_out_index = 1;
> +        break;
> +    case STATE_EVEN:
> +        if ((adb->data_out_index & 1) == 0) {
> +            return 0;
> +        }
> +        adb->data_out[adb->data_out_index++] = data;
> +        break;
> +    case STATE_ODD:
> +        if (adb->data_out_index & 1) {
> +            return 0;
> +        }
> +        adb->data_out[adb->data_out_index++] = data;
> +        break;
> +    case STATE_IDLE:
> +        return 0;
> +    }
> +    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;
> +        }
> +        *data = adb->data_in[adb->data_in_index++];
> +        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;
> +        }
> +        *data = adb->data_in[adb->data_in_index++];
> +        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;
> +        if (adb->data_in_size < 0) {
> +            *data = 0xff;
> +            qemu_irq_raise(adb->data_ready);
> +            return -1;
> +        }
> +        if (adb->data_in_size == 0) {
> +            return 0;
> +        }
> +        *data = adb->data_in[0];
> +        adb->data_in_index = 1;
> +        break;
> +    }
> +    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,

I'm not completely convinced by this part: from working on Mac PMU 
patches my feeling is that any buffering should be handled by the level 
above the ADB bus, since once you've sent/received something the 
supporting logic appears completely different.

Having said that, the ADB bus state part is new so I'm not sure I 
understand why this is currently needed?

> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 00e834d0f0..2cd8941faa 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -68,5 +68,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..a6a11c5b3d
> --- /dev/null
> +++ b/hw/misc/mac_via.c
> @@ -0,0 +1,940 @@
> +/*
> + * 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/input/adb.h"
> +#include "sysemu/sysemu.h"
> +#include "qemu/cutils.h"
> +
> +/* debug VIA */
> +#undef DEBUG_VIA
> +
> +#ifdef DEBUG_VIA
> +#define VIA_DPRINTF(fmt, ...)                                  \
> +    do { printf("VIA%d: " fmt , via, ## __VA_ARGS__); } while (0)
> +#else
> +#define VIA_DPRINTF(fmt, ...)
> +#endif
> +
> +/*
> + * 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
> +
> +typedef struct VIATimer {
> +    int index;
> +    uint16_t counter; /* Timer counter */
> +    uint16_t latch;   /* Timer latch */
> +    int64_t next_irq_time;
> +    QEMUTimer *timer;
> +} VIATimer;
> +
> +typedef struct VIAState {
> +    /* VIA registers */
> +    uint8_t a;    /* data register A */
> +    uint8_t b;    /* data register B */
> +    uint8_t dira; /* data direction register A (1 = output) */
> +    uint8_t dirb; /* data direction register B (1 = output) */
> +    uint8_t pcr;  /* peripheral control register */
> +    uint8_t acr;  /* auxiliary control register */
> +    uint8_t ifr;  /* interrupt flag register */
> +    uint8_t ier;  /* interrupt enable register */
> +    uint8_t sr;   /* shift register */
> +
> +    uint8_t last_b;
> +
> +    /* Timers */
> +
> +    VIATimer timers[2];
> +
> +    /* IRQs */
> +
> +    qemu_irq out_irq;
> +
> +} VIAState;
> +
> +typedef struct MacVIAState {
> +    SysBusDevice busdev;
> +
> +    /* MMIO */
> +
> +    MemoryRegion mmio;
> +
> +    /* VIAs */
> +
> +    VIAState via[2];
> +
> +    /* 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;
> +
> +#define VIA_TIMER_FREQ (783360)
> +
> +static int64_t get_next_irq_time(VIATimer *s, int64_t current_time)
> +{
> +    int64_t d, next_time;
> +
> +    /* current counter value */
> +    d = muldiv64(current_time, VIA_TIMER_FREQ, NANOSECONDS_PER_SECOND);
> +    next_time = d + s->counter;
> +    next_time = muldiv64(next_time, NANOSECONDS_PER_SECOND, VIA_TIMER_FREQ);
> +    if (next_time <= current_time) {
> +        next_time = current_time + 1;
> +    }
> +    return next_time;
> +}
> +
> +#define T1MODE      0xc0
> +#define T1MODE_CONT 0x40
> +
> +static void via_arm_timer(VIATimer *ti, int64_t current_time)
> +{
> +    if (!ti->timer) {
> +        return;
> +    }
> +    ti->next_irq_time = get_next_irq_time(ti, current_time);
> +    timer_mod(ti->timer, ti->next_irq_time);
> +}
> +
> +static void via_timer_update(VIAState *s, VIATimer *ti,
> +                             int64_t current_time)
> +{
> +    if (!ti->timer) {
> +        return;
> +    }
> +    if (!(s->ier & VIA_IRQ_TIMER1) &&
> +        (s->acr & T1MODE) != T1MODE_CONT) {
> +        timer_del(ti->timer);
> +    } else {
> +        ti->counter = ti->latch;
> +        via_arm_timer(ti, current_time);
> +    }
> +}
> +
> +static void via_update_irq(VIAState *s)
> +{
> +    if (s->ifr & s->ier) {
> +        qemu_irq_raise(s->out_irq);
> +    } else {
> +        qemu_irq_lower(s->out_irq);
> +    }
> +}
> +
> +static void via_timer1(void *opaque)
> +{
> +    VIAState *s = opaque;
> +    VIATimer *ti = &s->timers[0];
> +
> +    via_timer_update(s, ti, ti->next_irq_time);
> +    s->ifr |= VIA_IRQ_TIMER1;
> +    via_update_irq(s);
> +}
> +
> +static void via1_VBL_update(MacVIAState *m)
> +{
> +    if (m->via[0].ifr & m->via[0].ier & VIA1_IRQ_VBLANK) { /* 60 Hz irq */
> +        timer_mod(m->VBL_timer, (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16630)
> +                  / 16630 * 16630);
> +    } else {
> +        timer_del(m->VBL_timer);
> +    }
> +}
> +
> +static void via1_VBL(void *opaque)
> +{
> +    MacVIAState *m = opaque;
> +    via1_VBL_update(m);
> +    m->via[0].ifr |= VIA1_IRQ_VBLANK;
> +    via_update_irq(&m->via[0]);
> +}
> +
> +static void via1_irq_request(VIAState *s, int irq, int level)
> +{
> +    if (level) {
> +        s->ifr |= 1 << irq;
> +    } else {
> +        s->ifr &= ~(1 << irq);
> +    }
> +    via_update_irq(s);
> +}
> +
> +static void via2_irq_request(VIAState *s, int irq, int level)
> +{
> +    if (level) {
> +        s->ifr |= 1 << irq;
> +    } else {
> +        s->ifr &= ~(1 << irq);
> +    }
> +    via_update_irq(s);
> +}
> +
> +static void via_irq_request(void *opaque, int irq, int level)
> +{
> +    MacVIAState *s = opaque;
> +    if (irq < VIA1_IRQ_NB) {
> +        via1_irq_request(&s->via[0], irq, level);
> +        return;
> +    }
> +    irq -= VIA1_IRQ_NB;
> +    if (irq < VIA2_IRQ_NB) {
> +        via2_irq_request(&s->via[1], irq, level);
> +        return;
> +    }
> +}
> +
> +static void via1_one_second_update(MacVIAState *m)
> +{
> +    if (m->via[0].ifr & m->via[0].ier & VIA1_IRQ_ONE_SECOND) {
> +        timer_mod(m->one_second_timer, (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
> +                  + 1000) / 1000 * 1000);
> +    } else {
> +        timer_del(m->one_second_timer);
> +    }
> +}
> +
> +static void via1_one_second(void *opaque)
> +{
> +    MacVIAState *m = opaque;
> +    via1_one_second_update(m);
> +    m->via[0].ifr |= VIA1_IRQ_ONE_SECOND;
> +    via_update_irq(&m->via[0]);
> +}
> +
> +static void via_irq_update(MacVIAState *m, int via)
> +{
> +    switch (via) {
> +    case 0:
> +        via1_one_second_update(m);
> +        via1_VBL(m);
> +        break;
> +    case 1:
> +        break;
> +    }
> +}
> +
> +#define RTC_OFFSET 2082844800
> +static uint8_t PRAM[256];
> +
> +static void via1_rtc_update(MacVIAState *m)
> +{
> +    VIAState *s = &m->via[0];
> +
> +    if (s->b & VIA1B_vRTCEnb) {
> +        return;
> +    }
> +
> +    if (s->dirb & VIA1B_vRTCData) {
> +        /* send bits to the RTC */
> +        if (!(s->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 ((s->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 void via1_adb_update(MacVIAState *m)
> +{
> +    VIAState *s = &m->via[0];
> +    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->b &= ~VIA1B_vADBInt;
> +        } else {
> +            s->b |= VIA1B_vADBInt;
> +        }
> +    }
> +}
> +
> +static void via_write(void *opaque, hwaddr addr,
> +                       uint64_t val, unsigned int size)
> +{
> +    MacVIAState *m = opaque;
> +    VIAState *s;
> +    int via;
> +
> +    via = addr / VIA_SIZE;
> +    addr &= VIA_SIZE - 1;
> +
> +    s = &m->via[via];
> +
> +    switch (addr) {
> +    case vBufA: /* Buffer A */
> +        VIA_DPRINTF("writeb: vBufA = %02"PRIx64"\n", val);
> +        s->a = (s->a & ~s->dira) | (val & s->dira);
> +        break;
> +    case vBufB:  /* Register B */
> +        VIA_DPRINTF("writeb: vBufB = %02"PRIx64"\n", val);
> +        s->b = (s->b & ~s->dirb) | (val & s->dirb);
> +        switch (via) {
> +        case 0:
> +            via1_rtc_update(m);
> +            via1_adb_update(m);
> +            s->last_b = s->b;
> +            break;
> +        case 1:
> +            if (s->dirb & VIA2B_vPower &&
> +                (val & VIA2B_vPower) == 0) {
> +                /* shutdown */
> +                qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +            }
> +            break;
> +        }
> +        break;
> +    case vDirA:  /* Data Direction Register A. */
> +        VIA_DPRINTF("writeb: vDirA = %02"PRIx64"\n", val);
> +        s->dira = val;
> +        break;
> +    case vDirB:  /* Data Direction Register B. */
> +        VIA_DPRINTF("writeb: vDirB = %02"PRIx64"\n", val);
> +        s->dirb = val;
> +        break;
> +    case vT1CL:  /* Timer one counter low. */
> +        VIA_DPRINTF("writeb: vT1CL = %02"PRIx64"\n", val);
> +        s->timers[0].counter = (s->timers[0].counter & 0xff00) | val;
> +        break;
> +    case vT1CH:  /* Timer one counter high. */
> +        VIA_DPRINTF("writeb: vT1CH = %02"PRIx64"\n", val);
> +        s->timers[0].counter = (s->timers[0].counter & 0x00ff) | (val << 8);
> +        via_arm_timer(&s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
> +        break;
> +    case vT1LL:  /* Timer one latches low. */
> +        VIA_DPRINTF("writeb: vT1LL = %02"PRIx64"\n", val);
> +        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
> +        break;
> +    case vT1LH:  /* Timer one latches high. */
> +        VIA_DPRINTF("writeb: vT1LH = %02"PRIx64"\n", val);
> +        s->timers[0].latch = (s->timers[0].latch & 0x00ff) | (val << 8);
> +        via_arm_timer(&s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
> +        break;
> +    case vT2CL:  /* Timer two counter low. */
> +        VIA_DPRINTF("writeb: vT2CL = %02"PRIx64"\n", val);
> +        s->timers[1].counter = (s->timers[1].counter & 0xff00) | val;
> +        break;
> +    case vT2CH:  /* Timer two counter high. */
> +        VIA_DPRINTF("writeb: vT2CH = %02"PRIx64"\n", val);
> +        s->timers[1].counter = (s->timers[1].counter & 0x00ff) | (val << 8);
> +        via_arm_timer(&s->timers[1], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
> +        break;
> +    case vSR:    /* Shift register. */
> +        VIA_DPRINTF("writeb: vSR = %02"PRIx64"\n", val);
> +        s->sr = val;
> +        break;
> +    case vACR:   /* Auxilary control register. */
> +        VIA_DPRINTF("writeb: vACR = %02"PRIx64"\n", val);
> +        s->acr = val;
> +        via_timer_update(s, &s->timers[0],
> +                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
> +        break;
> +    case vPCR:   /* Peripheral control register. */
> +        VIA_DPRINTF("writeb: vPCR = %02"PRIx64"\n", val);
> +        s->pcr = val;
> +        break;
> +    case vIFR:   /* Interrupt flag register. */
> +        VIA_DPRINTF("writeb: vIFR = %02"PRIx64"\n", val);
> +        if (val & IRQ_SET) {
> +            /* set bits */
> +            s->ifr |= val & 0x7f;
> +        } else {
> +            /* clear bits */
> +            s->ifr &= ~val;
> +        }
> +        VIA_DPRINTF("            -> %02x\n", s->ifr);
> +        via_timer_update(s, &s->timers[0],
> +                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
> +        via_irq_update(m, via);
> +        break;
> +    case vIER:   /* Interrupt enable register. */
> +        VIA_DPRINTF("writeb: vIER = %02"PRIx64"\n", val);
> +        if (val & IRQ_SET) {
> +            /* set bits */
> +            s->ier |= val & 0x7f;
> +        } else {
> +            /* clear bits */
> +            s->ier &= ~val;
> +        }
> +        VIA_DPRINTF("            -> %02x\n", s->ier);
> +        via_timer_update(s, &s->timers[0],
> +                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
> +        via_irq_update(m, via);
> +        break;
> +    default:
> +        VIA_DPRINTF("writeb: addr 0x%08lx val %02"PRIx64"\n", (long)addr, val);
> +        break;
> +    }
> +}
> +
> +static uint64_t via_read(void *opaque, hwaddr addr,
> +                         unsigned int size)
> +{
> +    MacVIAState *m = opaque;
> +    VIAState *s;
> +    uint32_t val;
> +    int via;
> +
> +    via = addr / VIA_SIZE;
> +    addr &= VIA_SIZE - 1;
> +
> +    s = &m->via[via];
> +
> +    switch (addr) {
> +    case vBufA: /* Buffer A */
> +        val = s->a;
> +        VIA_DPRINTF("readb:  vBufA = %02x\n", val);
> +        break;
> +    case vBufB:  /* Register B */
> +        val = s->b;
> +        VIA_DPRINTF("readb:  vBufB = %02x\n", val);
> +        break;
> +    case vDirA:  /* Data Direction Register A. */
> +        val = s->dira;
> +        VIA_DPRINTF("readb:  vDirA = %02x\n", val);
> +        break;
> +    case vDirB:  /* Data Direction Register B. */
> +        val = s->dirb;
> +        VIA_DPRINTF("readb:  vDirB = %02x\n", val);
> +        break;
> +    case vT1CL:  /* Timer one counter low. */
> +        val = s->timers[0].counter & 0x00ff;
> +        VIA_DPRINTF("readb:  vT1CL = %02x\n", val);
> +        break;
> +    case vT1CH:  /* Timer one counter high. */
> +        val = (s->timers[0].counter >> 8) & 0x00ff;
> +        VIA_DPRINTF("readb:  vT1CH = %02x\n", val);
> +        break;
> +    case vT1LL:  /* Timer one latches low. */
> +        val = s->timers[0].latch & 0x00ff;
> +        VIA_DPRINTF("readb:  vT1LL = %02x\n", val);
> +        break;
> +    case vT1LH:  /* Timer one latches high. */
> +        val = (s->timers[0].latch >> 8) & 0x00ff;
> +        VIA_DPRINTF("readb:  vT1LH = %02x\n", val);
> +        break;
> +    case vT2CL:  /* Timer two counter low. */
> +        val = s->timers[1].counter & 0x00ff;
> +        VIA_DPRINTF("readb:  vT2CL = %02x\n", val);
> +        break;
> +    case vT2CH:  /* Timer two counter high. */
> +        val = (s->timers[1].counter >> 8) & 0x00ff;
> +        VIA_DPRINTF("readb:  vT2CH = %02x\n", val);
> +        break;
> +    case vSR:    /* Shift register. */
> +        val = s->sr;
> +        VIA_DPRINTF("readb:  vSR = %02x\n", val);
> +        break;
> +    case vACR:   /* Auxilary control register. */
> +        val = s->acr;
> +        VIA_DPRINTF("readb:  vACR = %02x\n", val);
> +        break;
> +    case vPCR:   /* Peripheral control register. */
> +        val = s->pcr;
> +        VIA_DPRINTF("readb:  vPCR = %02x\n", val);
> +        break;
> +    case vIFR:   /* Interrupt flag register. */
> +        val = s->ifr | ((s->ifr & 0x7f) ? IRQ_SET : 0);
> +        VIA_DPRINTF("readb:  vIFR = %02x\n", val);
> +        break;
> +    case vIER:   /* Interrupt enable register. */
> +        val = s->ier | IRQ_SET;
> +        VIA_DPRINTF("readb:  vIER = %02x\n", val);
> +        break;
> +    default:
> +        val = 0;
> +        VIA_DPRINTF("readb:  addr 0x%08lx val ??\n", (long)addr);
> +        break;
> +    }
> +    return val;
> +}
> +
> +static const MemoryRegionOps via_ops = {
> +    .read = via_read,
> +    .write = via_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static void mac_via_reset(DeviceState *dev)
> +{
> +    MacVIAState *m = MAC_VIA(dev);
> +
> +    m->via[0].a = 0;
> +    /* 1 = disabled */
> +    m->via[0].b = VIA1B_vADB_StateMask | VIA1B_vADBInt | VIA1B_vRTCEnb;
> +    m->via[0].dira = 0;
> +    m->via[0].dirb = 0;
> +    m->via[0].pcr = 0;
> +    m->via[0].acr = 0;
> +    m->via[0].ifr = 0;
> +    m->via[0].ier = 0;
> +    m->via[0].sr = 0;
> +    m->via[0].last_b = 0;
> +
> +    m->via[0].timers[0].counter = 0;
> +    m->via[0].timers[0].latch = 0;
> +    m->via[0].timers[1].counter = 0;
> +    m->via[0].timers[1].latch = 0;
> +
> +    m->via[1].a = 0;
> +    m->via[1].b = 0;
> +    m->via[1].dira = 0;
> +    m->via[1].dirb = 0;
> +    m->via[1].pcr = 0;
> +    m->via[1].acr = 0;
> +    m->via[1].ifr = 0;
> +    m->via[1].ier = 0;
> +    m->via[1].sr = 0;
> +    m->via[1].last_b = 0;
> +
> +    m->via[1].timers[0].counter = 0;
> +    m->via[1].timers[0].latch = 0;
> +    m->via[1].timers[1].counter = 0;
> +    m->via[1].timers[1].latch = 0;
> +
> +    m->data_out = 0;
> +    m->data_out_cnt = 0;
> +    m->data_in = 0;
> +    m->data_in_cnt = 0;
> +    m->cmd = 0;
> +    m->wprotect = 0;
> +    m->alt = 0;
> +}
> +
> +static void mac_via_realizefn(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;
> +
> +    /* ouput IRQs */
> +
> +    m->via[0].timers[0].index = 0;
> +    m->via[0].timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                             via_timer1, &m->via[0]);
> +    m->via[0].timers[1].index = 1;
> +
> +    /* VIA 2 */
> +
> +    /* output IRQs */
> +
> +    m->via[1].timers[0].index = 0;
> +    m->via[1].timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                             via_timer1, &m->via[1]);
> +    m->via[1].timers[1].index = 1;
> +}
> +
> +static void mac_via_initfn(Object *obj)
> +{
> +    SysBusDevice *d = SYS_BUS_DEVICE(obj);
> +    MacVIAState *m = MAC_VIA(obj);
> +
> +    memory_region_init_io(&m->mmio, NULL, &via_ops, m, "via", 2 * VIA_SIZE);
> +    sysbus_init_mmio(d, &m->mmio);
> +
> +    /* input IRQs */
> +
> +    qdev_init_gpio_in(DEVICE(d), via_irq_request, VIA1_IRQ_NB + VIA2_IRQ_NB);
> +
> +    /* ouput IRQs */
> +
> +    sysbus_init_irq(d, &m->via[0].out_irq);
> +    sysbus_init_irq(d, &m->via[1].out_irq);
> +
> +    /* ABD */
> +
> +    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(DEVICE(d),
> +                                             VIA1_IRQ_ADB_READY_BIT);
> +}
> +
> +static void mac_via_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    dc->realize = mac_via_realizefn;
> +    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_initfn,
> +    .class_init = mac_via_class_init,
> +};
> +
> +static void mac_via_register_types(void)
> +{
> +    type_register_static(&mac_via_info);
> +}
> +
> +type_init(mac_via_register_types);
> diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h
> index 3ae8445e95..ce393004eb 100644
> --- a/include/hw/input/adb.h
> +++ b/include/hw/input/adb.h
> @@ -75,6 +75,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,
> @@ -84,4 +90,6 @@ 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_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
> new file mode 100644
> index 0000000000..e106133c2a
> --- /dev/null
> +++ b/include/hw/misc/mac_via.h
> @@ -0,0 +1,45 @@
> +/*
> + *
> + * 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
> +#define TYPE_MAC_VIA "mac_via"
> +#define MAC_VIA(obj)   OBJECT_CHECK(MacVIAState, (obj), TYPE_MAC_VIA)
> +
> +/* VIA1 */
> +
> +#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)
> +
> +/* VIA2 */
> +
> +#define VIA2_IRQ_SCSI_DATA_BIT  (VIA1_IRQ_NB + 0)
> +#define VIA2_IRQ_SLOT_BIT       (VIA1_IRQ_NB + 1)
> +#define VIA2_IRQ_UNUSED_BIT     (VIA1_IRQ_NB + 2)
> +#define VIA2_IRQ_SCSI_BIT       (VIA1_IRQ_NB + 3)
> +#define VIA2_IRQ_ASC_BIT        (VIA1_IRQ_NB + 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)
> +#endif

Yeah, we can certainly remove a huge chunk of this by converting over to 
the mos6522 device. My last set of updates to CUDA a couple of days ago 
are probably the best reference, but I can probably find some time to do 
the basic conversion for you at some point...


ATB,

Mark.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 03/13] escc: introduce a selector for the register bit
  2018-06-08 20:05 ` [Qemu-devel] [RFC 03/13] escc: introduce a selector for the register bit Laurent Vivier
@ 2018-06-09 10:05   ` Mark Cave-Ayland
  0 siblings, 0 replies; 33+ messages in thread
From: Mark Cave-Ayland @ 2018-06-09 10:05 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 08/06/18 21:05, Laurent Vivier wrote:

> From: Laurent Vivier <Laurent@Vivier.EU>
> 
> 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 <laurent@vivier.eu>
> ---
>   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;
> 

I think that this is basically okay, but "bit_swap" doesn't really tell 
me much about what is being swapped - maybe something along the lines of 
"channel-bit0-reg-bit1"?


ATB,

Mark.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 04/13] hw/m68k: add video card
  2018-06-08 20:05 ` [Qemu-devel] [RFC 04/13] hw/m68k: add video card Laurent Vivier
@ 2018-06-09 10:14   ` Mark Cave-Ayland
  0 siblings, 0 replies; 33+ messages in thread
From: Mark Cave-Ayland @ 2018-06-09 10:14 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 08/06/18 21:05, Laurent Vivier wrote:

> From: Laurent Vivier <Laurent@Vivier.EU>
> 
> Signed-off-by: Laurent Vivier <Laurent@Vivier.EU>
> ---
>   arch_init.c                 |   4 +
>   hw/display/Makefile.objs    |   1 +
>   hw/display/macfb-template.h | 158 +++++++++++++++++++++++++
>   hw/display/macfb.c          | 283 ++++++++++++++++++++++++++++++++++++++++++++
>   qemu-options.hx             |   2 +-
>   vl.c                        |   3 +-
>   6 files changed, 449 insertions(+), 2 deletions(-)
>   create mode 100644 hw/display/macfb-template.h
>   create mode 100644 hw/display/macfb.c
> 
> 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 b5d97ab26d..925d5b848f 100644
> --- a/hw/display/Makefile.objs
> +++ b/hw/display/Makefile.objs
> @@ -19,6 +19,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

Fortunately most of this is now obsolete as the host surface has been 
fixed at 32-bits for a few years now which should help simplify things a 
lot.

For reference see the similar clear-up I did for TCX at ee72bed08c: tcx: 
remove primitives for non-32-bit surfaces.

> diff --git a/hw/display/macfb.c b/hw/display/macfb.c
> new file mode 100644
> index 0000000000..b2dd300a80
> --- /dev/null
> +++ b/hw/display/macfb.c
> @@ -0,0 +1,283 @@
> +/*
> + * 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"
> +
> +struct MacfbState {
> +    SysBusDevice busdev;
> +    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;
> +};
> +typedef struct MacfbState MacfbState;
> +
> +#define TYPE_MACFB "sysbus-macfb"
> +#define MACFB(obj) \
> +    OBJECT_CHECK(MacfbSysBusState, (obj), TYPE_MACFB)
> +
> +#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 inline void reset_dirty(MacfbState *s,
> +                               ram_addr_t page_min, ram_addr_t page_max)
> +{
> +    memory_region_reset_dirty(&s->mem_vram,
> +                              page_min,
> +                              page_max + MACFB_PAGE_SIZE - page_min - 1,
> +                              DIRTY_MEMORY_VGA);
> +}

Aha this probably explains why you get display glitches - with the 
advent of MTTCG you need to use memory_region_snapshot_get_dirty() 
otherwise the dirty bitmap can change during rendering.

For reference the relevant commit for TCX is:
     2dd285b5f3: tcx: make display updates thread safe

And you may also like to look at Paolo's latest update:

     0fe1eca7dc: memory: hide memory_region_sync_dirty_bitmap behind
                 DirtyBitmapSnapshot

> +static void macfb_draw_graphic(MacfbState *s)
> +{
> +    DisplaySurface *surface = qemu_console_surface(s->con);
> +    ram_addr_t page, page_min, page_max;
> +    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;
> +    }
> +
> +    page_min = (ram_addr_t)-1;
> +    page_max = 0;
> +    ymin = -1;
> +    page = 0;
> +    for (y = 0; y < s->height; y++) {
> +        int update;
> +
> +        update = memory_region_get_dirty(&s->mem_vram, page, macfb_stride,
> +                                         DIRTY_MEMORY_VGA);
> +
> +        if (update) {
> +            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;
> +            }
> +            if (page_min == (ram_addr_t)-1) {
> +                page_min = page;
> +            }
> +            page_max = page + macfb_stride - 1;
> +        } else {
> +            if (ymin >= 0) {
> +                dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
> +                ymin = -1;
> +            }
> +        }
> +        page += macfb_stride;
> +    }
> +    if (ymin >= 0) {
> +        dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
> +    }
> +    if (page_min != (ram_addr_t)-1) {
> +        reset_dirty(s, page_min, page_max);
> +    }
> +}
> +
> +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_init(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, "ctrl",
> +                          0x1000);
> +    memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram", MACFB_VRAM_SIZE,
> +                               s->vram);
> +    vmstate_register_ram(&s->mem_vram, dev);
> +    memory_region_set_coalescing(&s->mem_vram);
> +}
> +
> +typedef struct {
> +    SysBusDevice busdev;
> +    MacfbState macfb;
> +} MacfbSysBusState;
> +
> +static int macfb_sysbus_init(SysBusDevice *dev)
> +{
> +    MacfbState *s =  &MACFB(dev)->macfb;
> +
> +    macfb_init(DEVICE(dev), s);
> +    sysbus_init_mmio(dev, &s->mem_ctrl);
> +    sysbus_init_mmio(dev, &s->mem_vram);
> +
> +    return 0;
> +}
> +
> +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);
> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +
> +    k->init = macfb_sysbus_init;
> +    dc->desc = "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/qemu-options.hx b/qemu-options.hx
> index c0d3951e9f..c1181561e1 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1551,7 +1551,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 06031715ac..ac8e50ee92 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -3308,7 +3308,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') {
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh
  2018-06-08 20:05 ` [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh Laurent Vivier
  2018-06-09  8:57   ` Hervé Poussineau
@ 2018-06-09 10:19   ` Mark Cave-Ayland
  1 sibling, 0 replies; 33+ messages in thread
From: Mark Cave-Ayland @ 2018-06-09 10:19 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 08/06/18 21:05, Laurent Vivier wrote:

> From: Laurent Vivier <Laurent@Vivier.EU>
> 
> Signed-off-by: Laurent Vivier <Laurent@Vivier.EU>
> ---
>   hw/mips/mips_jazz.c   |   2 +-
>   hw/scsi/esp.c         | 330 +++++++++++++++++++++++++++++++++++++++++++++-----
>   include/hw/scsi/esp.h |  15 ++-
>   3 files changed, 313 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 */

A quick note here: last year I removed esp_init() from all of the SPARC 
code which means that mips/jazz is the last remaining user.

If we can switch this over to using qdev properties similar to how I did 
in 7f773ff5d0: sparc32_dma: make esp device child of espdma device then 
we can remove this function completely.

Hervé, is this something that you could take a quick look at?


ATB,

Mark.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 09/13] hw/m68k: define Macintosh Quadra 800
  2018-06-08 20:05 ` [Qemu-devel] [RFC 09/13] hw/m68k: define Macintosh Quadra 800 Laurent Vivier
@ 2018-06-09 10:24   ` Mark Cave-Ayland
  0 siblings, 0 replies; 33+ messages in thread
From: Mark Cave-Ayland @ 2018-06-09 10:24 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 08/06/18 21:05, Laurent Vivier wrote:

> From: Laurent Vivier <Laurent@Vivier.EU>
> 
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>   default-configs/m68k-softmmu.mak |  12 ++
>   hw/display/macfb.c               |  31 ++--
>   hw/m68k/Makefile.objs            |   6 +-
>   hw/m68k/bootinfo.h               |  99 ++++++++++
>   hw/m68k/mac.c                    | 384 +++++++++++++++++++++++++++++++++++++++
>   hw/nubus/nubus-device.c          |  13 --
>   tests/qom-test.c                 |   5 +
>   tests/test-hmp.c                 |   3 +-
>   8 files changed, 519 insertions(+), 34 deletions(-)
>   create mode 100644 hw/m68k/bootinfo.h
>   create mode 100644 hw/m68k/mac.c
> 
> diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
> index 60f7cdfbf2..1b568be166 100644
> --- a/default-configs/m68k-softmmu.mak
> +++ b/default-configs/m68k-softmmu.mak
> @@ -2,3 +2,15 @@
>   
>   CONFIG_COLDFIRE=y
>   CONFIG_PTIMER=y
> +CONFIG_ESCC=y
> +CONFIG_FRAMEBUFFER=y
> +CONFIG_ADB=y
> +CONFIG_MAC_VIA=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/display/macfb.c b/hw/display/macfb.c
> index 295fd0fc8a..a3204ab150 100644
> --- a/hw/display/macfb.c
> +++ b/hw/display/macfb.c
> @@ -240,31 +240,28 @@ typedef struct {
>       MacfbState macfb;
>   } MacfbNubusState;
>   
> -static int macfb_sysbus_init(SysBusDevice *dev)
> +static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
>   {
>       MacfbState *s =  &MACFB(dev)->macfb;
>   
> -    macfb_init(DEVICE(dev), s);
> -    sysbus_init_mmio(dev, &s->mem_ctrl);
> -    sysbus_init_mmio(dev, &s->mem_vram);
> -
> -    return 0;
> +    macfb_init(dev, s);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mem_ctrl);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mem_vram);
>   }
>   
>   const uint8_t macfb_rom[] = {
>       255, 0, 0, 0,
>   };
>   
> -static int macfb_nubus_init(NubusDevice *dev)
> +static void macfb_nubus_realize(DeviceState *dev, Error **errp)
>   {
> -    MacfbState *s = &DO_UPCAST(MacfbNubusState, busdev, dev)->macfb;

DO_UPCAST() - wow that's a blast from the past! Obviously these should 
be handled via proper QOM objects and casts.

> +    NubusDevice *nubus = NUBUS_DEVICE(dev);
> +    MacfbState *s = &DO_UPCAST(MacfbNubusState, busdev, nubus)->macfb;
>   
> -    macfb_init(DEVICE(dev), s);
> -    nubus_add_slot_mmio(dev, DAFB_BASE, &s->mem_ctrl);
> -    nubus_add_slot_mmio(dev, VIDEO_BASE, &s->mem_vram);
> -    nubus_register_rom(dev, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
> -
> -    return 0;
> +    macfb_init(dev, s);
> +    nubus_add_slot_mmio(nubus, DAFB_BASE, &s->mem_ctrl);
> +    nubus_add_slot_mmio(nubus, VIDEO_BASE, &s->mem_vram);
> +    nubus_register_rom(nubus, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
>   }
>   
>   static void macfb_sysbus_reset(DeviceState *d)
> @@ -296,9 +293,8 @@ static Property macfb_nubus_properties[] = {
>   static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
>   {
>       DeviceClass *dc = DEVICE_CLASS(klass);
> -    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>   
> -    k->init = macfb_sysbus_init;
> +    dc->realize = macfb_sysbus_realize;
>       dc->desc = "SysBus Macintosh framebuffer";
>       dc->reset = macfb_sysbus_reset;
>       dc->vmsd = &vmstate_macfb;
> @@ -308,9 +304,8 @@ static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
>   static void macfb_nubus_class_init(ObjectClass *klass, void *data)
>   {
>       DeviceClass *dc = DEVICE_CLASS(klass);
> -    NubusDeviceClass *k = NUBUS_DEVICE_CLASS(klass);
>   
> -    k->init = macfb_nubus_init;
> +    dc->realize = macfb_nubus_realize;
>       dc->desc = "Nubus Macintosh framebuffer";
>       dc->reset = macfb_nubus_reset;
>       dc->vmsd = &vmstate_macfb;
> diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs
> index d1f089c08a..ff739617b2 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) += mac.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..b04153ce1e
> --- /dev/null
> +++ b/hw/m68k/bootinfo.h
> @@ -0,0 +1,99 @@
> +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/mac.c b/hw/m68k/mac.c
> new file mode 100644
> index 0000000000..d573339e66
> --- /dev/null
> +++ b/hw/m68k/mac.c
> @@ -0,0 +1,384 @@
> +/*
> + * 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.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
> +
> +typedef struct {
> +    M68kCPU *cpu;
> +    uint8_t ipr;
> +} q800_glue_state_t;
> +
> +static void q800_glue_set_irq(void *opaque, int irq, int level)
> +{
> +    int i;
> +
> +    q800_glue_state_t *s = opaque;
> +
> +    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);
> +}

I would recommend making this a separate QOM device, and having the 
board wire up the CPU IRQs and expose them via qdev GPIOs so then 
everything else can wire up interrupts via the standard qdev_gpio APIs.

It is a bit more work, but doing it this way makes the board wiring much 
easier to follow.

> +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;
> +    q800_glue_state_t *s;
> +    qemu_irq *pic;
> +    hwaddr parameters_base;
> +    CPUState *cs;
> +    DeviceState *dev;
> +    DeviceState *via_dev;
> +    SysBusDevice *sysbus;
> +    BusState *adb_bus;
> +    qemu_irq  esp_reset_irq, esp_dma_enable;
> +    NubusBus *nubus;
> +    NubusDevice *nubus_dev;
> +    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);
> +
> +    /* Glue */
> +
> +    s = (q800_glue_state_t *)g_malloc0(sizeof(q800_glue_state_t));
> +    s->cpu = cpu;
> +    pic = qemu_allocate_irqs(q800_glue_set_irq, s, 6);
> +
> +    /* 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);
> +    sysbus_connect_irq(sysbus, 0, pic[0]);
> +    sysbus_connect_irq(sysbus, 1, pic[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, pic[2]);
> +
> +    /* SCC */
> +
> +    dev = qdev_create(NULL, "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, pic[3]);
> +    sysbus_connect_irq(sysbus, 1, pic[3]);
> +    sysbus_mmio_map(sysbus, 0, SCC_BASE);
> +
> +    /* SCSI */
> +
> +    esp_init_pdma(ESP_BASE, 4, ESP_PDMA,
> +                  qdev_get_gpio_in(via_dev, VIA2_IRQ_SCSI_BIT),
> +                  qdev_get_gpio_in(via_dev, VIA2_IRQ_SCSI_DATA_BIT),
> +                  &esp_reset_irq, &esp_dma_enable);
> +
> +    /* Apple Sound Chip */
> +
> +    dev = qdev_create(NULL, "apple-sound-chip");
> +    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(via_dev, 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, "sysbus-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 */
> +
> +    nubus = nubus_mac_new(NUBUS_SUPER_SLOT_BASE, NUBUS_SLOT_BASE);
> +
> +    /* framebuffer in nubus slot #9 */
> +
> +    nubus_dev = nubus_create(nubus, "nubus-macfb");
> +    qdev_prop_set_uint32(&nubus_dev->qdev, "width", graphic_width);
> +    qdev_prop_set_uint32(&nubus_dev->qdev, "height", graphic_height);
> +    qdev_prop_set_uint8(&nubus_dev->qdev, "depth", graphic_depth);
> +    qdev_init_nofail(&nubus_dev->qdev);
> +
> +    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/hw/nubus/nubus-device.c b/hw/nubus/nubus-device.c
> index 0c8023d46a..7fd1e03909 100644
> --- a/hw/nubus/nubus-device.c
> +++ b/hw/nubus/nubus-device.c
> @@ -238,22 +238,9 @@ static void nubus_device_init(Object *obj)
>   {
>   }
>   
> -static int nubus_qdev_init(DeviceState *qdev)
> -{
> -    NubusDevice *dev = NUBUS_DEVICE(qdev);
> -    NubusDeviceClass *klass = NUBUS_DEVICE_GET_CLASS(dev);
> -
> -    if (klass->init) {
> -        return klass->init(dev);
> -    }
> -
> -    return 0;
> -}
> -
>   static void nubus_device_class_init(ObjectClass *klass, void *data)
>   {
>       DeviceClass *k = DEVICE_CLASS(klass);
> -    k->init = nubus_qdev_init;
>       k->bus_type = TYPE_NUBUS_BUS;
>   }
>   
> 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;
>       }


ATB,

Mark.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine
  2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
                   ` (14 preceding siblings ...)
  2018-06-09  3:26 ` Philippe Mathieu-Daudé
@ 2018-06-09 14:25 ` Philippe Mathieu-Daudé
  2018-06-09 18:14   ` Thomas Huth
  15 siblings, 1 reply; 33+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-06-09 14:25 UTC (permalink / raw)
  To: Laurent Vivier, Hervé Poussineau, Richard Henderson
  Cc: qemu-devel, Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Gerd Hoffmann, Paolo Bonzini,
	Yongbok Kim, Andreas Färber, Aurelien Jarno

Hi Laurent,

On 06/08/2018 05:05 PM, Laurent Vivier wrote:
> if you want to test the machine, I'm sorry, it doesn't boot
> a MacROM, but you can boot a linux kernel from the command line.
> 
> You can install your own disk using debian-installer, with:
> 
>     ...
>     -M q800 \
>     -serial none -serial mon:stdio \
>     -m 1000M -drive file=m68k.qcow2,format=qcow2 \
>     -net nic,model=dp83932,addr=09:00:07:12:34:57 \
>     -append "console=ttyS0 vga=off" \
>     -kernel vmlinux-4.15.0-2-m68k \
>     -initrd initrd.gz \
>     -drive file=debian-9.0-m68k-NETINST-1.iso \
>     -drive file=m68k.qcow2,format=qcow2 \
>     -nographic
> 
> If you use a graphic adapter instead of "-nographic", you can use "-g" to set the
> size of the display (I use "-g 1600x800x24").
> 
> You can get the ISO from:
> 
> https://cdimage.debian.org/mirror/cdimage/ports/9.0/m68k/iso-cd/debian-9.0-m68k-NETINST-1.iso
> 
> and extract the kernel and initrd.gz:
> 
> guestfish --add debian-9.0-m68k-NETINST-1.iso --ro \
>           --mount /dev/sda:/ <<_EOF_
> copy-out /install/cdrom/initrd.gz .
> copy-out /install/kernels/vmlinux-4.15.0-2-m68k .
> _EOF_

Running with -d in_asm,int I get:

----------------
IN: nf_get_id
0x0000d432:  movel %a3,%d0
0x0000d434:  addil #0,%d0
0x0000d43a:  movel %d0,%sp@-
0x0000d43c:  jsr 0xd404

----------------
IN:
0x0000d404:  071400

INT      1: Unassigned(0xf4) pc=0000d404 sp=00393e60 sr=2700
INT      2: Access Fault(0x8) pc=00000000 sp=00393e58 sr=2700
            ssw:  00000506 ea:   00000000 sfc:  5    dfc: 5

----------------
IN:
0x0000280c:  clrl %sp@-
0x0000280e:  pea 0xffffffffffffffff
0x00002812:  movel %d0,%sp@-
0x00002814:  moveml %d1-%d5/%a0-%a2,%sp@-
0x00002818:  movel %sp,%d0
0x0000281a:  andil #-8192,%d0
0x00002820:  moveal %d0,%a2
0x00002822:  moveal %a2@,%a2
0x00002824:  movel %sp,%sp@-
0x00002826:  bsrl 0x557c

----------------
IN: buserr_c
0x0000557c:  subql #4,%sp
0x0000557e:  moveml %d2-%d7/%a3-%fp,%sp@-
0x00005582:  moveal %sp@(48),%a3
0x00005586:  btst #5,%a3@(44)
0x0000558c:  bnes 0x5592

...

----------------
IN: panic
0x0002c956:  moveal 0x39503c,%a0
0x0002c95c:  moveq #101,%d1
0x0002c95e:  subql #1,%d1
0x0002c960:  bnes 0x2c9c6

objdump -S gives:

0000d404 <nf_get_id_phys>:
    d404:       7300            mvsb %d0,%d1
    d406:       4e75            rts

Instruction which exists in the disas code, but doesn't seem
tcg-implemented:

disas/m68k.c:3654:{"mvsb", 2,   one(0070400),   one(0170700), "*bDd",
mcfisa_b },

> 
> The mirror to use is: http://ftp.ports.debian.org/debian-ports/
> when it fails, continue without boot loader.
> 
> In the same way, you can extract the kernel and the initramfs from the qcow2
> image to use it with "-kernel" and "-initrd":
> 
> guestfish --add m68k.qcow2 --mount /dev/sda2:/ <<_EOF_
> copy-out /boot/vmlinux-4.15.0-2-m68k .
> copy-out /boot/initrd.img-4.15.0-2-m68k .
> _EOF_
> 
> and boot with:
> 
>    ...
>    -append "root=/dev/sda2 rw console=ttyS0 console=tty \
>    -kernel vmlinux-4.15.0-2-m68k \
>    -initrd initrd.img-4.15.0-2-m68k

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 01/13] hw/m68k: add via support
  2018-06-09 10:01   ` Mark Cave-Ayland
@ 2018-06-09 15:48     ` Mark Cave-Ayland
  2018-06-10  8:22       ` Laurent Vivier
  0 siblings, 1 reply; 33+ messages in thread
From: Mark Cave-Ayland @ 2018-06-09 15:48 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 09/06/18 11:01, Mark Cave-Ayland wrote:

> Yeah, we can certainly remove a huge chunk of this by converting over to 
> the mos6522 device. My last set of updates to CUDA a couple of days ago 
> are probably the best reference, but I can probably find some time to do 
> the basic conversion for you at some point...

BTW is there a particular github branch I should be working from in 
order to attempt this?


ATB,

Mark.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine
  2018-06-09 14:25 ` Philippe Mathieu-Daudé
@ 2018-06-09 18:14   ` Thomas Huth
  0 siblings, 0 replies; 33+ messages in thread
From: Thomas Huth @ 2018-06-09 18:14 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé,
	Laurent Vivier, Hervé Poussineau, Richard Henderson
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang, qemu-devel,
	Dr. David Alan Gilbert, Gerd Hoffmann, Paolo Bonzini, Max Reitz,
	Yongbok Kim, Andreas Färber, Aurelien Jarno

On 09.06.2018 16:25, Philippe Mathieu-Daudé wrote:
> Hi Laurent,
> 
> On 06/08/2018 05:05 PM, Laurent Vivier wrote:
>> if you want to test the machine, I'm sorry, it doesn't boot
>> a MacROM, but you can boot a linux kernel from the command line.
>>
>> You can install your own disk using debian-installer, with:
>>
>>     ...
>>     -M q800 \
>>     -serial none -serial mon:stdio \
>>     -m 1000M -drive file=m68k.qcow2,format=qcow2 \
>>     -net nic,model=dp83932,addr=09:00:07:12:34:57 \
>>     -append "console=ttyS0 vga=off" \
>>     -kernel vmlinux-4.15.0-2-m68k \
>>     -initrd initrd.gz \
>>     -drive file=debian-9.0-m68k-NETINST-1.iso \
>>     -drive file=m68k.qcow2,format=qcow2 \
>>     -nographic
>>
>> If you use a graphic adapter instead of "-nographic", you can use "-g" to set the
>> size of the display (I use "-g 1600x800x24").
>>
>> You can get the ISO from:
>>
>> https://cdimage.debian.org/mirror/cdimage/ports/9.0/m68k/iso-cd/debian-9.0-m68k-NETINST-1.iso
>>
>> and extract the kernel and initrd.gz:
>>
>> guestfish --add debian-9.0-m68k-NETINST-1.iso --ro \
>>           --mount /dev/sda:/ <<_EOF_
>> copy-out /install/cdrom/initrd.gz .
>> copy-out /install/kernels/vmlinux-4.15.0-2-m68k .
>> _EOF_
> 
> Running with -d in_asm,int I get:
> 
> ----------------
> IN: nf_get_id
> 0x0000d432:  movel %a3,%d0
> 0x0000d434:  addil #0,%d0
> 0x0000d43a:  movel %d0,%sp@-
> 0x0000d43c:  jsr 0xd404
> 
> ----------------
> IN:
> 0x0000d404:  071400
> 
> INT      1: Unassigned(0xf4) pc=0000d404 sp=00393e60 sr=2700
> INT      2: Access Fault(0x8) pc=00000000 sp=00393e58 sr=2700
>             ssw:  00000506 ea:   00000000 sfc:  5    dfc: 5
> 
> ----------------
> IN:
> 0x0000280c:  clrl %sp@-
> 0x0000280e:  pea 0xffffffffffffffff
> 0x00002812:  movel %d0,%sp@-
> 0x00002814:  moveml %d1-%d5/%a0-%a2,%sp@-
> 0x00002818:  movel %sp,%d0
> 0x0000281a:  andil #-8192,%d0
> 0x00002820:  moveal %d0,%a2
> 0x00002822:  moveal %a2@,%a2
> 0x00002824:  movel %sp,%sp@-
> 0x00002826:  bsrl 0x557c
> 
> ----------------
> IN: buserr_c
> 0x0000557c:  subql #4,%sp
> 0x0000557e:  moveml %d2-%d7/%a3-%fp,%sp@-
> 0x00005582:  moveal %sp@(48),%a3
> 0x00005586:  btst #5,%a3@(44)
> 0x0000558c:  bnes 0x5592
> 
> ...
> 
> ----------------
> IN: panic
> 0x0002c956:  moveal 0x39503c,%a0
> 0x0002c95c:  moveq #101,%d1
> 0x0002c95e:  subql #1,%d1
> 0x0002c960:  bnes 0x2c9c6
> 
> objdump -S gives:
> 
> 0000d404 <nf_get_id_phys>:
>     d404:       7300            mvsb %d0,%d1
>     d406:       4e75            rts
> 
> Instruction which exists in the disas code, but doesn't seem
> tcg-implemented:
> 
> disas/m68k.c:3654:{"mvsb", 2,   one(0070400),   one(0170700), "*bDd",
> mcfisa_b },

0x7300 is the illegal opcode that is used by the Aranym emulator for its
"Native Feature" (some kind of Hypercall) interface:

https://github.com/aranym/aranym/wiki/natfeats-proposal#special-opcodes

It's also a valid opcode in the ColdFire ISA (that's why the
disassembler detects this as valid instruction), but the name of the
function (nf_get_id_phys) clearly indicates that Linux is trying to use
the Natfeats opcode here.

So it's normal that this opcode is not implemented in QEMU 680x0 mode.
If Linux correctly catches the illegal opcode exception afterwards,
everything is fine and you don't need to worry about this anymore.
However, if Linux fails to catch it correctly, there is certainly
something wrong here...

 Thomas

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus
  2018-06-08 20:05 ` [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus Laurent Vivier
  2018-06-09  8:55   ` Hervé Poussineau
@ 2018-06-09 18:25   ` Thomas Huth
  1 sibling, 0 replies; 33+ messages in thread
From: Thomas Huth @ 2018-06-09 18:25 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 08.06.2018 22:05, Laurent Vivier wrote:
> This is needed by Quadra 800, this card can run on little-endian
> or big-endian bus.
> 
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>  hw/net/dp8393x.c | 101 ++++++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 70 insertions(+), 31 deletions(-)
> 
> diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
> index ef5f1eb94f..5061474e6b 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;
> @@ -174,6 +175,12 @@ typedef struct dp8393xState {
>      AddressSpace as;
>  } dp8393xState;
>  
> +#ifdef HOST_WORDS_BIGENDIAN
> +static const bool host_big_endian = true;
> +#else
> +static const bool host_big_endian = false;
> +#endif
> +
>  /* Accessor functions for values which are formed by
>   * concatenating two 16 bit device registers. By putting these
>   * in their own functions with a uint32_t return type we avoid the
> @@ -220,6 +227,36 @@ 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 = base[offset * width + width - 1];
> +    } else {
> +        val = base[offset * width];
> +    }
> +    if (s->big_endian != host_big_endian) {
> +        val = bswap16(val);
> +    }
> +    return val;
> +}

Could you maybe write that like this instead:

{
    uint16_t val;

    if (s->big_endian) {
        val = base[offset * width + width - 1];
        val = be16_to_cpu(val);
    } else {
        val = base[offset * width];
        val = le16_to_cpu(val);
    }
    return val;
}

?
... then you don't need that ugly host_big_endian variable anymore.

 Thomas

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack
  2018-06-08 20:05 ` [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack Laurent Vivier
  2018-06-09  8:55   ` Hervé Poussineau
@ 2018-06-09 18:36   ` Thomas Huth
  1 sibling, 0 replies; 33+ messages in thread
From: Thomas Huth @ 2018-06-09 18:36 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

On 08.06.2018 22:05, Laurent Vivier wrote:
> It's only 32 bytes, and this simplifies the dp8393x_get()/
> dp8393x_put() interface.

Maybe not worth the effort ... or do you need this in a later patch,
too? If so, please mention it in the patch description here.

> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>  hw/net/dp8393x.c | 107 ++++++++++++++++++++++++++-----------------------------
>  1 file changed, 51 insertions(+), 56 deletions(-)
> 
> diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
> index 5061474e6b..40e5f8257b 100644
> --- a/hw/net/dp8393x.c
> +++ b/hw/net/dp8393x.c
> @@ -168,6 +168,7 @@ typedef struct dp8393xState {
>  
>      /* Temporaries */
>      uint8_t tx_buffer[0x10000];
> +    uint16_t data[16];

Why 16? The biggest array that you replaced has only 12 entries...

Also, while you're at it, maybe change the name of the variable
("dma_data"?) or add a comment with a short explanation ?

 Thomas

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC 01/13] hw/m68k: add via support
  2018-06-09 15:48     ` Mark Cave-Ayland
@ 2018-06-10  8:22       ` Laurent Vivier
  0 siblings, 0 replies; 33+ messages in thread
From: Laurent Vivier @ 2018-06-10  8:22 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel
  Cc: Kevin Wolf, Fam Zheng, qemu-block, Jason Wang,
	Dr. David Alan Gilbert, Max Reitz, Hervé Poussineau,
	Gerd Hoffmann, Paolo Bonzini, Yongbok Kim, Andreas Färber,
	Aurelien Jarno

Le 09/06/2018 à 17:48, Mark Cave-Ayland a écrit :
> On 09/06/18 11:01, Mark Cave-Ayland wrote:
> 
>> Yeah, we can certainly remove a huge chunk of this by converting over
>> to the mos6522 device. My last set of updates to CUDA a couple of days
>> ago are probably the best reference, but I can probably find some time
>> to do the basic conversion for you at some point...
> 
> BTW is there a particular github branch I should be working from in
> order to attempt this?
> 

You can use q800-dev-part1 from git://github.com/vivier/qemu-m68k.git

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2018-06-10  8:22 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-08 20:05 [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine Laurent Vivier
2018-06-08 20:05 ` [Qemu-devel] [RFC 01/13] hw/m68k: add via support Laurent Vivier
2018-06-09 10:01   ` Mark Cave-Ayland
2018-06-09 15:48     ` Mark Cave-Ayland
2018-06-10  8:22       ` Laurent Vivier
2018-06-08 20:05 ` [Qemu-devel] [RFC 02/13] ADB: VIA probes ADB bus when it is idle Laurent Vivier
2018-06-08 20:05 ` [Qemu-devel] [RFC 03/13] escc: introduce a selector for the register bit Laurent Vivier
2018-06-09 10:05   ` Mark Cave-Ayland
2018-06-08 20:05 ` [Qemu-devel] [RFC 04/13] hw/m68k: add video card Laurent Vivier
2018-06-09 10:14   ` Mark Cave-Ayland
2018-06-08 20:05 ` [Qemu-devel] [RFC 05/13] hw/m68k: Apple Sound Chip (ASC) emulation Laurent Vivier
2018-06-08 20:05 ` [Qemu-devel] [RFC 06/13] ESP: add pseudo-DMA as used by Macintosh Laurent Vivier
2018-06-09  8:57   ` Hervé Poussineau
2018-06-09 10:19   ` Mark Cave-Ayland
2018-06-08 20:05 ` [Qemu-devel] [RFC 07/13] hw/m68k: add Nubus support Laurent Vivier
2018-06-08 20:05 ` [Qemu-devel] [RFC 08/13] hw/m68k: add a dummy SWIM floppy controller Laurent Vivier
2018-06-08 20:05 ` [Qemu-devel] [RFC 09/13] hw/m68k: define Macintosh Quadra 800 Laurent Vivier
2018-06-09 10:24   ` Mark Cave-Ayland
2018-06-08 20:05 ` [Qemu-devel] [RFC 10/13] dp8393x: fix dp8393x_receive Laurent Vivier
2018-06-09  8:47   ` Hervé Poussineau
2018-06-08 20:05 ` [Qemu-devel] [RFC 11/13] dp8393x: manage big endian bus Laurent Vivier
2018-06-09  8:55   ` Hervé Poussineau
2018-06-09 18:25   ` Thomas Huth
2018-06-08 20:05 ` [Qemu-devel] [RFC 12/13] dp8393x: put DMA temp buffer in the state, not in the stack Laurent Vivier
2018-06-09  8:55   ` Hervé Poussineau
2018-06-09 18:36   ` Thomas Huth
2018-06-08 20:05 ` [Qemu-devel] [RFC 13/13] dp8393x: fix receiving buffer exhaustion Laurent Vivier
2018-06-09  8:55   ` Hervé Poussineau
2018-06-08 20:34 ` [Qemu-devel] [RFC 00/13] hw/m68k: add Apple Machintosh Quadra 800 machine no-reply
2018-06-09  3:26 ` Philippe Mathieu-Daudé
2018-06-09  8:34   ` Laurent Vivier
2018-06-09 14:25 ` Philippe Mathieu-Daudé
2018-06-09 18:14   ` Thomas Huth

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.