qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support
@ 2011-03-07 22:32 Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 01/14] lm32: add Milkymist AC97 support Michael Walle
                   ` (14 more replies)
  0 siblings, 15 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Alexander Graf

This is the second (and last) patchset of the LatticeMico32 support. It
adds almost complete support for the opensource and openhardware Milkymist
One board [1].

[1] http://www.milkymist.org/mmone.html

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

* [Qemu-devel] [PATCH 01/14] lm32: add Milkymist AC97 support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-16 16:50   ` [Qemu-devel] " Alexander Graf
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 02/14] lm32: add Milkymist HPDMC support Michael Walle
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for the Milkymist AC97 compatible sound output and
input core.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target     |    1 +
 configure           |    3 +
 hw/milkymist-ac97.c |  335 +++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events        |   12 ++
 4 files changed, 351 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-ac97.c

diff --git a/Makefile.target b/Makefile.target
index f0df98e..3be7868 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -256,6 +256,7 @@ obj-lm32-y += lm32_juart.o
 obj-lm32-y += lm32_timer.o
 obj-lm32-y += lm32_uart.o
 obj-lm32-y += lm32_sys.o
+obj-lm32-y += milkymist-ac97.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/configure b/configure
index 5513d3e..e75e1a2 100755
--- a/configure
+++ b/configure
@@ -3281,6 +3281,9 @@ if test "$target_softmmu" = "yes" ; then
   arm)
     cflags="-DHAS_AUDIO $cflags"
   ;;
+  lm32)
+    cflags="-DHAS_AUDIO $cflags"
+  ;;
   i386|mips|ppc)
     cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
   ;;
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
new file mode 100644
index 0000000..6c9e318
--- /dev/null
+++ b/hw/milkymist-ac97.c
@@ -0,0 +1,335 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/ac97.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "audio/audio.h"
+#include "qemu-error.h"
+
+enum {
+    R_AC97_CTRL = 0,
+    R_AC97_ADDR,
+    R_AC97_DATAOUT,
+    R_AC97_DATAIN,
+    R_D_CTRL,
+    R_D_ADDR,
+    R_D_REMAINING,
+    R_RESERVED,
+    R_U_CTRL,
+    R_U_ADDR,
+    R_U_REMAINING,
+    R_MAX
+};
+
+enum {
+    AC97_CTRL_RQEN  = (1<<0),
+    AC97_CTRL_WRITE = (1<<1),
+};
+
+enum {
+    CTRL_EN = (1<<0),
+};
+
+struct MilkymistAC97State {
+    SysBusDevice busdev;
+
+    QEMUSoundCard card;
+    SWVoiceIn *voice_in;
+    SWVoiceOut *voice_out;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq crrequest_irq;
+    qemu_irq crreply_irq;
+    qemu_irq dmar_irq;
+    qemu_irq dmaw_irq;
+};
+typedef struct MilkymistAC97State MilkymistAC97State;
+
+static void update_voices(MilkymistAC97State *s)
+{
+    if (s->regs[R_D_CTRL] & CTRL_EN) {
+        AUD_set_active_out(s->voice_out, 1);
+    } else {
+        AUD_set_active_out(s->voice_out, 0);
+    }
+
+    if (s->regs[R_U_CTRL] & CTRL_EN) {
+        AUD_set_active_in(s->voice_in, 1);
+    } else {
+        AUD_set_active_in(s->voice_in, 0);
+    }
+}
+
+static uint32_t ac97_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistAC97State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_CTRL:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_CTRL:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_ac97: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_ac97_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistAC97State *s = opaque;
+
+    trace_milkymist_ac97_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+        /* always raise an IRQ according to the direction */
+        if (value & AC97_CTRL_RQEN) {
+            if (value & AC97_CTRL_WRITE) {
+                trace_milkymist_ac97_pulse_irq_crrequest();
+                qemu_irq_pulse(s->crrequest_irq);
+            } else {
+                trace_milkymist_ac97_pulse_irq_crreply();
+                qemu_irq_pulse(s->crreply_irq);
+            }
+        }
+
+        /* RQEN is self clearing */
+        s->regs[addr] = value & ~AC97_CTRL_RQEN;
+        break;
+    case R_D_CTRL:
+    case R_U_CTRL:
+        s->regs[addr] = value;
+        update_voices(s);
+        break;
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_ac97: write access to unkown register 0x"
+                TARGET_FMT_plx, addr);
+        break;
+    }
+
+}
+
+static CPUReadMemoryFunc * const ac97_read_fn[] = {
+    NULL,
+    NULL,
+    &ac97_read,
+};
+
+static CPUWriteMemoryFunc * const ac97_write_fn[] = {
+    NULL,
+    NULL,
+    &ac97_write,
+};
+
+static void ac97_in_cb(void *opaque, int avail_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_U_REMAINING];
+    int temp = audio_MIN(remaining, avail_b);
+    uint32_t addr = s->regs[R_U_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_in_cb(avail_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int acquired, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        acquired = AUD_read(s->voice_in, buf, to_copy);
+        if (!acquired) {
+            break;
+        }
+
+        cpu_physical_memory_write(addr, buf, acquired);
+
+        temp -= acquired;
+        addr += acquired;
+        transferred += acquired;
+    }
+
+    trace_milkymist_ac97_in_cb_transferred(transferred);
+
+    s->regs[R_U_ADDR] = addr;
+    s->regs[R_U_REMAINING] -= transferred;
+
+    if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmaw();
+        qemu_irq_pulse(s->dmaw_irq);
+    }
+}
+
+static void ac97_out_cb(void *opaque, int free_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_D_REMAINING];
+    int temp = audio_MIN(remaining, free_b);
+    uint32_t addr = s->regs[R_D_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_out_cb(free_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int copied, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        cpu_physical_memory_read(addr, buf, to_copy);
+        copied = AUD_write(s->voice_out, buf, to_copy);
+        if (!copied) {
+            break;
+        }
+        temp -= copied;
+        addr += copied;
+        transferred += copied;
+    }
+
+    trace_milkymist_ac97_out_cb_transferred(transferred);
+
+    s->regs[R_D_ADDR] = addr;
+    s->regs[R_D_REMAINING] -= transferred;
+
+    if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmar();
+        qemu_irq_pulse(s->dmar_irq);
+    }
+}
+
+static void milkymist_ac97_reset(DeviceState *d)
+{
+    MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    AUD_set_active_in(s->voice_in, 0);
+    AUD_set_active_out(s->voice_out, 0);
+}
+
+static int ac97_post_load(void *opaque, int version_id)
+{
+    MilkymistAC97State *s = opaque;
+
+    update_voices(s);
+
+    return 0;
+}
+
+static int milkymist_ac97_init(SysBusDevice *dev)
+{
+    MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
+    int ac97_regs;
+
+    struct audsettings as;
+    sysbus_init_irq(dev, &s->crrequest_irq);
+    sysbus_init_irq(dev, &s->crreply_irq);
+    sysbus_init_irq(dev, &s->dmar_irq);
+    sysbus_init_irq(dev, &s->dmaw_irq);
+
+    AUD_register_card("Milkymist AC'97", &s->card);
+
+    as.freq = 48000;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 1;
+
+    s->voice_in = AUD_open_in(&s->card, s->voice_in,
+            "mm_ac97.in", s, ac97_in_cb, &as);
+    s->voice_out = AUD_open_out(&s->card, s->voice_out,
+            "mm_ac97.out", s, ac97_out_cb, &as);
+
+    ac97_regs = cpu_register_io_memory(ac97_read_fn, ac97_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, ac97_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_ac97 = {
+    .name = "milkymist-ac97",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ac97_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_ac97_info = {
+    .init = milkymist_ac97_init,
+    .qdev.name  = "milkymist-ac97",
+    .qdev.size  = sizeof(MilkymistAC97State),
+    .qdev.vmsd  = &vmstate_milkymist_ac97,
+    .qdev.reset = milkymist_ac97_reset,
+};
+
+static void milkymist_ac97_register(void)
+{
+    sysbus_register_withprop(&milkymist_ac97_info);
+}
+
+device_init(milkymist_ac97_register)
diff --git a/trace-events b/trace-events
index c791719..9241ac9 100644
--- a/trace-events
+++ b/trace-events
@@ -283,3 +283,15 @@ disable lm32_uart_irq_state(int level) "irq state %d"
 
 # hw/lm32_sys.c
 disable lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+
+# hw/milkymist-ac97.c
+disable milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
+disable milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
+disable milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
+disable milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
+disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u"
+disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
+disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
+disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 02/14] lm32: add Milkymist HPDMC support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 01/14] lm32: add Milkymist AC97 support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 03/14] lm32: add Milkymist memory card support Michael Walle
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for the Milkymist's High Performance Dynamic Memory
Controller. This is just a dumb model without any functionality. While the
real hardware acts for example as a bridge between software and hardware
for sending SDRAM commans, this model will only eat up these commands and
always returns the expected hardware states, eg. PLL locked etc.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target      |    1 +
 hw/milkymist-hpdmc.c |  161 ++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events         |    4 +
 3 files changed, 166 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-hpdmc.c

diff --git a/Makefile.target b/Makefile.target
index 3be7868..57902eb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -257,6 +257,7 @@ obj-lm32-y += lm32_timer.o
 obj-lm32-y += lm32_uart.o
 obj-lm32-y += lm32_sys.o
 obj-lm32-y += milkymist-ac97.o
+obj-lm32-y += milkymist-hpdmc.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
new file mode 100644
index 0000000..c0962fb
--- /dev/null
+++ b/hw/milkymist-hpdmc.c
@@ -0,0 +1,161 @@
+/*
+ *  QEMU model of the Milkymist High Performance Dynamic Memory Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/hpdmc.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-error.h"
+
+enum {
+    R_SYSTEM = 0,
+    R_BYPASS,
+    R_TIMING,
+    R_IODELAY,
+    R_MAX
+};
+
+enum {
+    IODELAY_DQSDELAY_RDY = (1<<5),
+    IODELAY_PLL1_LOCKED  = (1<<6),
+    IODELAY_PLL2_LOCKED  = (1<<7),
+};
+
+struct MilkymistHpdmcState {
+    SysBusDevice busdev;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistHpdmcState MilkymistHpdmcState;
+
+static uint32_t hpdmc_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistHpdmcState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+    case R_IODELAY:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_hpdmc_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistHpdmcState *s = opaque;
+
+    trace_milkymist_hpdmc_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+        s->regs[addr] = value;
+        break;
+    case R_IODELAY:
+        /* ignore writes */
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const hpdmc_read_fn[] = {
+    NULL,
+    NULL,
+    &hpdmc_read,
+};
+
+static CPUWriteMemoryFunc * const hpdmc_write_fn[] = {
+    NULL,
+    NULL,
+    &hpdmc_write,
+};
+
+static void milkymist_hpdmc_reset(DeviceState *d)
+{
+    MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
+                         | IODELAY_PLL2_LOCKED;
+}
+
+static int milkymist_hpdmc_init(SysBusDevice *dev)
+{
+    MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev);
+    int hpdmc_regs;
+
+    hpdmc_regs = cpu_register_io_memory(hpdmc_read_fn, hpdmc_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, hpdmc_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_hpdmc = {
+    .name = "milkymist-hpdmc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_hpdmc_info = {
+    .init = milkymist_hpdmc_init,
+    .qdev.name  = "milkymist-hpdmc",
+    .qdev.size  = sizeof(MilkymistHpdmcState),
+    .qdev.vmsd  = &vmstate_milkymist_hpdmc,
+    .qdev.reset = milkymist_hpdmc_reset,
+};
+
+static void milkymist_hpdmc_register(void)
+{
+    sysbus_register_withprop(&milkymist_hpdmc_info);
+}
+
+device_init(milkymist_hpdmc_register)
diff --git a/trace-events b/trace-events
index 9241ac9..afed656 100644
--- a/trace-events
+++ b/trace-events
@@ -295,3 +295,7 @@ disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining
 disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
 disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
 disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
+
+# hw/milkymist-hpdmc.c
+disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 03/14] lm32: add Milkymist memory card support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 01/14] lm32: add Milkymist AC97 support Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 02/14] lm32: add Milkymist HPDMC support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 04/14] lm32: add Milkymist Minimac support Michael Walle
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's memory card core.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target                  |    1 +
 default-configs/lm32-softmmu.mak |    1 +
 hw/milkymist-memcard.c           |  294 ++++++++++++++++++++++++++++++++++++++
 trace-events                     |    8 +-
 4 files changed, 302 insertions(+), 2 deletions(-)
 create mode 100644 hw/milkymist-memcard.c

diff --git a/Makefile.target b/Makefile.target
index 57902eb..86b0006 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -258,6 +258,7 @@ obj-lm32-y += lm32_uart.o
 obj-lm32-y += lm32_sys.o
 obj-lm32-y += milkymist-ac97.o
 obj-lm32-y += milkymist-hpdmc.o
+obj-lm32-y += milkymist-memcard.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/default-configs/lm32-softmmu.mak b/default-configs/lm32-softmmu.mak
index ab774a2..3e7f57e 100644
--- a/default-configs/lm32-softmmu.mak
+++ b/default-configs/lm32-softmmu.mak
@@ -2,3 +2,4 @@
 
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI02=y
+CONFIG_SD=y
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
new file mode 100644
index 0000000..06077af
--- /dev/null
+++ b/hw/milkymist-memcard.c
@@ -0,0 +1,294 @@
+/*
+ *  QEMU model of the Milkymist SD Card Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/memcard.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu-error.h"
+#include "blockdev.h"
+#include "sd.h"
+
+enum {
+    ENABLE_CMD_TX   = (1<<0),
+    ENABLE_CMD_RX   = (1<<1),
+    ENABLE_DAT_TX   = (1<<2),
+    ENABLE_DAT_RX   = (1<<3),
+};
+
+enum {
+    PENDING_CMD_TX   = (1<<0),
+    PENDING_CMD_RX   = (1<<1),
+    PENDING_DAT_TX   = (1<<2),
+    PENDING_DAT_RX   = (1<<3),
+};
+
+enum {
+    START_CMD_TX    = (1<<0),
+    START_DAT_RX    = (1<<1),
+};
+
+enum {
+    R_CLK2XDIV = 0,
+    R_ENABLE,
+    R_PENDING,
+    R_START,
+    R_CMD,
+    R_DAT,
+    R_MAX
+};
+
+struct MilkymistMemcardState {
+    SysBusDevice busdev;
+    SDState *card;
+
+    int command_write_ptr;
+    int response_read_ptr;
+    int response_len;
+    int ignore_next_cmd;
+    int enabled;
+    uint8_t command[6];
+    uint8_t response[17];
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistMemcardState MilkymistMemcardState;
+
+static void update_pending_bits(MilkymistMemcardState *s)
+{
+    /* transmits are instantaneous, thus tx pending bits are never set */
+    s->regs[R_PENDING] = 0;
+    /* if rx is enabled the corresponding pending bits are always set */
+    if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
+        s->regs[R_PENDING] |= PENDING_CMD_RX;
+    }
+    if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
+        s->regs[R_PENDING] |= PENDING_DAT_RX;
+    }
+}
+
+static void memcard_sd_command(MilkymistMemcardState *s)
+{
+    SDRequest req;
+
+    req.cmd = s->command[0] & 0x3f;
+    req.arg = (s->command[1] << 24) | (s->command[2] << 16)
+              | (s->command[3] << 8) | s->command[4];
+    req.crc = s->command[5];
+
+    s->response[0] = req.cmd;
+    s->response_len = sd_do_command(s->card, &req, s->response+1);
+    s->response_read_ptr = 0;
+
+    if (s->response_len == 16) {
+        /* R2 response */
+        s->response[0] = 0x3f;
+        s->response_len += 1;
+    } else if (s->response_len == 4) {
+        /* no crc calculation, insert dummy byte */
+        s->response[5] = 0;
+        s->response_len += 2;
+    }
+
+    if (req.cmd == 0) {
+        /* next write is a dummy byte to clock the initialization of the sd
+         * card */
+        s->ignore_next_cmd = 1;
+    }
+}
+
+static uint32_t memcard_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistMemcardState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CMD:
+        if (!s->enabled) {
+            r = 0xff;
+        } else {
+            r = s->response[s->response_read_ptr++];
+            if (s->response_read_ptr > s->response_len) {
+                error_report("milkymist_memcard: "
+                        "read more cmd bytes than available. Clipping.");
+                s->response_read_ptr = 0;
+            }
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            r = 0xffffffff;
+        } else {
+            r = 0;
+            r |= sd_read_data(s->card) << 24;
+            r |= sd_read_data(s->card) << 16;
+            r |= sd_read_data(s->card) << 8;
+            r |= sd_read_data(s->card);
+        }
+        break;
+    case R_CLK2XDIV:
+    case R_ENABLE:
+    case R_PENDING:
+    case R_START:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_memcard: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_memcard_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void memcard_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistMemcardState *s = opaque;
+
+    trace_milkymist_memcard_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_PENDING:
+        /* clear rx pending bits */
+        s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
+        update_pending_bits(s);
+        break;
+    case R_CMD:
+        if (!s->enabled) {
+            break;
+        }
+        if (s->ignore_next_cmd) {
+            s->ignore_next_cmd = 0;
+            break;
+        }
+        s->command[s->command_write_ptr] = value & 0xff;
+        s->command_write_ptr = (s->command_write_ptr + 1) % 6;
+        if (s->command_write_ptr == 0) {
+            memcard_sd_command(s);
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            break;
+        }
+        sd_write_data(s->card, (value >> 24) & 0xff);
+        sd_write_data(s->card, (value >> 16) & 0xff);
+        sd_write_data(s->card, (value >> 8) & 0xff);
+        sd_write_data(s->card, value & 0xff);
+        break;
+    case R_ENABLE:
+        s->regs[addr] = value;
+        update_pending_bits(s);
+        break;
+    case R_CLK2XDIV:
+    case R_START:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_memcard: write access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const memcard_read_fn[] = {
+    NULL,
+    NULL,
+    &memcard_read,
+};
+
+static CPUWriteMemoryFunc * const memcard_write_fn[] = {
+    NULL,
+    NULL,
+    &memcard_write,
+};
+
+static void milkymist_memcard_reset(DeviceState *d)
+{
+    MilkymistMemcardState *s =
+            container_of(d, MilkymistMemcardState, busdev.qdev);
+    int i;
+
+    s->command_write_ptr = 0;
+    s->response_read_ptr = 0;
+    s->response_len = 0;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_memcard_init(SysBusDevice *dev)
+{
+    MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
+    DriveInfo *dinfo;
+    int memcard_regs;
+
+    dinfo = drive_get_next(IF_SD);
+    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
+
+    memcard_regs = cpu_register_io_memory(memcard_read_fn, memcard_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, memcard_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_memcard = {
+    .name = "milkymist-memcard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_len, MilkymistMemcardState),
+        VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
+        VMSTATE_INT32(enabled, MilkymistMemcardState),
+        VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
+        VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_memcard_info = {
+    .init = milkymist_memcard_init,
+    .qdev.name  = "milkymist-memcard",
+    .qdev.size  = sizeof(MilkymistMemcardState),
+    .qdev.vmsd  = &vmstate_milkymist_memcard,
+    .qdev.reset = milkymist_memcard_reset,
+};
+
+static void milkymist_memcard_register(void)
+{
+    sysbus_register_withprop(&milkymist_memcard_info);
+}
+
+device_init(milkymist_memcard_register)
diff --git a/trace-events b/trace-events
index afed656..a1de942 100644
--- a/trace-events
+++ b/trace-events
@@ -297,5 +297,9 @@ disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %
 disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
 
 # hw/milkymist-hpdmc.c
-disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
-disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+
+# hw/milkymist-memcard.c
+disable milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 04/14] lm32: add Milkymist Minimac support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (2 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 03/14] lm32: add Milkymist memory card support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 05/14] lm32: add Milkymist PFPU support Michael Walle
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's minimal Ethernet MAC.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target        |    1 +
 hw/milkymist-minimac.c |  568 ++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events           |   12 +
 3 files changed, 581 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-minimac.c

diff --git a/Makefile.target b/Makefile.target
index 86b0006..8021476 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -259,6 +259,7 @@ obj-lm32-y += lm32_sys.o
 obj-lm32-y += milkymist-ac97.o
 obj-lm32-y += milkymist-hpdmc.o
 obj-lm32-y += milkymist-memcard.o
+obj-lm32-y += milkymist-minimac.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-minimac.c b/hw/milkymist-minimac.c
new file mode 100644
index 0000000..b07f18d
--- /dev/null
+++ b/hw/milkymist-minimac.c
@@ -0,0 +1,568 @@
+/*
+ *  QEMU model of the Milkymist minimac block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/minimac.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "net.h"
+#include "qemu-error.h"
+
+#include <zlib.h>
+
+enum {
+    R_SETUP = 0,
+    R_MDIO,
+    R_STATE0,
+    R_ADDR0,
+    R_COUNT0,
+    R_STATE1,
+    R_ADDR1,
+    R_COUNT1,
+    R_STATE2,
+    R_ADDR2,
+    R_COUNT2,
+    R_STATE3,
+    R_ADDR3,
+    R_COUNT3,
+    R_TXADDR,
+    R_TXCOUNT,
+    R_MAX
+};
+
+enum {
+    SETUP_RX_RST = (1<<0),
+    SETUP_TX_RST = (1<<2),
+};
+
+enum {
+    MDIO_DO  = (1<<0),
+    MDIO_DI  = (1<<1),
+    MDIO_OE  = (1<<2),
+    MDIO_CLK = (1<<3),
+};
+
+enum {
+    STATE_EMPTY   = 0,
+    STATE_LOADED  = 1,
+    STATE_PENDING = 2,
+};
+
+enum {
+    MDIO_OP_WRITE = 1,
+    MDIO_OP_READ  = 2,
+};
+
+enum mdio_state {
+    MDIO_STATE_IDLE,
+    MDIO_STATE_READING,
+    MDIO_STATE_WRITING,
+};
+
+enum {
+    R_PHY_ID1  = 2,
+    R_PHY_ID2  = 3,
+    R_PHY_MAX  = 32
+};
+
+#define MINIMAC_MTU 1530
+
+struct MilkymistMinimacMdioState {
+    int last_clk;
+    int count;
+    uint32_t data;
+    uint16_t data_out;
+    int state;
+
+    uint8_t phy_addr;
+    uint8_t reg_addr;
+};
+typedef struct MilkymistMinimacMdioState MilkymistMinimacMdioState;
+
+struct MilkymistMinimacState {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    char *phy_model;
+
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+
+    MilkymistMinimacMdioState mdio;
+
+    uint16_t phy_regs[R_PHY_MAX];
+};
+typedef struct MilkymistMinimacState MilkymistMinimacState;
+
+static const uint8_t preamble_sfd[] = {
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
+};
+
+static void minimac_mdio_write_reg(MilkymistMinimacState *s,
+        uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
+{
+    trace_milkymist_minimac_mdio_write(phy_addr, reg_addr, value);
+
+    /* nop */
+}
+
+static uint16_t minimac_mdio_read_reg(MilkymistMinimacState *s,
+        uint8_t phy_addr, uint8_t reg_addr)
+{
+    uint16_t r = s->phy_regs[reg_addr];
+
+    trace_milkymist_minimac_mdio_read(phy_addr, reg_addr, r);
+
+    return r;
+}
+
+static void minimac_update_mdio(MilkymistMinimacState *s)
+{
+    MilkymistMinimacMdioState *m = &s->mdio;
+
+    /* detect rising clk edge */
+    if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
+        /* shift data in */
+        int bit = ((s->regs[R_MDIO] & MDIO_DO)
+                   && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
+        m->data = (m->data << 1) | bit;
+
+        /* check for sync */
+        if (m->data == 0xffffffff) {
+            m->count = 32;
+        }
+
+        if (m->count == 16) {
+            uint8_t start = (m->data >> 14) & 0x3;
+            uint8_t op = (m->data >> 12) & 0x3;
+            uint8_t ta = (m->data) & 0x3;
+
+            if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
+                m->state = MDIO_STATE_WRITING;
+            } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
+                m->state = MDIO_STATE_READING;
+            } else {
+                m->state = MDIO_STATE_IDLE;
+            }
+
+            if (m->state != MDIO_STATE_IDLE) {
+                m->phy_addr = (m->data >> 7) & 0x1f;
+                m->reg_addr = (m->data >> 2) & 0x1f;
+            }
+
+            if (m->state == MDIO_STATE_READING) {
+                m->data_out = minimac_mdio_read_reg(s, m->phy_addr,
+                        m->reg_addr);
+            }
+        }
+
+        if (m->count < 16 && m->state == MDIO_STATE_READING) {
+            int bit = (m->data_out & 0x8000) ? 1 : 0;
+            m->data_out <<= 1;
+
+            if (bit) {
+                s->regs[R_MDIO] |= MDIO_DI;
+            } else {
+                s->regs[R_MDIO] &= ~MDIO_DI;
+            }
+        }
+
+        if (m->count == 0 && m->state) {
+            if (m->state == MDIO_STATE_WRITING) {
+                uint16_t data = m->data & 0xffff;
+                minimac_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
+            }
+            m->state = MDIO_STATE_IDLE;
+        }
+        m->count--;
+    }
+
+    m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
+}
+
+static size_t assemble_frame(uint8_t *buf, size_t size,
+        const uint8_t *payload, size_t payload_size)
+{
+    uint32_t crc;
+
+    if (size < payload_size + 12) {
+        error_report("milkymist_minimac: received too big ethernet frame");
+        return 0;
+    }
+
+    /* prepend preamble and sfd */
+    memcpy(buf, preamble_sfd, 8);
+
+    /* now copy the payload */
+    memcpy(buf + 8, payload, payload_size);
+
+    /* pad frame if needed */
+    if (payload_size < 60) {
+        memset(buf + payload_size + 8, 0, 60 - payload_size);
+        payload_size = 60;
+    }
+
+    /* append fcs */
+    crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
+    memcpy(buf + payload_size + 8, &crc, 4);
+
+    return payload_size + 12;
+}
+
+static void minimac_tx(MilkymistMinimacState *s)
+{
+    uint8_t buf[MINIMAC_MTU];
+    uint32_t txcount = s->regs[R_TXCOUNT];
+
+    /* do nothing if transmission logic is in reset */
+    if (s->regs[R_SETUP] & SETUP_TX_RST) {
+        return;
+    }
+
+    if (txcount < 64) {
+        error_report("milkymist_minimac: ethernet frame too small (%u < %u)\n",
+                txcount, 64);
+        return;
+    }
+
+    if (txcount > MINIMAC_MTU) {
+        error_report("milkymist_minimac: MTU exceeded (%u > %u)\n",
+                txcount, MINIMAC_MTU);
+        return;
+    }
+
+    /* dma */
+    cpu_physical_memory_read(s->regs[R_TXADDR], buf, txcount);
+
+    if (memcmp(buf, preamble_sfd, 8) != 0) {
+        error_report("milkymist_minimac: frame doesn't contain the preamble "
+                "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)\n",
+                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+        return;
+    }
+
+    trace_milkymist_minimac_tx_frame(txcount - 12);
+
+    /* send packet, skipping preamble and sfd */
+    qemu_send_packet_raw(&s->nic->nc, buf + 8, txcount - 12);
+
+    s->regs[R_TXCOUNT] = 0;
+
+    trace_milkymist_minimac_pulse_irq_tx();
+    qemu_irq_pulse(s->tx_irq);
+}
+
+static ssize_t minimac_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    uint32_t r_addr;
+    uint32_t r_count;
+    uint32_t r_state;
+
+    uint8_t frame_buf[MINIMAC_MTU];
+    size_t frame_size;
+
+    trace_milkymist_minimac_rx_frame(buf, size);
+
+    /* discard frames if nic is in reset */
+    if (s->regs[R_SETUP] & SETUP_RX_RST) {
+        return size;
+    }
+
+    /* choose appropriate slot */
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        r_addr = R_ADDR0;
+        r_count = R_COUNT0;
+        r_state = R_STATE0;
+    } else if (s->regs[R_STATE1] == STATE_LOADED) {
+        r_addr = R_ADDR1;
+        r_count = R_COUNT1;
+        r_state = R_STATE1;
+    } else if (s->regs[R_STATE2] == STATE_LOADED) {
+        r_addr = R_ADDR2;
+        r_count = R_COUNT2;
+        r_state = R_STATE2;
+    } else if (s->regs[R_STATE3] == STATE_LOADED) {
+        r_addr = R_ADDR3;
+        r_count = R_COUNT3;
+        r_state = R_STATE3;
+    } else {
+        trace_milkymist_minimac_drop_rx_frame(buf);
+        return size;
+    }
+
+    /* assemble frame */
+    frame_size = assemble_frame(frame_buf, sizeof(frame_buf), buf, size);
+
+    if (frame_size == 0) {
+        return size;
+    }
+
+    trace_milkymist_minimac_rx_transfer(buf, frame_size);
+
+    /* do dma */
+    cpu_physical_memory_write(s->regs[r_addr], frame_buf, frame_size);
+
+    /* update slot */
+    s->regs[r_count] = frame_size;
+    s->regs[r_state] = STATE_PENDING;
+
+    trace_milkymist_minimac_pulse_irq_rx();
+    qemu_irq_pulse(s->rx_irq);
+
+    return size;
+}
+
+static uint32_t
+minimac_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistMinimacState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SETUP:
+    case R_MDIO:
+    case R_STATE0:
+    case R_ADDR0:
+    case R_COUNT0:
+    case R_STATE1:
+    case R_ADDR1:
+    case R_COUNT1:
+    case R_STATE2:
+    case R_ADDR2:
+    case R_COUNT2:
+    case R_STATE3:
+    case R_ADDR3:
+    case R_COUNT3:
+    case R_TXADDR:
+    case R_TXCOUNT:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_minimac: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_minimac_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+minimac_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistMinimacState *s = opaque;
+
+    trace_milkymist_minimac_memory_read(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_MDIO:
+    {
+        /* MDIO_DI is read only */
+        int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
+        s->regs[R_MDIO] = value;
+        if (mdio_di) {
+            s->regs[R_MDIO] |= mdio_di;
+        } else {
+            s->regs[R_MDIO] &= ~mdio_di;
+        }
+
+        minimac_update_mdio(s);
+    } break;
+    case R_TXCOUNT:
+        s->regs[addr] = value;
+        if (value > 0) {
+            minimac_tx(s);
+        }
+        break;
+    case R_SETUP:
+    case R_STATE0:
+    case R_ADDR0:
+    case R_COUNT0:
+    case R_STATE1:
+    case R_ADDR1:
+    case R_COUNT1:
+    case R_STATE2:
+    case R_ADDR2:
+    case R_COUNT2:
+    case R_STATE3:
+    case R_ADDR3:
+    case R_COUNT3:
+    case R_TXADDR:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_minimac: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const minimac_read_fn[] = {
+    NULL,
+    NULL,
+    &minimac_read,
+};
+
+static CPUWriteMemoryFunc * const minimac_write_fn[] = {
+    NULL,
+    NULL,
+    &minimac_write,
+};
+
+static int minimac_can_rx(VLANClientState *nc)
+{
+    MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    /* discard frames if nic is in reset */
+    if (s->regs[R_SETUP] & SETUP_RX_RST) {
+        return 1;
+    }
+
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        return 1;
+    }
+    if (s->regs[R_STATE1] == STATE_LOADED) {
+        return 1;
+    }
+    if (s->regs[R_STATE2] == STATE_LOADED) {
+        return 1;
+    }
+    if (s->regs[R_STATE3] == STATE_LOADED) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void minimac_cleanup(VLANClientState *nc)
+{
+    MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static void milkymist_minimac_reset(DeviceState *d)
+{
+    MilkymistMinimacState *s =
+            container_of(d, MilkymistMinimacState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < R_PHY_MAX; i++) {
+        s->phy_regs[i] = 0;
+    }
+
+    /* defaults */
+    s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
+    s->phy_regs[R_PHY_ID2] = 0x161a;
+}
+
+static NetClientInfo net_milkymist_minimac_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = minimac_can_rx,
+    .receive = minimac_rx,
+    .cleanup = minimac_cleanup,
+};
+
+static int milkymist_minimac_init(SysBusDevice *dev)
+{
+    MilkymistMinimacState *s = FROM_SYSBUS(typeof(*s), dev);
+    int regs;
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    regs = cpu_register_io_memory(minimac_read_fn, minimac_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, regs);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_milkymist_minimac_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_minimac_mdio = {
+    .name = "milkymist_minimac_mdio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(last_clk, MilkymistMinimacMdioState),
+        VMSTATE_INT32(count, MilkymistMinimacMdioState),
+        VMSTATE_UINT32(data, MilkymistMinimacMdioState),
+        VMSTATE_UINT16(data_out, MilkymistMinimacMdioState),
+        VMSTATE_INT32(state, MilkymistMinimacMdioState),
+        VMSTATE_UINT8(phy_addr, MilkymistMinimacMdioState),
+        VMSTATE_UINT8(reg_addr, MilkymistMinimacMdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_milkymist_minimac = {
+    .name = "milkymist-minimac",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMinimacState, R_MAX),
+        VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimacState, R_PHY_MAX),
+        VMSTATE_STRUCT(mdio, MilkymistMinimacState, 0,
+                vmstate_milkymist_minimac_mdio, MilkymistMinimacMdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_minimac_info = {
+    .init = milkymist_minimac_init,
+    .qdev.name  = "milkymist-minimac",
+    .qdev.size  = sizeof(MilkymistMinimacState),
+    .qdev.vmsd  = &vmstate_milkymist_minimac,
+    .qdev.reset = milkymist_minimac_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(MilkymistMinimacState, conf),
+        DEFINE_PROP_STRING("phy_model", MilkymistMinimacState, phy_model),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_minimac_register(void)
+{
+    sysbus_register_withprop(&milkymist_minimac_info);
+}
+
+device_init(milkymist_minimac_register)
diff --git a/trace-events b/trace-events
index a1de942..3437ba6 100644
--- a/trace-events
+++ b/trace-events
@@ -303,3 +303,15 @@ disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x v
 # hw/milkymist-memcard.c
 disable milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
 disable milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+
+# hw/milkymist-minimac.c
+disable milkymist_minimac_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_minimac_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_minimac_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+disable milkymist_minimac_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+disable milkymist_minimac_tx_frame(uint32_t length) "length %u"
+disable milkymist_minimac_rx_frame(const void *buf, uint32_t length) "buf %p length %u"
+disable milkymist_minimac_drop_rx_frame(const void *buf) "buf %p"
+disable milkymist_minimac_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
+disable milkymist_minimac_pulse_irq_rx(void) "Pulse IRQ RX"
+disable milkymist_minimac_pulse_irq_tx(void) "Pulse IRQ TX"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 05/14] lm32: add Milkymist PFPU support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (3 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 04/14] lm32: add Milkymist Minimac support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 06/14] lm32: add Milkymist SoftUSB support Michael Walle
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's Programmable FPU.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target     |    1 +
 hw/milkymist-pfpu.c |  536 +++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events        |    6 +
 3 files changed, 543 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-pfpu.c

diff --git a/Makefile.target b/Makefile.target
index 8021476..13f9e72 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -260,6 +260,7 @@ obj-lm32-y += milkymist-ac97.o
 obj-lm32-y += milkymist-hpdmc.o
 obj-lm32-y += milkymist-memcard.o
 obj-lm32-y += milkymist-minimac.o
+obj-lm32-y += milkymist-pfpu.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
new file mode 100644
index 0000000..4831e00
--- /dev/null
+++ b/hw/milkymist-pfpu.c
@@ -0,0 +1,536 @@
+/*
+ *  QEMU model of the Milkymist programmable FPU.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/pfpu.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-log.h"
+#include "qemu-error.h"
+#include <math.h>
+
+/* #define TRACE_EXEC */
+
+#ifdef TRACE_EXEC
+#    define D_EXEC(x) x
+#else
+#    define D_EXEC(x)
+#endif
+
+enum {
+    R_CTL = 0,
+    R_MESHBASE,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_CODEPAGE,
+    R_VERTICES,
+    R_COLLISIONS,
+    R_STRAYWRITES,
+    R_LASTDMA,
+    R_PC,
+    R_DREGBASE,
+    R_CODEBASE,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY = (1<<0),
+};
+
+enum {
+    OP_NOP = 0,
+    OP_FADD,
+    OP_FSUB,
+    OP_FMUL,
+    OP_FABS,
+    OP_F2I,
+    OP_I2F,
+    OP_VECTOUT,
+    OP_SIN,
+    OP_COS,
+    OP_ABOVE,
+    OP_EQUAL,
+    OP_COPY,
+    OP_IF,
+    OP_TSIGN,
+    OP_QUAKE,
+};
+
+enum {
+    GPR_X = 0,
+    GPR_Y = 1,
+    GPR_FLAGS = 2,
+};
+
+enum {
+    LATENCY_FADD = 5,
+    LATENCY_FSUB = 5,
+    LATENCY_FMUL = 7,
+    LATENCY_FABS = 2,
+    LATENCY_F2I = 2,
+    LATENCY_I2F = 3,
+    LATENCY_VECTOUT = 0,
+    LATENCY_SIN = 4,
+    LATENCY_COS = 4,
+    LATENCY_ABOVE = 2,
+    LATENCY_EQUAL = 2,
+    LATENCY_COPY = 2,
+    LATENCY_IF = 2,
+    LATENCY_TSIGN = 2,
+    LATENCY_QUAKE = 2,
+    MAX_LATENCY = 7
+};
+
+#define GPR_BEGIN       0x100
+#define GPR_END         0x17f
+#define MICROCODE_BEGIN 0x200
+#define MICROCODE_END   0x3ff
+#define MICROCODE_WORDS 2048
+
+#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
+
+#ifdef TRACE_EXEC
+static const char *opcode_to_str[] = {
+    "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
+    "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
+};
+#endif
+
+struct MilkymistPFPUState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+    uint32_t gp_regs[128];
+    uint32_t microcode[MICROCODE_WORDS];
+
+    int output_queue_pos;
+    uint32_t output_queue[MAX_LATENCY];
+};
+typedef struct MilkymistPFPUState MilkymistPFPUState;
+
+static inline target_phys_addr_t
+get_dma_address(uint32_t base, uint32_t x, uint32_t y)
+{
+    return base + 8 * (128 * y + x);
+}
+
+static inline void
+output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
+{
+    s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
+}
+
+static inline uint32_t
+output_queue_remove(MilkymistPFPUState *s)
+{
+    return s->output_queue[s->output_queue_pos];
+}
+
+static inline void
+output_queue_advance(MilkymistPFPUState *s)
+{
+    s->output_queue[s->output_queue_pos] = 0;
+    s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
+}
+
+static int pfpu_decode_insn(MilkymistPFPUState *s)
+{
+    uint32_t pc = s->regs[R_PC];
+    uint32_t insn = s->microcode[pc];
+    uint32_t reg_a = (insn >> 18) & 0x7f;
+    uint32_t reg_b = (insn >> 11) & 0x7f;
+    uint32_t op = (insn >> 7) & 0xf;
+    uint32_t reg_d = insn & 0x7f;
+    uint32_t r;
+    int latency = 0;
+
+    switch (op) {
+    case OP_NOP:
+        break;
+    case OP_FADD:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a + b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FADD;
+        D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FSUB:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a - b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FSUB;
+        D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FMUL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a * b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FMUL;
+        D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FABS:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float t = fabsf(a);
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FABS;
+        D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_F2I:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        int32_t t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_F2I;
+        D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
+    } break;
+    case OP_I2F:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_I2F;
+        D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_VECTOUT:
+    {
+        uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
+        uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
+        target_phys_addr_t dma_ptr =
+            get_dma_address(s->regs[R_MESHBASE],
+                    s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
+        cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4);
+        cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4);
+        s->regs[R_LASTDMA] = dma_ptr + 4;
+        D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
+        trace_milkymist_pfpu_vectout(a, b, dma_ptr);
+    } break;
+    case OP_SIN:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_SIN;
+        D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_COS:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_COS;
+        D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_ABOVE:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a > b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_ABOVE;
+        D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_EQUAL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a == b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_EQUAL;
+        D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_COPY:
+    {
+        r = s->gp_regs[reg_a];
+        latency = LATENCY_COPY;
+        D_EXEC(qemu_log("COPY"));
+    } break;
+    case OP_IF:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        uint32_t f = s->gp_regs[GPR_FLAGS];
+        float t = (f != 0) ? a : b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_IF;
+        D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
+    } break;
+    case OP_TSIGN:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (b < 0) ? -a : a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_TSIGN;
+        D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_QUAKE:
+    {
+        uint32_t a = s->gp_regs[reg_a];
+        r = 0x5f3759df - (a >> 1);
+        latency = LATENCY_QUAKE;
+        D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
+    } break;
+
+    default:
+        error_report("milkymist_pfpu: unknown opcode %d\n", op);
+        break;
+    }
+
+    if (!reg_d) {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency));
+    } else {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency, reg_d));
+    }
+
+    if (op == OP_VECTOUT) {
+        return 0;
+    }
+
+    /* store output for this cycle */
+    if (reg_d) {
+        uint32_t val = output_queue_remove(s);
+        D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
+        s->gp_regs[reg_d] = val;
+    }
+
+    output_queue_advance(s);
+
+    /* store op output */
+    if (op != OP_NOP) {
+        output_queue_insert(s, r, latency-1);
+    }
+
+    /* advance PC */
+    s->regs[R_PC]++;
+
+    return 1;
+};
+
+static void pfpu_start(MilkymistPFPUState *s)
+{
+    int x, y;
+    int i;
+
+    for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
+        for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
+            D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
+
+            /* set current position */
+            s->gp_regs[GPR_X] = x;
+            s->gp_regs[GPR_Y] = y;
+
+            /* run microcode on this position */
+            i = 0;
+            while (pfpu_decode_insn(s)) {
+                /* decode at most MICROCODE_WORDS instructions */
+                if (i++ >= MICROCODE_WORDS) {
+                    error_report("milkymist_pfpu: too many instructions "
+                            "executed in microcode. No VECTOUT?\n");
+                    break;
+                }
+            }
+
+            /* reset pc for next run */
+            s->regs[R_PC] = 0;
+        }
+    }
+
+    s->regs[R_VERTICES] = x * y;
+
+    trace_milkymist_pfpu_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
+{
+    return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
+}
+
+static uint32_t pfpu_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistPFPUState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        r = s->regs[addr];
+        break;
+    case GPR_BEGIN ... GPR_END:
+        r = s->gp_regs[addr - GPR_BEGIN];
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        r = s->microcode[get_microcode_address(s, addr)];
+        break;
+
+    default:
+        error_report("milkymist_pfpu: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_pfpu_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+pfpu_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistPFPUState *s = opaque;
+
+    trace_milkymist_pfpu_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        if (value & CTL_START_BUSY) {
+            pfpu_start(s);
+        }
+        break;
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        s->regs[addr] = value;
+        break;
+    case GPR_BEGIN ...  GPR_END:
+        s->gp_regs[addr - GPR_BEGIN] = value;
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        s->microcode[get_microcode_address(s, addr)] = value;
+        break;
+
+    default:
+        error_report("milkymist_pfpu: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const pfpu_read_fn[] = {
+    NULL,
+    NULL,
+    &pfpu_read,
+};
+
+static CPUWriteMemoryFunc * const pfpu_write_fn[] = {
+    NULL,
+    NULL,
+    &pfpu_write,
+};
+
+static void milkymist_pfpu_reset(DeviceState *d)
+{
+    MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < 128; i++) {
+        s->gp_regs[i] = 0;
+    }
+    for (i = 0; i < MICROCODE_WORDS; i++) {
+        s->microcode[i] = 0;
+    }
+    s->output_queue_pos = 0;
+    for (i = 0; i < MAX_LATENCY; i++) {
+        s->output_queue[i] = 0;
+    }
+}
+
+static int milkymist_pfpu_init(SysBusDevice *dev)
+{
+    MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev);
+    int pfpu_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    pfpu_regs = cpu_register_io_memory(pfpu_read_fn, pfpu_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MICROCODE_END * 4, pfpu_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_pfpu = {
+    .name = "milkymist-pfpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
+        VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
+        VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
+        VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
+        VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_pfpu_info = {
+    .init = milkymist_pfpu_init,
+    .qdev.name  = "milkymist-pfpu",
+    .qdev.size  = sizeof(MilkymistPFPUState),
+    .qdev.vmsd  = &vmstate_milkymist_pfpu,
+    .qdev.reset = milkymist_pfpu_reset,
+};
+
+static void milkymist_pfpu_register(void)
+{
+    sysbus_register_withprop(&milkymist_pfpu_info);
+}
+
+device_init(milkymist_pfpu_register)
diff --git a/trace-events b/trace-events
index 3437ba6..a410e93 100644
--- a/trace-events
+++ b/trace-events
@@ -315,3 +315,9 @@ disable milkymist_minimac_drop_rx_frame(const void *buf) "buf %p"
 disable milkymist_minimac_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
 disable milkymist_minimac_pulse_irq_rx(void) "Pulse IRQ RX"
 disable milkymist_minimac_pulse_irq_tx(void) "Pulse IRQ TX"
+
+# hw/milkymist-pfpu.c
+disable milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x"
+disable milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 06/14] lm32: add Milkymist SoftUSB support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (4 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 05/14] lm32: add Milkymist PFPU support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 07/14] lm32: add Milkymist System Controller support Michael Walle
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's SoftUSB core. This model differ
from the real hardware in its functionality. The real hardware consits of a
tiny freely programmable microcontroller which controls the USB ports. For
simplicity reasons, this model emulates only keyboard and mouse input
devices, eg. input events translates directly to the corresponding expected
messages.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target        |    1 +
 hw/milkymist-softusb.c |  357 ++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events           |    8 +
 3 files changed, 366 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-softusb.c

diff --git a/Makefile.target b/Makefile.target
index 13f9e72..280a91d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -261,6 +261,7 @@ obj-lm32-y += milkymist-hpdmc.o
 obj-lm32-y += milkymist-memcard.o
 obj-lm32-y += milkymist-minimac.o
 obj-lm32-y += milkymist-pfpu.o
+obj-lm32-y += milkymist-softusb.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
new file mode 100644
index 0000000..1565260
--- /dev/null
+++ b/hw/milkymist-softusb.c
@@ -0,0 +1,357 @@
+/*
+ *  QEMU model of the Milkymist SoftUSB block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "console.h"
+#include "usb.h"
+#include "qemu-error.h"
+
+enum {
+    R_CTRL = 0,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+#define COMLOC_DEBUG_PRODUCE 0x1000
+#define COMLOC_DEBUG_BASE    0x1001
+#define COMLOC_MEVT_PRODUCE  0x1101
+#define COMLOC_MEVT_BASE     0x1102
+#define COMLOC_KEVT_PRODUCE  0x1142
+#define COMLOC_KEVT_BASE     0x1143
+
+struct MilkymistSoftUsbState {
+    SysBusDevice busdev;
+    USBBus usbbus;
+    USBPort usbport[2];
+    USBDevice *usbdev;
+
+    qemu_irq irq;
+
+    /* device properties */
+    uint32_t pmem_base;
+    uint32_t pmem_size;
+    uint32_t dmem_base;
+    uint32_t dmem_size;
+
+    /* device registers */
+    uint32_t regs[R_MAX];
+
+    /* mouse state */
+    int mouse_dx;
+    int mouse_dy;
+    int mouse_dz;
+    uint8_t mouse_buttons_state;
+
+    /* keyboard state */
+    uint8_t kbd_usb_buffer[8];
+};
+typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
+
+static uint32_t softusb_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistSoftUsbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_softusb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_softusb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+softusb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    trace_milkymist_softusb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_softusb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const softusb_read_fn[] = {
+    NULL,
+    NULL,
+    &softusb_read,
+};
+
+static CPUWriteMemoryFunc * const softusb_write_fn[] = {
+    NULL,
+    NULL,
+    &softusb_write,
+};
+
+static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: read dmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_read(s->dmem_base + offset, buf, len);
+}
+
+static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: write dmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_write(s->dmem_base + offset, buf, len);
+}
+
+static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: read pmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_read(s->pmem_base + offset, buf, len);
+}
+
+static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: write pmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_write(s->pmem_base + offset, buf, len);
+}
+
+static void softusb_mouse_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+    uint8_t buf[4];
+
+    buf[0] = s->mouse_buttons_state;
+    buf[1] = s->mouse_dx;
+    buf[2] = s->mouse_dy;
+    buf[3] = s->mouse_dz;
+
+    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_mevt(m);
+    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, buf, 4);
+    m = (m + 1) & 0xf;
+    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_kbd_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_kevt(m);
+    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_usb_buffer, 8);
+    m = (m + 1) & 0x7;
+    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_mouse_event(void *opaque,
+       int dx, int dy, int dz, int buttons_state)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    trace_milkymist_softusb_mouse_event(dx, dy, dz, buttons_state);
+
+    s->mouse_dx = dx;
+    s->mouse_dy = dy;
+    s->mouse_dz = dz;
+    s->mouse_buttons_state = buttons_state;
+
+    softusb_mouse_changed(s);
+}
+
+static void softusb_usbdev_datain(void *opaque)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    USBPacket p;
+
+    p.pid = USB_TOKEN_IN;
+    p.devep = 1;
+    p.data = s->kbd_usb_buffer;
+    p.len = sizeof(s->kbd_usb_buffer);
+    s->usbdev->info->handle_data(s->usbdev, &p);
+
+    softusb_kbd_changed(s);
+}
+
+static void softusb_attach(USBPort *port)
+{
+}
+
+static USBPortOps softusb_ops = {
+    .attach = softusb_attach,
+};
+
+static void milkymist_softusb_reset(DeviceState *d)
+{
+    MilkymistSoftUsbState *s =
+            container_of(d, MilkymistSoftUsbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    s->mouse_dx = 0;
+    s->mouse_dy = 0;
+    s->mouse_dz = 0;
+    s->mouse_buttons_state = 0;
+    memset(s->kbd_usb_buffer, 0, sizeof(s->kbd_usb_buffer));
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+}
+
+static int milkymist_softusb_init(SysBusDevice *dev)
+{
+    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
+    int softusb_regs;
+    ram_addr_t pmem_ram;
+    ram_addr_t dmem_ram;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    softusb_regs = cpu_register_io_memory(softusb_read_fn, softusb_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, softusb_regs);
+
+    /* register pmem and dmem */
+    pmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.pmem", s->pmem_size);
+    cpu_register_physical_memory(s->pmem_base, s->pmem_size,
+            pmem_ram | IO_MEM_RAM);
+    dmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.dmem", s->dmem_size);
+    cpu_register_physical_memory(s->dmem_base, s->dmem_size,
+            dmem_ram | IO_MEM_RAM);
+
+    qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
+
+    /* create our usb bus */
+    usb_bus_new(&s->usbbus, NULL);
+
+    /* our two ports */
+    usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
+            USB_SPEED_MASK_LOW);
+    usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
+            USB_SPEED_MASK_LOW);
+
+    /* and finally create an usb keyboard */
+    s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");
+    usb_hid_datain_cb(s->usbdev, s, softusb_usbdev_datain);
+    s->usbdev->info->handle_reset(s->usbdev);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_softusb = {
+    .name = "milkymist-softusb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
+        VMSTATE_INT32(mouse_dx, MilkymistSoftUsbState),
+        VMSTATE_INT32(mouse_dy, MilkymistSoftUsbState),
+        VMSTATE_INT32(mouse_dz, MilkymistSoftUsbState),
+        VMSTATE_UINT8(mouse_buttons_state, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(kbd_usb_buffer, MilkymistSoftUsbState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_softusb_info = {
+    .init = milkymist_softusb_init,
+    .qdev.name  = "milkymist-softusb",
+    .qdev.size  = sizeof(MilkymistSoftUsbState),
+    .qdev.vmsd  = &vmstate_milkymist_softusb,
+    .qdev.reset = milkymist_softusb_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32(
+                "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
+        ),
+        DEFINE_PROP_UINT32(
+                "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
+        ),
+        DEFINE_PROP_UINT32(
+                "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
+        ),
+        DEFINE_PROP_UINT32(
+                "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
+        ),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_softusb_register(void)
+{
+    sysbus_register_withprop(&milkymist_softusb_info);
+}
+
+device_init(milkymist_softusb_register)
diff --git a/trace-events b/trace-events
index a410e93..9766f98 100644
--- a/trace-events
+++ b/trace-events
@@ -321,3 +321,11 @@ disable milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x val
 disable milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
 disable milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x"
 disable milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-softusb.c
+disable milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_softusb_mevt(uint8_t m) "m %d"
+disable milkymist_softusb_kevt(uint8_t m) "m %d"
+disable milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x"
+disable milkymist_softusb_pulse_irq(void) "Pulse IRQ"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 07/14] lm32: add Milkymist System Controller support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (5 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 06/14] lm32: add Milkymist SoftUSB support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 08/14] configure: add opengl detection Michael Walle
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's System Controller core. The model
has the following features:
 - support for shutting down and restarting the board
 - provide two timers and GPIO
 - provide registers for system identification and reading the boards
   capabilities

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target       |    1 +
 hw/milkymist-sysctl.c |  330 +++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events          |   11 ++
 3 files changed, 342 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-sysctl.c

diff --git a/Makefile.target b/Makefile.target
index 280a91d..1c558a6 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -262,6 +262,7 @@ obj-lm32-y += milkymist-memcard.o
 obj-lm32-y += milkymist-minimac.o
 obj-lm32-y += milkymist-pfpu.o
 obj-lm32-y += milkymist-softusb.o
+obj-lm32-y += milkymist-sysctl.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
new file mode 100644
index 0000000..eaea543
--- /dev/null
+++ b/hw/milkymist-sysctl.c
@@ -0,0 +1,330 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/sysctl.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu-timer.h"
+#include "qemu-error.h"
+
+enum {
+    CTRL_ENABLE      = (1<<0),
+    CTRL_AUTORESTART = (1<<1),
+};
+
+enum {
+    ICAP_READY       = (1<<0),
+};
+
+enum {
+    R_GPIO_IN = 0,
+    R_GPIO_OUT,
+    R_GPIO_INTEN,
+    R_RESERVED0,
+    R_TIMER0_CONTROL,
+    R_TIMER0_COMPARE,
+    R_TIMER0_COUNTER,
+    R_RESERVED1,
+    R_TIMER1_CONTROL,
+    R_TIMER1_COMPARE,
+    R_TIMER1_COUNTER,
+    R_RESERVED2,
+    R_RESERVED3,
+    R_ICAP,
+    R_CAPABILITIES,
+    R_SYSTEM_ID,
+    R_MAX
+};
+
+struct MilkymistSysctlState {
+    SysBusDevice busdev;
+
+    QEMUBH *bh0;
+    QEMUBH *bh1;
+    ptimer_state *ptimer0;
+    ptimer_state *ptimer1;
+
+    uint32_t freq_hz;
+    uint32_t capabilities;
+    uint32_t systemid;
+    uint32_t strappings;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq gpio_irq;
+    qemu_irq timer0_irq;
+    qemu_irq timer1_irq;
+};
+typedef struct MilkymistSysctlState MilkymistSysctlState;
+
+static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
+{
+    trace_milkymist_sysctl_icap_write(value);
+    switch (value & 0xffff) {
+    case 0x000e:
+        qemu_system_shutdown_request();
+        break;
+    }
+}
+
+static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistSysctlState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_TIMER0_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer0);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER0_COMPARE] - r;
+        break;
+    case R_TIMER1_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer1);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER1_COMPARE] - r;
+        break;
+    case R_GPIO_IN:
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_CONTROL:
+    case R_TIMER0_COMPARE:
+    case R_TIMER1_CONTROL:
+    case R_TIMER1_COMPARE:
+    case R_ICAP:
+    case R_CAPABILITIES:
+    case R_SYSTEM_ID:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_sysctl: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_sysctl_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistSysctlState *s = opaque;
+
+    trace_milkymist_sysctl_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_COUNTER:
+        if (value > s->regs[R_TIMER0_COUNTER]) {
+            value = s->regs[R_TIMER0_COUNTER];
+            error_report("milkymist_sysctl: timer0: trying to write a "
+                    "value greater than the limit. Clipping.");
+        }
+        /* milkymist timer counts up */
+        value = s->regs[R_TIMER0_COUNTER] - value;
+        ptimer_set_count(s->ptimer0, value);
+        break;
+    case R_TIMER1_COUNTER:
+        if (value > s->regs[R_TIMER1_COUNTER]) {
+            value = s->regs[R_TIMER1_COUNTER];
+            error_report("milkymist_sysctl: timer1: trying to write a "
+                    "value greater than the limit. Clipping.");
+        }
+        /* milkymist timer counts up */
+        value = s->regs[R_TIMER1_COUNTER] - value;
+        ptimer_set_count(s->ptimer1, value);
+        break;
+    case R_TIMER0_COMPARE:
+        ptimer_set_limit(s->ptimer0, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER1_COMPARE:
+        ptimer_set_limit(s->ptimer1, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer1();
+            ptimer_run(s->ptimer0, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer1();
+            ptimer_stop(s->ptimer0);
+        }
+        break;
+    case R_TIMER1_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer1();
+            ptimer_run(s->ptimer1, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer1();
+            ptimer_stop(s->ptimer1);
+        }
+        break;
+    case R_ICAP:
+        sysctl_icap_write(s, value);
+        break;
+    case R_SYSTEM_ID:
+        qemu_system_reset_request();
+        break;
+
+    case R_GPIO_IN:
+    case R_CAPABILITIES:
+        error_report("milkymist_sysctl: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_sysctl: write access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const sysctl_read_fn[] = {
+    NULL,
+    NULL,
+    &sysctl_read,
+};
+
+static CPUWriteMemoryFunc * const sysctl_write_fn[] = {
+    NULL,
+    NULL,
+    &sysctl_write,
+};
+
+static void timer0_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer0();
+        ptimer_stop(s->ptimer0);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer0();
+    qemu_irq_pulse(s->timer0_irq);
+}
+
+static void timer1_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer1();
+        ptimer_stop(s->ptimer1);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer1();
+    qemu_irq_pulse(s->timer1_irq);
+}
+
+static void milkymist_sysctl_reset(DeviceState *d)
+{
+    MilkymistSysctlState *s =
+            container_of(d, MilkymistSysctlState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    ptimer_stop(s->ptimer0);
+    ptimer_stop(s->ptimer1);
+
+    /* defaults */
+    s->regs[R_ICAP] = ICAP_READY;
+    s->regs[R_SYSTEM_ID] = s->systemid;
+    s->regs[R_CAPABILITIES] = s->capabilities;
+    s->regs[R_GPIO_IN] = s->strappings;
+}
+
+static int milkymist_sysctl_init(SysBusDevice *dev)
+{
+    MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
+    int sysctl_regs;
+
+    sysbus_init_irq(dev, &s->gpio_irq);
+    sysbus_init_irq(dev, &s->timer0_irq);
+    sysbus_init_irq(dev, &s->timer1_irq);
+
+    s->bh0 = qemu_bh_new(timer0_hit, s);
+    s->bh1 = qemu_bh_new(timer1_hit, s);
+    s->ptimer0 = ptimer_init(s->bh0);
+    s->ptimer1 = ptimer_init(s->bh1);
+    ptimer_set_freq(s->ptimer0, s->freq_hz);
+    ptimer_set_freq(s->ptimer1, s->freq_hz);
+
+    sysctl_regs = cpu_register_io_memory(sysctl_read_fn, sysctl_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, sysctl_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_sysctl = {
+    .name = "milkymist-sysctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
+        VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
+        VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_sysctl_info = {
+    .init = milkymist_sysctl_init,
+    .qdev.name  = "milkymist-sysctl",
+    .qdev.size  = sizeof(MilkymistSysctlState),
+    .qdev.vmsd  = &vmstate_milkymist_sysctl,
+    .qdev.reset = milkymist_sysctl_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+                freq_hz, 80000000),
+        DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+                capabilities, 0x00000000),
+        DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+                systemid, 0x10014d31),
+        DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+                strappings, 0x00000001),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_sysctl_register(void)
+{
+    sysbus_register_withprop(&milkymist_sysctl_info);
+}
+
+device_init(milkymist_sysctl_register)
diff --git a/trace-events b/trace-events
index 9766f98..02ea2e8 100644
--- a/trace-events
+++ b/trace-events
@@ -329,3 +329,14 @@ disable milkymist_softusb_mevt(uint8_t m) "m %d"
 disable milkymist_softusb_kevt(uint8_t m) "m %d"
 disable milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x"
 disable milkymist_softusb_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-sysctl.c
+disable milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_sysctl_icap_write(uint32_t value) "value %08x"
+disable milkymist_sysctl_start_timer0(void) "Start timer0"
+disable milkymist_sysctl_stop_timer0(void) "Stop timer0"
+disable milkymist_sysctl_start_timer1(void) "Start timer1"
+disable milkymist_sysctl_stop_timer1(void) "Stop timer1"
+disable milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
+disable milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 08/14] configure: add opengl detection
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (6 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 07/14] lm32: add Milkymist System Controller support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 09/14] lm32: add Milkymist TMU2 support Michael Walle
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch introduce a new config option CONFIG_OPENGL.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 configure |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/configure b/configure
index e75e1a2..fe8791d 100755
--- a/configure
+++ b/configure
@@ -130,6 +130,7 @@ linux_aio=""
 attr=""
 vhost_net=""
 xfs=""
+opengl=""
 
 gprof="no"
 debug_tcg="no"
@@ -713,6 +714,10 @@ for opt do
   ;;
   --enable-vhost-net) vhost_net="yes"
   ;;
+  --disable-opengl) opengl="no"
+  ;;
+  --enable-opengl) opengl="yes"
+  ;;
   --*dir)
   ;;
   --disable-rbd) rbd="no"
@@ -872,6 +877,8 @@ echo "  --disable-kvm            disable KVM acceleration support"
 echo "  --enable-kvm             enable KVM acceleration support"
 echo "  --disable-nptl           disable usermode NPTL support"
 echo "  --enable-nptl            enable usermode NPTL support"
+echo "  --disable-opengl         disable OpenGL support"
+echo "  --enable-opengl          enable OpenGL support"
 echo "  --enable-system          enable all system emulation targets"
 echo "  --disable-system         disable all system emulation targets"
 echo "  --enable-user            enable supported user emulation targets"
@@ -1923,6 +1930,27 @@ EOF
   fi
 fi
 
+##########################################
+# opengl probe, used by milkymist-tmu2
+if test "$opengl" != "no" ; then
+  opengl_libs="-lGL"
+  cat > $TMPC << EOF
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+int main(void) { GL_VERSION; return 0; }
+EOF
+  if compile_prog "" "-lGL" ; then
+    opengl=yes
+	libs_softmmu="$opengl_libs $libs_softmmu"
+  else
+    if test "$opengl" = "yes" ; then
+      feature_not_found "opengl"
+    fi
+    opengl=no
+  fi
+fi
+
 #
 # Check for xxxat() functions when we are building linux-user
 # emulator.  This is done because older glibc versions don't
@@ -2530,6 +2558,7 @@ echo "Trace output file $trace_file-<pid>"
 echo "spice support     $spice"
 echo "rbd support       $rbd"
 echo "xfsctl support    $xfs"
+echo "OpenGL support    $opengl"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2811,6 +2840,10 @@ if test "$spice" = "yes" ; then
   echo "CONFIG_SPICE=y" >> $config_host_mak
 fi
 
+if test "$opengl" = "yes" ; then
+  echo "CONFIG_OPENGL=y" >> $config_host_mak
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "CONFIG_BSD=y" >> $config_host_mak
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 09/14] lm32: add Milkymist TMU2 support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (7 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 08/14] configure: add opengl detection Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 10/14] lm32: add Milkymist UART support Michael Walle
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's texture mapping unit. For fast
computation this model needs hardware accelerated 3D graphics support
(OpenGL). There is no graphical output, all computations belong to internal
framebuffers only.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target     |    1 +
 hw/milkymist-tmu2.c |  481 +++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events        |    6 +
 3 files changed, 488 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-tmu2.c

diff --git a/Makefile.target b/Makefile.target
index 1c558a6..0aae6d0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -263,6 +263,7 @@ obj-lm32-y += milkymist-minimac.o
 obj-lm32-y += milkymist-pfpu.o
 obj-lm32-y += milkymist-softusb.o
 obj-lm32-y += milkymist-sysctl.o
+obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
new file mode 100644
index 0000000..9cebe31
--- /dev/null
+++ b/hw/milkymist-tmu2.c
@@ -0,0 +1,481 @@
+/*
+ *  QEMU model of the Milkymist texture mapping unit.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *  Copyright (c) 2010 Sebastien Bourdeauducq
+ *                       <sebastien.bourdeauducq@lekernel.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/tmu2.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-error.h"
+
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+enum {
+    R_CTL = 0,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_BRIGHTNESS,
+    R_CHROMAKEY,
+    R_VERTICESADDR,
+    R_TEXFBUF,
+    R_TEXHRES,
+    R_TEXVRES,
+    R_TEXHMASK,
+    R_TEXVMASK,
+    R_DSTFBUF,
+    R_DSTHRES,
+    R_DSTVRES,
+    R_DSTHOFFSET,
+    R_DSTVOFFSET,
+    R_DSTSQUAREW,
+    R_DSTSQUAREH,
+    R_ALPHA,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY  = (1<<0),
+    CTL_CHROMAKEY   = (1<<1),
+};
+
+enum {
+    MAX_BRIGHTNESS = 63,
+    MAX_ALPHA      = 63,
+};
+
+enum {
+    MESH_MAXSIZE = 128,
+};
+
+struct vertex {
+    int x;
+    int y;
+} __attribute__((packed));
+
+struct MilkymistTMU2State {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+
+    Display *dpy;
+    GLXFBConfig glx_fb_config;
+    GLXContext glx_context;
+};
+typedef struct MilkymistTMU2State MilkymistTMU2State;
+
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+
+static int tmu2_glx_init(MilkymistTMU2State *s)
+{
+    GLXFBConfig *configs;
+    int nelements;
+
+    s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
+    if (s->dpy == NULL) {
+        return 1;
+    }
+
+    configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        return 1;
+    }
+
+    s->glx_fb_config = *configs;
+    XFree(configs);
+
+    /* FIXME: call glXDestroyContext() */
+    s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
+            GLX_RGBA_TYPE, NULL, 1);
+    if (s->glx_context == NULL) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
+        int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
+{
+    int x, y;
+    int x0, y0, x1, y1;
+    int u0, v0, u1, v1, u2, v2, u3, v3;
+    double xscale = 1.0 / ((double)(64 * texhres));
+    double yscale = 1.0 / ((double)(64 * texvres));
+
+    glLoadIdentity();
+    glTranslatef(ho, vo, 0);
+    glEnable(GL_TEXTURE_2D);
+    glBegin(GL_QUADS);
+
+    for (y = 0; y < vmeshlast; y++) {
+        y0 = y * sh;
+        y1 = y0 + sh;
+        for (x = 0; x < hmeshlast; x++) {
+            x0 = x * sw;
+            x1 = x0 + sw;
+
+            u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
+            v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
+            u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
+            v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
+            u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
+            v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
+            u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
+            v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
+
+            glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
+            glVertex3i(x0, y0, 0);
+            glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
+            glVertex3i(x1, y0, 0);
+            glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
+            glVertex3i(x1, y1, 0);
+            glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
+            glVertex3i(x0, y1, 0);
+        }
+    }
+
+    glEnd();
+}
+
+static void tmu2_start(MilkymistTMU2State *s)
+{
+    int pbuffer_attrib[6] = {
+        GLX_PBUFFER_WIDTH,
+        0,
+        GLX_PBUFFER_HEIGHT,
+        0,
+        GLX_PRESERVED_CONTENTS,
+        True
+    };
+
+    GLXPbuffer pbuffer;
+    GLuint texture;
+    void *fb;
+    target_phys_addr_t fb_len;
+    void *mesh;
+    target_phys_addr_t mesh_len;
+    float m;
+
+    trace_milkymist_tmu2_start();
+
+    /* Create and set up a suitable OpenGL context */
+    pbuffer_attrib[1] = s->regs[R_DSTHRES];
+    pbuffer_attrib[3] = s->regs[R_DSTVRES];
+    pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
+    glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
+
+    /* Fixup endianness. TODO: would it work on BE hosts? */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+    glPixelStorei(GL_PACK_SWAP_BYTES, 1);
+
+    /* Row alignment */
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_PACK_ALIGNMENT, 2);
+
+    /* Read the QEMU source framebuffer into an OpenGL texture */
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
+    fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+    glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+            0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+
+    /* Set up texturing options */
+    /* WARNING:
+     * Many cases of TMU2 masking are not supported by OpenGL.
+     * We only implement the most common ones:
+     *  - full bilinear filtering vs. nearest texel
+     *  - texture clamping vs. texture wrapping
+     */
+    if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    }
+    if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    }
+    if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+
+    /* Translucency and decay */
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
+    glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
+
+    /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+    glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+
+    /* Map the texture */
+    mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
+    mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
+    if (mesh == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    tmu2_gl_map((struct vertex *)mesh,
+        s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+        s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
+        s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
+        s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
+    cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
+
+    /* Write back the OpenGL framebuffer to the QEMU framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
+
+    /* Free OpenGL allocs */
+    glDeleteTextures(1, &texture);
+    glXMakeContextCurrent(s->dpy, None, None, NULL);
+    glXDestroyPbuffer(s->dpy, pbuffer);
+
+    s->regs[R_CTL] &= ~CTL_START_BUSY;
+
+    trace_milkymist_tmu2_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static uint32_t tmu2_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistTMU2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_BRIGHTNESS:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_tmu2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_tmu2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void tmu2_check_registers(MilkymistTMU2State *s)
+{
+    if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
+        error_report("milkymist_tmu2: max brightness is %d\n", MAX_BRIGHTNESS);
+    }
+
+    if (s->regs[R_ALPHA] > MAX_ALPHA) {
+        error_report("milkymist_tmu2: max alpha is %d\n", MAX_ALPHA);
+    }
+
+    if (s->regs[R_VERTICESADDR] & 0x07) {
+        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
+                "aligned\n");
+    }
+
+    if (s->regs[R_TEXFBUF] & 0x01) {
+        error_report("milkymist_tmu2: texture buffer address has to be "
+                "16-bit aligned\n");
+    }
+}
+
+static void tmu2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistTMU2State *s = opaque;
+
+    trace_milkymist_tmu2_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        s->regs[addr] = value;
+        if (value & CTL_START_BUSY) {
+            tmu2_start(s);
+        }
+        break;
+    case R_BRIGHTNESS:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_tmu2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    tmu2_check_registers(s);
+}
+
+static CPUReadMemoryFunc * const tmu2_read_fn[] = {
+    NULL,
+    NULL,
+    &tmu2_read,
+};
+
+static CPUWriteMemoryFunc * const tmu2_write_fn[] = {
+    NULL,
+    NULL,
+    &tmu2_write,
+};
+
+static void milkymist_tmu2_reset(DeviceState *d)
+{
+    MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_tmu2_init(SysBusDevice *dev)
+{
+    MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
+    int tmu2_regs;
+
+    if (tmu2_glx_init(s)) {
+        return 1;
+    }
+
+    sysbus_init_irq(dev, &s->irq);
+
+    tmu2_regs = cpu_register_io_memory(tmu2_read_fn, tmu2_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, tmu2_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_tmu2 = {
+    .name = "milkymist-tmu2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_tmu2_info = {
+    .init = milkymist_tmu2_init,
+    .qdev.name  = "milkymist-tmu2",
+    .qdev.size  = sizeof(MilkymistTMU2State),
+    .qdev.vmsd  = &vmstate_milkymist_tmu2,
+    .qdev.reset = milkymist_tmu2_reset,
+};
+
+static void milkymist_tmu2_register(void)
+{
+    sysbus_register_withprop(&milkymist_tmu2_info);
+}
+
+device_init(milkymist_tmu2_register)
diff --git a/trace-events b/trace-events
index 02ea2e8..85b6b21 100644
--- a/trace-events
+++ b/trace-events
@@ -340,3 +340,9 @@ disable milkymist_sysctl_start_timer1(void) "Start timer1"
 disable milkymist_sysctl_stop_timer1(void) "Stop timer1"
 disable milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
 disable milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
+
+# hw/milkymist-tmu2.c
+disable milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_tmu2_start(void) "Start TMU"
+disable milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 10/14] lm32: add Milkymist UART support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (8 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 09/14] lm32: add Milkymist TMU2 support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 11/14] lm32: add Milkymist VGAFB support Michael Walle
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's simple UART.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target     |    1 +
 hw/milkymist-uart.c |  180 +++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events        |    6 ++
 3 files changed, 187 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-uart.c

diff --git a/Makefile.target b/Makefile.target
index 0aae6d0..c78e9d4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -264,6 +264,7 @@ obj-lm32-y += milkymist-pfpu.o
 obj-lm32-y += milkymist-softusb.o
 obj-lm32-y += milkymist-sysctl.o
 obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o
+obj-lm32-y += milkymist-uart.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
new file mode 100644
index 0000000..56c90da
--- /dev/null
+++ b/hw/milkymist-uart.c
@@ -0,0 +1,180 @@
+/*
+ *  QEMU model of the Milkymist UART block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/uart.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+#include "qemu-error.h"
+
+enum {
+    R_RXTX = 0,
+    R_DIV,
+    R_MAX
+};
+
+struct MilkymistUartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistUartState MilkymistUartState;
+
+static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistUartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+    case R_DIV:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_uart: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_uart_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistUartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_milkymist_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_write(s->chr, &ch, 1);
+        }
+        trace_milkymist_uart_pulse_irq_tx();
+        qemu_irq_pulse(s->tx_irq);
+        break;
+    case R_DIV:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const uart_read_fn[] = {
+    NULL,
+    NULL,
+    &uart_read,
+};
+
+static CPUWriteMemoryFunc * const uart_write_fn[] = {
+    NULL,
+    NULL,
+    &uart_write,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    MilkymistUartState *s = opaque;
+
+    s->regs[R_RXTX] = *buf;
+    trace_milkymist_uart_pulse_irq_rx();
+    qemu_irq_pulse(s->rx_irq);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    return 1;
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void milkymist_uart_reset(DeviceState *d)
+{
+    MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_uart_init(SysBusDevice *dev)
+{
+    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
+    int uart_regs;
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_uart = {
+    .name = "milkymist-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_uart_info = {
+    .init = milkymist_uart_init,
+    .qdev.name  = "milkymist-uart",
+    .qdev.size  = sizeof(MilkymistUartState),
+    .qdev.vmsd  = &vmstate_milkymist_uart,
+    .qdev.reset = milkymist_uart_reset,
+};
+
+static void milkymist_uart_register(void)
+{
+    sysbus_register_withprop(&milkymist_uart_info);
+}
+
+device_init(milkymist_uart_register)
diff --git a/trace-events b/trace-events
index 85b6b21..1e574c4 100644
--- a/trace-events
+++ b/trace-events
@@ -346,3 +346,9 @@ disable milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x val
 disable milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
 disable milkymist_tmu2_start(void) "Start TMU"
 disable milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-uart.c
+disable milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX"
+disable milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 11/14] lm32: add Milkymist VGAFB support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (9 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 10/14] lm32: add Milkymist UART support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 12/14] lm32: add milkymist hw support functions Michael Walle
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for Milkymist's VGA framebuffer.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target               |    2 +
 hw/milkymist-vgafb.c          |  318 +++++++++++++++++++++++++++++++++++++++++
 hw/milkymist-vgafb_template.h |   74 ++++++++++
 trace-events                  |    4 +
 4 files changed, 398 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-vgafb.c
 create mode 100644 hw/milkymist-vgafb_template.h

diff --git a/Makefile.target b/Makefile.target
index c78e9d4..52a5528 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -265,6 +265,8 @@ obj-lm32-y += milkymist-softusb.o
 obj-lm32-y += milkymist-sysctl.o
 obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o
 obj-lm32-y += milkymist-uart.o
+obj-lm32-y += milkymist-vgafb.o
+obj-lm32-y += framebuffer.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
new file mode 100644
index 0000000..8922731
--- /dev/null
+++ b/hw/milkymist-vgafb.c
@@ -0,0 +1,318 @@
+
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/vgafb.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "console.h"
+#include "framebuffer.h"
+#include "pixel_ops.h"
+#include "qemu-error.h"
+
+#define BITS 8
+#include "milkymist-vgafb_template.h"
+#define BITS 15
+#include "milkymist-vgafb_template.h"
+#define BITS 16
+#include "milkymist-vgafb_template.h"
+#define BITS 24
+#include "milkymist-vgafb_template.h"
+#define BITS 32
+#include "milkymist-vgafb_template.h"
+
+enum {
+    R_CTRL = 0,
+    R_HRES,
+    R_HSYNC_START,
+    R_HSYNC_END,
+    R_HSCAN,
+    R_VRES,
+    R_VSYNC_START,
+    R_VSYNC_END,
+    R_VSCAN,
+    R_BASEADDRESS,
+    R_BASEADDRESS_ACT,
+    R_BURST_COUNT,
+    R_SOURCE_CLOCK,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+struct MilkymistVgafbState {
+    SysBusDevice busdev;
+    DisplayState *ds;
+
+    int invalidate;
+    uint32_t fb_offset;
+    uint32_t fb_mask;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistVgafbState MilkymistVgafbState;
+
+static int vgafb_enabled(MilkymistVgafbState *s)
+{
+    return !(s->regs[R_CTRL] & CTRL_RESET);
+}
+
+static void vgafb_update_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    int first = 0;
+    int last = 0;
+    drawfn fn;
+
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    int dest_width = s->regs[R_HRES];
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+    case 8:
+        fn = draw_line_8;
+        break;
+    case 15:
+        fn = draw_line_15;
+        dest_width *= 2;
+        break;
+    case 16:
+        fn = draw_line_16;
+        dest_width *= 2;
+        break;
+    case 24:
+        fn = draw_line_24;
+        dest_width *= 3;
+        break;
+    case 32:
+        fn = draw_line_32;
+        dest_width *= 4;
+        break;
+    default:
+        hw_error("milkymist_vgafb: bad color depth\n");
+        break;
+    }
+
+    framebuffer_update_display(s->ds,
+                               s->regs[R_BASEADDRESS] + s->fb_offset,
+                               s->regs[R_HRES],
+                               s->regs[R_VRES],
+                               s->regs[R_HRES] * 2,
+                               dest_width,
+                               0,
+                               s->invalidate,
+                               fn,
+                               NULL,
+                               &first, &last);
+
+    if (first >= 0) {
+        dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
+    }
+    s->invalidate = 0;
+}
+
+static void vgafb_invalidate_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    s->invalidate = 1;
+}
+
+static void vgafb_resize(MilkymistVgafbState *s)
+{
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]);
+    s->invalidate = 1;
+}
+
+static uint32_t vgafb_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistVgafbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+    case R_HRES:
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VRES:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BASEADDRESS:
+    case R_BURST_COUNT:
+    case R_SOURCE_CLOCK:
+        r = s->regs[addr];
+    break;
+    case R_BASEADDRESS_ACT:
+        r = s->regs[R_BASEADDRESS];
+    break;
+
+    default:
+        error_report("milkymist_vgafb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_vgafb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistVgafbState *s = opaque;
+
+    trace_milkymist_vgafb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BURST_COUNT:
+    case R_SOURCE_CLOCK:
+        s->regs[addr] = value;
+        break;
+    case R_BASEADDRESS:
+        if (value & 0x1f) {
+            error_report("milkymist_vgafb: framebuffer base address have to "
+                     "be 32 byte aligned");
+            break;
+        }
+        s->regs[addr] = value & s->fb_mask;
+        s->invalidate = 1;
+        break;
+    case R_HRES:
+    case R_VRES:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_BASEADDRESS_ACT:
+        error_report("milkymist_vgafb: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_vgafb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const vgafb_read_fn[] = {
+   NULL,
+   NULL,
+   &vgafb_read
+};
+
+static CPUWriteMemoryFunc * const vgafb_write_fn[] = {
+   NULL,
+   NULL,
+   &vgafb_write
+};
+
+static void milkymist_vgafb_reset(DeviceState *d)
+{
+    MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+    s->regs[R_HRES] = 640;
+    s->regs[R_VRES] = 480;
+    s->regs[R_BASEADDRESS] = 0;
+}
+
+static int milkymist_vgafb_init(SysBusDevice *dev)
+{
+    MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
+    int vgafb_regs;
+
+    vgafb_regs = cpu_register_io_memory(vgafb_read_fn, vgafb_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, vgafb_regs);
+
+    s->ds = graphic_console_init(vgafb_update_display,
+                                 vgafb_invalidate_display,
+                                 NULL, NULL, s);
+
+    return 0;
+}
+
+static int vgafb_post_load(void *opaque, int version_id)
+{
+    vgafb_invalidate_display(opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_vgafb = {
+    .name = "milkymist-vgafb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vgafb_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_vgafb_info = {
+    .init = milkymist_vgafb_init,
+    .qdev.name  = "milkymist-vgafb",
+    .qdev.size  = sizeof(MilkymistVgafbState),
+    .qdev.vmsd  = &vmstate_milkymist_vgafb,
+    .qdev.reset = milkymist_vgafb_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+        DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_vgafb_register(void)
+{
+    sysbus_register_withprop(&milkymist_vgafb_info);
+}
+
+device_init(milkymist_vgafb_register)
diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h
new file mode 100644
index 0000000..69af9ef
--- /dev/null
+++ b/hw/milkymist-vgafb_template.h
@@ -0,0 +1,74 @@
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if BITS == 8
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *to = rgb_to_pixel8(r, g, b);              \
+        to += 1;                                   \
+    } while (0)
+#elif BITS == 15
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 16
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 24
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        uint32 tmp = rgb_to_pixel24(r, g, b);      \
+        *(to++) =         tmp & 0xff;              \
+        *(to++) =  (tmp >> 8) & 0xff;              \
+        *(to++) = (tmp >> 16) & 0xff;              \
+    } while (0)
+#elif BITS == 32
+#define COPY_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(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
+        int width, int deststep)
+{
+    uint16_t rgb565;
+    uint8_t r, g, b;
+
+    while (width--) {
+        rgb565 = lduw_raw(s);
+        r = ((rgb565 >> 11) & 0x1f) << 3;
+        g = ((rgb565 >>  5) & 0x3f) << 2;
+        b = ((rgb565 >>  0) & 0x1f) << 3;
+        COPY_PIXEL(d, r, g, b);
+        s += 2;
+    }
+}
+
+#undef BITS
+#undef COPY_PIXEL
diff --git a/trace-events b/trace-events
index 1e574c4..058a027 100644
--- a/trace-events
+++ b/trace-events
@@ -352,3 +352,7 @@ disable milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x val
 disable milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
 disable milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX"
 disable milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
+
+# hw/milkymist-vgafb.c
+disable milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 12/14] lm32: add milkymist hw support functions
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (10 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 11/14] lm32: add Milkymist VGAFB support Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 13/14] lm32: add support for the Milkymist board Michael Walle
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds wrappers for easy creation of the qdev devices.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 hw/milkymist-hw.h |  204 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 204 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist-hw.h

diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h
new file mode 100644
index 0000000..15acdbc
--- /dev/null
+++ b/hw/milkymist-hw.h
@@ -0,0 +1,204 @@
+#ifndef QEMU_HW_MILKYMIST_H
+#define QEMU_HW_MILKYMIST_H
+
+static inline DeviceState *milkymist_uart_create(target_phys_addr_t base,
+        qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-uart");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_hpdmc_create(target_phys_addr_t base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-hpdmc");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_memcard_create(target_phys_addr_t base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-memcard");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_vgafb_create(target_phys_addr_t base,
+        uint32_t fb_offset, uint32_t fb_mask)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-vgafb");
+    qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
+    qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_sysctl_create(target_phys_addr_t base,
+        qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
+        uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
+        uint32_t gpio_strappings)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-sysctl");
+    qdev_prop_set_uint32(dev, "frequency", freq_hz);
+    qdev_prop_set_uint32(dev, "systemid", system_id);
+    qdev_prop_set_uint32(dev, "capabilities", capabilities);
+    qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, gpio_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, timer0_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2, timer1_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_pfpu_create(target_phys_addr_t base,
+        qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-pfpu");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+    return dev;
+}
+
+#ifdef CONFIG_OPENGL
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+#endif
+
+static inline DeviceState *milkymist_tmu2_create(target_phys_addr_t base,
+        qemu_irq irq)
+{
+#ifdef CONFIG_OPENGL
+    DeviceState *dev;
+    Display *d;
+    GLXFBConfig *configs;
+    int nelements;
+    int ver_major, ver_minor;
+
+    if (display_type == DT_NOGRAPHIC) {
+        return NULL;
+    }
+
+    /* check that GLX will work */
+    d = XOpenDisplay(NULL);
+    if (d == NULL) {
+        return NULL;
+    }
+
+    if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
+        /* Yeah, sometimes getting the GLX version can fail.
+         * Isn't X beautiful? */
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
+        printf("Your GLX version is %d.%d,"
+          "but TMU emulation needs at least 1.3. TMU disabled.\n",
+          ver_major, ver_minor);
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    XFree(configs);
+    XCloseDisplay(d);
+
+    dev = qdev_create(NULL, "milkymist-tmu2");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+#else
+    return NULL;
+#endif
+}
+
+static inline DeviceState *milkymist_ac97_create(target_phys_addr_t base,
+        qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
+        qemu_irq dmaw_irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-ac97");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, crrequest_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, crreply_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2, dmar_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 3, dmaw_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_minimac_create(target_phys_addr_t base,
+        qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(&nd_table[0], "minimac");
+    dev = qdev_create(NULL, "milkymist-minimac");
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_softusb_create(target_phys_addr_t base,
+        qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
+        uint32_t dmem_base, uint32_t dmem_size)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-softusb");
+    qdev_prop_set_uint32(dev, "pmem_base", pmem_base);
+    qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
+    qdev_prop_set_uint32(dev, "dmem_base", dmem_base);
+    qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+#endif /* QEMU_HW_MILKYMIST_H */
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 13/14] lm32: add support for the Milkymist board
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (11 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 12/14] lm32: add milkymist hw support functions Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 14/14] MAINTAINERS: add " Michael Walle
  2011-03-16 17:08 ` [Qemu-devel] Re: [PATCH 00/14] lm32: Milkymist board support Alexander Graf
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds almost complete support for the Milkymist system-on-chip
(http://www.milkymist.org).

Additional to running bare metal applications, booting a linux kernel with
initrd is supported.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target                  |    1 +
 default-configs/lm32-softmmu.mak |    1 +
 hw/milkymist.c                   |  216 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 218 insertions(+), 0 deletions(-)
 create mode 100644 hw/milkymist.c

diff --git a/Makefile.target b/Makefile.target
index 52a5528..8d0e101 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -249,6 +249,7 @@ obj-ppc-y += xilinx_ethlite.o
 
 # LM32 boards
 obj-lm32-y += lm32_boards.o
+obj-lm32-y += milkymist.o
 
 # LM32 peripherals
 obj-lm32-y += lm32_pic.o
diff --git a/default-configs/lm32-softmmu.mak b/default-configs/lm32-softmmu.mak
index 3e7f57e..0d19974 100644
--- a/default-configs/lm32-softmmu.mak
+++ b/default-configs/lm32-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for lm32-softmmu
 
 CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_SD=y
diff --git a/hw/milkymist.c b/hw/milkymist.c
new file mode 100644
index 0000000..8defad8
--- /dev/null
+++ b/hw/milkymist.c
@@ -0,0 +1,216 @@
+/*
+ *  QEMU model for the Milkymist board.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+#include "milkymist-hw.h"
+#include "lm32.h"
+
+#define BIOS_FILENAME    "mmone-bios.bin"
+#define BIOS_OFFSET      0x00860000
+#define BIOS_SIZE        (512*1024)
+#define KERNEL_LOAD_ADDR 0x40000000
+
+typedef struct {
+    CPUState *env;
+    target_phys_addr_t bootstrap_pc;
+    target_phys_addr_t flash_base;
+    target_phys_addr_t initrd_base;
+    size_t initrd_size;
+    target_phys_addr_t cmdline_base;
+} ResetInfo;
+
+static void cpu_irq_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = opaque;
+
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetInfo *reset_info = opaque;
+    CPUState *env = reset_info->env;
+
+    cpu_reset(env);
+
+    /* init defaults */
+    env->pc = reset_info->bootstrap_pc;
+    env->regs[R_R1] = reset_info->cmdline_base;
+    env->regs[R_R2] = reset_info->initrd_base;
+    env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void
+milkymist_init(ram_addr_t ram_size_not_used,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    int kernel_size;
+    DriveInfo *dinfo;
+    ram_addr_t phys_sdram;
+    ram_addr_t phys_flash;
+    qemu_irq irq[32], *cpu_irq;
+    int i;
+    char *bios_filename;
+    ResetInfo *reset_info;
+
+    /* memory map */
+    target_phys_addr_t flash_base   = 0x00000000;
+    size_t flash_sector_size        = 128 * 1024;
+    size_t flash_size               = 32 * 1024 * 1024;
+    target_phys_addr_t sdram_base   = 0x40000000;
+    size_t sdram_size               = 128 * 1024 * 1024;
+
+    target_phys_addr_t initrd_base  = sdram_base + 0x1002000;
+    target_phys_addr_t cmdline_base = sdram_base + 0x1000000;
+    size_t initrd_max = sdram_size - 0x1002000;
+
+    reset_info = qemu_mallocz(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    cpu_lm32_set_phys_msb_ignore(env, 1);
+
+    phys_sdram = qemu_ram_alloc(NULL, "milkymist.sdram", sdram_size);
+    cpu_register_physical_memory(sdram_base, sdram_size,
+            phys_sdram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "milkymist.flash", flash_size);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Numonyx JS28F256J3F105 */
+    pflash_cfi01_register(flash_base, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 2,
+                          0x00, 0x89, 0x00, 0x1d, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    /* load bios rom */
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    if (bios_filename) {
+        load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE);
+    }
+
+    reset_info->bootstrap_pc = BIOS_OFFSET;
+
+    /* if no kernel is given no valid bios rom is a fatal error */
+    if (!kernel_filename && !dinfo && !bios_filename) {
+        fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n",
+                bios_name);
+        exit(1);
+    }
+
+    milkymist_uart_create(0x60000000, irq[0], irq[1]);
+    milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4],
+            80000000, 0x10014d31, 0x0000041f, 0x00000001);
+    milkymist_hpdmc_create(0x60002000);
+    milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
+    milkymist_memcard_create(0x60004000);
+    milkymist_ac97_create(0x60005000, irq[5], irq[6], irq[7], irq[8]);
+    milkymist_pfpu_create(0x60006000, irq[9]);
+    milkymist_tmu2_create(0x60007000, irq[10]);
+    milkymist_minimac_create(0x60008000, irq[11], irq[12]);
+    milkymist_softusb_create(0x6000f000, irq[17],
+            0x20000000, 0x1000, 0x20020000, 0x2000);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    if (kernel_filename) {
+        uint64_t entry;
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, sdram_base,
+                                              sdram_size);
+            reset_info->bootstrap_pc = sdram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = (uint32_t)cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = (uint32_t)initrd_base;
+        reset_info->initrd_size = (uint32_t)initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine milkymist_machine = {
+    .name = "milkymist",
+    .desc = "Milkymist One",
+    .init = milkymist_init,
+    .is_default = 0
+};
+
+static void milkymist_machine_init(void)
+{
+    qemu_register_machine(&milkymist_machine);
+}
+
+machine_init(milkymist_machine_init);
-- 
1.7.2.3

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

* [Qemu-devel] [PATCH 14/14] MAINTAINERS: add Milkymist board
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (12 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 13/14] lm32: add support for the Milkymist board Michael Walle
@ 2011-03-07 22:32 ` Michael Walle
  2011-03-16 17:08 ` [Qemu-devel] Re: [PATCH 00/14] lm32: Milkymist board support Alexander Graf
  14 siblings, 0 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-07 22:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

Signed-off-by: Michael Walle <michael@walle.cc>
---
 MAINTAINERS |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9f3ff0e..e6f853d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -214,6 +214,11 @@ M: Michael Walle <michael@walle.cc>
 S: Maintained
 F: hw/lm32_boards.c
 
+milkymist
+M: Michael Walle <michael@walle.cc>
+S: Maintained
+F: hw/milkymist.c
+
 M68K Machines
 -------------
 an5206
-- 
1.7.2.3

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

* [Qemu-devel] Re: [PATCH 01/14] lm32: add Milkymist AC97 support
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 01/14] lm32: add Milkymist AC97 support Michael Walle
@ 2011-03-16 16:50   ` Alexander Graf
  2011-03-16 18:12     ` malc
  0 siblings, 1 reply; 23+ messages in thread
From: Alexander Graf @ 2011-03-16 16:50 UTC (permalink / raw)
  To: Michael Walle; +Cc: Edgar E. Iglesias, qemu-devel

On 03/07/2011 11:32 PM, Michael Walle wrote:
> This patch adds support for the Milkymist AC97 compatible sound output and
> input core.

Malc, could you please take a look at this? :)

> Signed-off-by: Michael Walle<michael@walle.cc>
> ---
>   Makefile.target     |    1 +
>   configure           |    3 +
>   hw/milkymist-ac97.c |  335 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   trace-events        |   12 ++
>   4 files changed, 351 insertions(+), 0 deletions(-)
>   create mode 100644 hw/milkymist-ac97.c
>
> diff --git a/Makefile.target b/Makefile.target
> index f0df98e..3be7868 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -256,6 +256,7 @@ obj-lm32-y += lm32_juart.o
>   obj-lm32-y += lm32_timer.o
>   obj-lm32-y += lm32_uart.o
>   obj-lm32-y += lm32_sys.o
> +obj-lm32-y += milkymist-ac97.o
>
>   obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
>   obj-mips-y += mips_addr.o mips_timer.o mips_int.o
> diff --git a/configure b/configure
> index 5513d3e..e75e1a2 100755
> --- a/configure
> +++ b/configure
> @@ -3281,6 +3281,9 @@ if test "$target_softmmu" = "yes" ; then
>     arm)
>       cflags="-DHAS_AUDIO $cflags"
>     ;;
> +  lm32)
> +    cflags="-DHAS_AUDIO $cflags"
> +  ;;
>     i386|mips|ppc)
>       cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
>     ;;
> diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
> new file mode 100644
> index 0000000..6c9e318
> --- /dev/null
> +++ b/hw/milkymist-ac97.c
> @@ -0,0 +1,335 @@
> +/*
> + *  QEMU model of the Milkymist System Controller.
> + *
> + *  Copyright (c) 2010 Michael Walle<michael@walle.cc>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see<http://www.gnu.org/licenses/>.
> + *
> + *
> + * Specification available at:
> + *   http://www.milkymist.org/socdoc/ac97.pdf
> + */
> +
> +#include "hw.h"
> +#include "sysbus.h"
> +#include "trace.h"
> +#include "audio/audio.h"
> +#include "qemu-error.h"
> +
> +enum {
> +    R_AC97_CTRL = 0,
> +    R_AC97_ADDR,
> +    R_AC97_DATAOUT,
> +    R_AC97_DATAIN,
> +    R_D_CTRL,
> +    R_D_ADDR,
> +    R_D_REMAINING,
> +    R_RESERVED,
> +    R_U_CTRL,
> +    R_U_ADDR,
> +    R_U_REMAINING,
> +    R_MAX
> +};
> +
> +enum {
> +    AC97_CTRL_RQEN  = (1<<0),
> +    AC97_CTRL_WRITE = (1<<1),
> +};
> +
> +enum {
> +    CTRL_EN = (1<<0),
> +};
> +
> +struct MilkymistAC97State {
> +    SysBusDevice busdev;
> +
> +    QEMUSoundCard card;
> +    SWVoiceIn *voice_in;
> +    SWVoiceOut *voice_out;
> +
> +    uint32_t regs[R_MAX];
> +
> +    qemu_irq crrequest_irq;
> +    qemu_irq crreply_irq;
> +    qemu_irq dmar_irq;
> +    qemu_irq dmaw_irq;
> +};
> +typedef struct MilkymistAC97State MilkymistAC97State;
> +
> +static void update_voices(MilkymistAC97State *s)
> +{
> +    if (s->regs[R_D_CTRL]&  CTRL_EN) {
> +        AUD_set_active_out(s->voice_out, 1);
> +    } else {
> +        AUD_set_active_out(s->voice_out, 0);
> +    }
> +
> +    if (s->regs[R_U_CTRL]&  CTRL_EN) {
> +        AUD_set_active_in(s->voice_in, 1);
> +    } else {
> +        AUD_set_active_in(s->voice_in, 0);
> +    }
> +}
> +
> +static uint32_t ac97_read(void *opaque, target_phys_addr_t addr)
> +{
> +    MilkymistAC97State *s = opaque;
> +    uint32_t r = 0;
> +
> +    addr>>= 2;
> +    switch (addr) {
> +    case R_AC97_CTRL:
> +    case R_AC97_ADDR:
> +    case R_AC97_DATAOUT:
> +    case R_AC97_DATAIN:
> +    case R_D_CTRL:
> +    case R_D_ADDR:
> +    case R_D_REMAINING:
> +    case R_U_CTRL:
> +    case R_U_ADDR:
> +    case R_U_REMAINING:
> +        r = s->regs[addr];
> +        break;
> +
> +    default:
> +        error_report("milkymist_ac97: read access to unkown register 0x"
> +                TARGET_FMT_plx, addr<<  2);
> +        break;
> +    }
> +
> +    trace_milkymist_ac97_memory_read(addr<<  2, r);
> +
> +    return r;
> +}
> +
> +static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value)
> +{
> +    MilkymistAC97State *s = opaque;
> +
> +    trace_milkymist_ac97_memory_write(addr, value);
> +
> +    addr>>= 2;
> +    switch (addr) {
> +    case R_AC97_CTRL:
> +        /* always raise an IRQ according to the direction */
> +        if (value&  AC97_CTRL_RQEN) {
> +            if (value&  AC97_CTRL_WRITE) {
> +                trace_milkymist_ac97_pulse_irq_crrequest();
> +                qemu_irq_pulse(s->crrequest_irq);
> +            } else {
> +                trace_milkymist_ac97_pulse_irq_crreply();
> +                qemu_irq_pulse(s->crreply_irq);
> +            }
> +        }
> +
> +        /* RQEN is self clearing */
> +        s->regs[addr] = value&  ~AC97_CTRL_RQEN;
> +        break;
> +    case R_D_CTRL:
> +    case R_U_CTRL:
> +        s->regs[addr] = value;
> +        update_voices(s);
> +        break;
> +    case R_AC97_ADDR:
> +    case R_AC97_DATAOUT:
> +    case R_AC97_DATAIN:
> +    case R_D_ADDR:
> +    case R_D_REMAINING:
> +    case R_U_ADDR:
> +    case R_U_REMAINING:
> +        s->regs[addr] = value;
> +        break;
> +
> +    default:
> +        error_report("milkymist_ac97: write access to unkown register 0x"
> +                TARGET_FMT_plx, addr);
> +        break;
> +    }
> +
> +}
> +
> +static CPUReadMemoryFunc * const ac97_read_fn[] = {
> +    NULL,
> +    NULL,
> +&ac97_read,
> +};
> +
> +static CPUWriteMemoryFunc * const ac97_write_fn[] = {
> +    NULL,
> +    NULL,
> +&ac97_write,
> +};
> +
> +static void ac97_in_cb(void *opaque, int avail_b)
> +{
> +    MilkymistAC97State *s = opaque;
> +    uint8_t buf[4096];
> +    uint32_t remaining = s->regs[R_U_REMAINING];
> +    int temp = audio_MIN(remaining, avail_b);
> +    uint32_t addr = s->regs[R_U_ADDR];
> +    int transferred = 0;
> +
> +    trace_milkymist_ac97_in_cb(avail_b, remaining);
> +
> +    /* prevent from raising an IRQ */
> +    if (temp == 0) {
> +        return;
> +    }
> +
> +    while (temp) {
> +        int acquired, to_copy;
> +
> +        to_copy = audio_MIN(temp, sizeof(buf));
> +        acquired = AUD_read(s->voice_in, buf, to_copy);
> +        if (!acquired) {
> +            break;
> +        }
> +
> +        cpu_physical_memory_write(addr, buf, acquired);
> +
> +        temp -= acquired;
> +        addr += acquired;
> +        transferred += acquired;
> +    }
> +
> +    trace_milkymist_ac97_in_cb_transferred(transferred);
> +
> +    s->regs[R_U_ADDR] = addr;
> +    s->regs[R_U_REMAINING] -= transferred;
> +
> +    if ((s->regs[R_U_CTRL]&  CTRL_EN)&&  (s->regs[R_U_REMAINING] == 0)) {
> +        trace_milkymist_ac97_pulse_irq_dmaw();
> +        qemu_irq_pulse(s->dmaw_irq);
> +    }
> +}
> +
> +static void ac97_out_cb(void *opaque, int free_b)
> +{
> +    MilkymistAC97State *s = opaque;
> +    uint8_t buf[4096];
> +    uint32_t remaining = s->regs[R_D_REMAINING];
> +    int temp = audio_MIN(remaining, free_b);
> +    uint32_t addr = s->regs[R_D_ADDR];
> +    int transferred = 0;
> +
> +    trace_milkymist_ac97_out_cb(free_b, remaining);
> +
> +    /* prevent from raising an IRQ */
> +    if (temp == 0) {
> +        return;
> +    }
> +
> +    while (temp) {
> +        int copied, to_copy;
> +
> +        to_copy = audio_MIN(temp, sizeof(buf));
> +        cpu_physical_memory_read(addr, buf, to_copy);
> +        copied = AUD_write(s->voice_out, buf, to_copy);
> +        if (!copied) {
> +            break;
> +        }
> +        temp -= copied;
> +        addr += copied;
> +        transferred += copied;
> +    }
> +
> +    trace_milkymist_ac97_out_cb_transferred(transferred);
> +
> +    s->regs[R_D_ADDR] = addr;
> +    s->regs[R_D_REMAINING] -= transferred;
> +
> +    if ((s->regs[R_D_CTRL]&  CTRL_EN)&&  (s->regs[R_D_REMAINING] == 0)) {
> +        trace_milkymist_ac97_pulse_irq_dmar();
> +        qemu_irq_pulse(s->dmar_irq);
> +    }
> +}
> +
> +static void milkymist_ac97_reset(DeviceState *d)
> +{
> +    MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev);
> +    int i;
> +
> +    for (i = 0; i<  R_MAX; i++) {
> +        s->regs[i] = 0;
> +    }
> +
> +    AUD_set_active_in(s->voice_in, 0);
> +    AUD_set_active_out(s->voice_out, 0);
> +}
> +
> +static int ac97_post_load(void *opaque, int version_id)
> +{
> +    MilkymistAC97State *s = opaque;
> +
> +    update_voices(s);
> +
> +    return 0;
> +}
> +
> +static int milkymist_ac97_init(SysBusDevice *dev)
> +{
> +    MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
> +    int ac97_regs;
> +
> +    struct audsettings as;
> +    sysbus_init_irq(dev,&s->crrequest_irq);
> +    sysbus_init_irq(dev,&s->crreply_irq);
> +    sysbus_init_irq(dev,&s->dmar_irq);
> +    sysbus_init_irq(dev,&s->dmaw_irq);
> +
> +    AUD_register_card("Milkymist AC'97",&s->card);
> +
> +    as.freq = 48000;
> +    as.nchannels = 2;
> +    as.fmt = AUD_FMT_S16;
> +    as.endianness = 1;
> +
> +    s->voice_in = AUD_open_in(&s->card, s->voice_in,
> +            "mm_ac97.in", s, ac97_in_cb,&as);
> +    s->voice_out = AUD_open_out(&s->card, s->voice_out,
> +            "mm_ac97.out", s, ac97_out_cb,&as);
> +
> +    ac97_regs = cpu_register_io_memory(ac97_read_fn, ac97_write_fn, s,
> +            DEVICE_NATIVE_ENDIAN);
> +    sysbus_init_mmio(dev, R_MAX * 4, ac97_regs);
> +
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_milkymist_ac97 = {
> +    .name = "milkymist-ac97",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .post_load = ac97_post_load,
> +    .fields      = (VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static SysBusDeviceInfo milkymist_ac97_info = {
> +    .init = milkymist_ac97_init,
> +    .qdev.name  = "milkymist-ac97",
> +    .qdev.size  = sizeof(MilkymistAC97State),
> +    .qdev.vmsd  =&vmstate_milkymist_ac97,
> +    .qdev.reset = milkymist_ac97_reset,
> +};
> +
> +static void milkymist_ac97_register(void)
> +{
> +    sysbus_register_withprop(&milkymist_ac97_info);
> +}
> +
> +device_init(milkymist_ac97_register)
> diff --git a/trace-events b/trace-events
> index c791719..9241ac9 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -283,3 +283,15 @@ disable lm32_uart_irq_state(int level) "irq state %d"
>
>   # hw/lm32_sys.c
>   disable lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
> +
> +# hw/milkymist-ac97.c
> +disable milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
> +disable milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
> +disable milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
> +disable milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
> +disable milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
> +disable milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
> +disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u"
> +disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
> +disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
> +disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"

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

* [Qemu-devel] Re: [PATCH 00/14] lm32: Milkymist board support
  2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
                   ` (13 preceding siblings ...)
  2011-03-07 22:32 ` [Qemu-devel] [PATCH 14/14] MAINTAINERS: add " Michael Walle
@ 2011-03-16 17:08 ` Alexander Graf
  2011-03-24  9:28   ` Alexander Graf
  14 siblings, 1 reply; 23+ messages in thread
From: Alexander Graf @ 2011-03-16 17:08 UTC (permalink / raw)
  To: Michael Walle; +Cc: Edgar E. Iglesias, qemu-devel

On 03/07/2011 11:32 PM, Michael Walle wrote:
> This is the second (and last) patchset of the LatticeMico32 support. It
> adds almost complete support for the opensource and openhardware Milkymist
> One board [1].
>
> [1] http://www.milkymist.org/mmone.html
>

 From my side you get:

Acked-by: Alexander Graf <agraf@suse.de>

But it'd be great if the respective subsystem maintainers could also 
take a look at code affecting them.

Alex

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

* [Qemu-devel] Re: [PATCH 01/14] lm32: add Milkymist AC97 support
  2011-03-16 16:50   ` [Qemu-devel] " Alexander Graf
@ 2011-03-16 18:12     ` malc
  2011-03-16 23:02       ` Michael Walle
  0 siblings, 1 reply; 23+ messages in thread
From: malc @ 2011-03-16 18:12 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Edgar E. Iglesias, Michael Walle, qemu-devel

On Wed, 16 Mar 2011, Alexander Graf wrote:

> On 03/07/2011 11:32 PM, Michael Walle wrote:
> > This patch adds support for the Milkymist AC97 compatible sound output and
> > input core.
> 
> Malc, could you please take a look at this? :)

Okay...

> 
> > Signed-off-by: Michael Walle<michael@walle.cc>
> > ---
> >   Makefile.target     |    1 +
> >   configure           |    3 +
> >   hw/milkymist-ac97.c |  335
> > +++++++++++++++++++++++++++++++++++++++++++++++++++
> >   trace-events        |   12 ++
> >   4 files changed, 351 insertions(+), 0 deletions(-)
> >   create mode 100644 hw/milkymist-ac97.c
> > 
> > diff --git a/Makefile.target b/Makefile.target
> > index f0df98e..3be7868 100644
> > --- a/Makefile.target
> > +++ b/Makefile.target
> > @@ -256,6 +256,7 @@ obj-lm32-y += lm32_juart.o
> >   obj-lm32-y += lm32_timer.o
> >   obj-lm32-y += lm32_uart.o
> >   obj-lm32-y += lm32_sys.o
> > +obj-lm32-y += milkymist-ac97.o
> > 
> >   obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
> >   obj-mips-y += mips_addr.o mips_timer.o mips_int.o
> > diff --git a/configure b/configure
> > index 5513d3e..e75e1a2 100755
> > --- a/configure
> > +++ b/configure
> > @@ -3281,6 +3281,9 @@ if test "$target_softmmu" = "yes" ; then
> >     arm)
> >       cflags="-DHAS_AUDIO $cflags"
> >     ;;
> > +  lm32)
> > +    cflags="-DHAS_AUDIO $cflags"
> > +  ;;
> >     i386|mips|ppc)
> >       cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
> >     ;;
> > diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
> > new file mode 100644
> > index 0000000..6c9e318
> > --- /dev/null
> > +++ b/hw/milkymist-ac97.c
> > @@ -0,0 +1,335 @@
> > +/*
> > + *  QEMU model of the Milkymist System Controller.
> > + *
> > + *  Copyright (c) 2010 Michael Walle<michael@walle.cc>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not,
> > see<http://www.gnu.org/licenses/>.
> > + *
> > + *
> > + * Specification available at:
> > + *   http://www.milkymist.org/socdoc/ac97.pdf
> > + */
> > +
> > +#include "hw.h"
> > +#include "sysbus.h"
> > +#include "trace.h"
> > +#include "audio/audio.h"
> > +#include "qemu-error.h"
> > +
> > +enum {
> > +    R_AC97_CTRL = 0,

Unneeded..

> > +    R_AC97_ADDR,
> > +    R_AC97_DATAOUT,
> > +    R_AC97_DATAIN,
> > +    R_D_CTRL,
> > +    R_D_ADDR,
> > +    R_D_REMAINING,
> > +    R_RESERVED,
> > +    R_U_CTRL,
> > +    R_U_ADDR,
> > +    R_U_REMAINING,
> > +    R_MAX
> > +};
> > +
> > +enum {
> > +    AC97_CTRL_RQEN  = (1<<0),

Oookay..

> > +    AC97_CTRL_WRITE = (1<<1),

Incinsistent(with previous enum formatting) comma (and C99 only at that)

> > +};
> > +
> > +enum {
> > +    CTRL_EN = (1<<0),

Ditto x2

> > +};
> > +
> > +struct MilkymistAC97State {
> > +    SysBusDevice busdev;
> > +
> > +    QEMUSoundCard card;
> > +    SWVoiceIn *voice_in;
> > +    SWVoiceOut *voice_out;
> > +
> > +    uint32_t regs[R_MAX];
> > +
> > +    qemu_irq crrequest_irq;
> > +    qemu_irq crreply_irq;
> > +    qemu_irq dmar_irq;
> > +    qemu_irq dmaw_irq;
> > +};
> > +typedef struct MilkymistAC97State MilkymistAC97State;
> > +
> > +static void update_voices(MilkymistAC97State *s)
> > +{
> > +    if (s->regs[R_D_CTRL]&  CTRL_EN) {

Space before ampersand would be nice.

> > +        AUD_set_active_out(s->voice_out, 1);
> > +    } else {
> > +        AUD_set_active_out(s->voice_out, 0);
> > +    }
> > +
> > +    if (s->regs[R_U_CTRL]&  CTRL_EN) {
> > +        AUD_set_active_in(s->voice_in, 1);
> > +    } else {
> > +        AUD_set_active_in(s->voice_in, 0);
> > +    }
> > +}
> > +
> > +static uint32_t ac97_read(void *opaque, target_phys_addr_t addr)
> > +{
> > +    MilkymistAC97State *s = opaque;
> > +    uint32_t r = 0;
> > +
> > +    addr>>= 2;

Again space here and elsewhere.

> > +    switch (addr) {
> > +    case R_AC97_CTRL:
> > +    case R_AC97_ADDR:
> > +    case R_AC97_DATAOUT:
> > +    case R_AC97_DATAIN:
> > +    case R_D_CTRL:
> > +    case R_D_ADDR:
> > +    case R_D_REMAINING:
> > +    case R_U_CTRL:
> > +    case R_U_ADDR:
> > +    case R_U_REMAINING:
> > +        r = s->regs[addr];
> > +        break;
> > +
> > +    default:
> > +        error_report("milkymist_ac97: read access to unkown register 0x"
> > +                TARGET_FMT_plx, addr<<  2);
> > +        break;
> > +    }
> > +
> > +    trace_milkymist_ac97_memory_read(addr<<  2, r);
> > +
> > +    return r;
> > +}
> > +
> > +static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t
> > value)
> > +{
> > +    MilkymistAC97State *s = opaque;
> > +
> > +    trace_milkymist_ac97_memory_write(addr, value);
> > +
> > +    addr>>= 2;
> > +    switch (addr) {
> > +    case R_AC97_CTRL:
> > +        /* always raise an IRQ according to the direction */
> > +        if (value&  AC97_CTRL_RQEN) {
> > +            if (value&  AC97_CTRL_WRITE) {
> > +                trace_milkymist_ac97_pulse_irq_crrequest();
> > +                qemu_irq_pulse(s->crrequest_irq);
> > +            } else {
> > +                trace_milkymist_ac97_pulse_irq_crreply();
> > +                qemu_irq_pulse(s->crreply_irq);
> > +            }
> > +        }
> > +
> > +        /* RQEN is self clearing */
> > +        s->regs[addr] = value&  ~AC97_CTRL_RQEN;
> > +        break;
> > +    case R_D_CTRL:
> > +    case R_U_CTRL:
> > +        s->regs[addr] = value;
> > +        update_voices(s);
> > +        break;
> > +    case R_AC97_ADDR:
> > +    case R_AC97_DATAOUT:
> > +    case R_AC97_DATAIN:
> > +    case R_D_ADDR:
> > +    case R_D_REMAINING:
> > +    case R_U_ADDR:
> > +    case R_U_REMAINING:
> > +        s->regs[addr] = value;
> > +        break;
> > +
> > +    default:
> > +        error_report("milkymist_ac97: write access to unkown register 0x"
> > +                TARGET_FMT_plx, addr);
> > +        break;
> > +    }
> > +
> > +}
> > +
> > +static CPUReadMemoryFunc * const ac97_read_fn[] = {
> > +    NULL,
> > +    NULL,
> > +&ac97_read,
> > +};
> > +
> > +static CPUWriteMemoryFunc * const ac97_write_fn[] = {
> > +    NULL,
> > +    NULL,
> > +&ac97_write,
> > +};
> > +
> > +static void ac97_in_cb(void *opaque, int avail_b)
> > +{
> > +    MilkymistAC97State *s = opaque;
> > +    uint8_t buf[4096];
> > +    uint32_t remaining = s->regs[R_U_REMAINING];
> > +    int temp = audio_MIN(remaining, avail_b);
> > +    uint32_t addr = s->regs[R_U_ADDR];
> > +    int transferred = 0;
> > +
> > +    trace_milkymist_ac97_in_cb(avail_b, remaining);
> > +
> > +    /* prevent from raising an IRQ */
> > +    if (temp == 0) {
> > +        return;
> > +    }
> > +
> > +    while (temp) {
> > +        int acquired, to_copy;
> > +
> > +        to_copy = audio_MIN(temp, sizeof(buf));
> > +        acquired = AUD_read(s->voice_in, buf, to_copy);
> > +        if (!acquired) {
> > +            break;
> > +        }
> > +
> > +        cpu_physical_memory_write(addr, buf, acquired);
> > +
> > +        temp -= acquired;
> > +        addr += acquired;
> > +        transferred += acquired;
> > +    }
> > +
> > +    trace_milkymist_ac97_in_cb_transferred(transferred);
> > +
> > +    s->regs[R_U_ADDR] = addr;
> > +    s->regs[R_U_REMAINING] -= transferred;
> > +
> > +    if ((s->regs[R_U_CTRL]&  CTRL_EN)&&  (s->regs[R_U_REMAINING] == 0)) {
> > +        trace_milkymist_ac97_pulse_irq_dmaw();
> > +        qemu_irq_pulse(s->dmaw_irq);
> > +    }
> > +}
> > +
> > +static void ac97_out_cb(void *opaque, int free_b)
> > +{
> > +    MilkymistAC97State *s = opaque;
> > +    uint8_t buf[4096];
> > +    uint32_t remaining = s->regs[R_D_REMAINING];
> > +    int temp = audio_MIN(remaining, free_b);
> > +    uint32_t addr = s->regs[R_D_ADDR];
> > +    int transferred = 0;
> > +
> > +    trace_milkymist_ac97_out_cb(free_b, remaining);
> > +
> > +    /* prevent from raising an IRQ */
> > +    if (temp == 0) {
> > +        return;
> > +    }
> > +
> > +    while (temp) {
> > +        int copied, to_copy;
> > +
> > +        to_copy = audio_MIN(temp, sizeof(buf));
> > +        cpu_physical_memory_read(addr, buf, to_copy);
> > +        copied = AUD_write(s->voice_out, buf, to_copy);
> > +        if (!copied) {
> > +            break;
> > +        }
> > +        temp -= copied;
> > +        addr += copied;
> > +        transferred += copied;
> > +    }
> > +
> > +    trace_milkymist_ac97_out_cb_transferred(transferred);
> > +
> > +    s->regs[R_D_ADDR] = addr;
> > +    s->regs[R_D_REMAINING] -= transferred;
> > +
> > +    if ((s->regs[R_D_CTRL]&  CTRL_EN)&&  (s->regs[R_D_REMAINING] == 0)) {
> > +        trace_milkymist_ac97_pulse_irq_dmar();
> > +        qemu_irq_pulse(s->dmar_irq);
> > +    }
> > +}
> > +
> > +static void milkymist_ac97_reset(DeviceState *d)
> > +{
> > +    MilkymistAC97State *s = container_of(d, MilkymistAC97State,
> > busdev.qdev);
> > +    int i;
> > +
> > +    for (i = 0; i<  R_MAX; i++) {
> > +        s->regs[i] = 0;
> > +    }
> > +
> > +    AUD_set_active_in(s->voice_in, 0);
> > +    AUD_set_active_out(s->voice_out, 0);
> > +}
> > +
> > +static int ac97_post_load(void *opaque, int version_id)
> > +{
> > +    MilkymistAC97State *s = opaque;
> > +
> > +    update_voices(s);
> > +
> > +    return 0;
> > +}
> > +
> > +static int milkymist_ac97_init(SysBusDevice *dev)
> > +{
> > +    MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
> > +    int ac97_regs;
> > +
> > +    struct audsettings as;
> > +    sysbus_init_irq(dev,&s->crrequest_irq);
> > +    sysbus_init_irq(dev,&s->crreply_irq);
> > +    sysbus_init_irq(dev,&s->dmar_irq);
> > +    sysbus_init_irq(dev,&s->dmaw_irq);
> > +
> > +    AUD_register_card("Milkymist AC'97",&s->card);
> > +
> > +    as.freq = 48000;
> > +    as.nchannels = 2;
> > +    as.fmt = AUD_FMT_S16;
> > +    as.endianness = 1;
> > +
> > +    s->voice_in = AUD_open_in(&s->card, s->voice_in,
> > +            "mm_ac97.in", s, ac97_in_cb,&as);
> > +    s->voice_out = AUD_open_out(&s->card, s->voice_out,
> > +            "mm_ac97.out", s, ac97_out_cb,&as);
> > +
> > +    ac97_regs = cpu_register_io_memory(ac97_read_fn, ac97_write_fn, s,
> > +            DEVICE_NATIVE_ENDIAN);
> > +    sysbus_init_mmio(dev, R_MAX * 4, ac97_regs);
> > +
> > +    return 0;
> > +}
> > +
> > +static const VMStateDescription vmstate_milkymist_ac97 = {
> > +    .name = "milkymist-ac97",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .minimum_version_id_old = 1,
> > +    .post_load = ac97_post_load,
> > +    .fields      = (VMStateField[]) {
> > +        VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static SysBusDeviceInfo milkymist_ac97_info = {
> > +    .init = milkymist_ac97_init,
> > +    .qdev.name  = "milkymist-ac97",
> > +    .qdev.size  = sizeof(MilkymistAC97State),
> > +    .qdev.vmsd  =&vmstate_milkymist_ac97,
> > +    .qdev.reset = milkymist_ac97_reset,
> > +};
> > +
> > +static void milkymist_ac97_register(void)
> > +{
> > +    sysbus_register_withprop(&milkymist_ac97_info);
> > +}
> > +
> > +device_init(milkymist_ac97_register)
> > diff --git a/trace-events b/trace-events
> > index c791719..9241ac9 100644
> > --- a/trace-events
> > +++ b/trace-events
> > @@ -283,3 +283,15 @@ disable lm32_uart_irq_state(int level) "irq state %d"
> > 
> >   # hw/lm32_sys.c
> >   disable lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x
> > value 0x%08x"
> > +
> > +# hw/milkymist-ac97.c
> > +disable milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr
> > %08x value %08x"
> > +disable milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr
> > %08x value %08x"
> > +disable milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
> > +disable milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
> > +disable milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
> > +disable milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
> > +disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d
> > remaining %u"
> > +disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
> > +disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d
> > remaining %u"
> > +disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
> 

IOW looks good to me.

-- 
mailto:av1474@comtv.ru

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

* [Qemu-devel] Re: [PATCH 01/14] lm32: add Milkymist AC97 support
  2011-03-16 18:12     ` malc
@ 2011-03-16 23:02       ` Michael Walle
  2011-03-16 23:49         ` Alexander Graf
  2011-03-17  0:10         ` malc
  0 siblings, 2 replies; 23+ messages in thread
From: Michael Walle @ 2011-03-16 23:02 UTC (permalink / raw)
  To: malc; +Cc: Edgar E. Iglesias, Alexander Graf, qemu-devel

Am Mittwoch 16 März 2011, 19:12:44 schrieb malc:
> > > diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
> > > new file mode 100644
> > > index 0000000..6c9e318
> > > --- /dev/null
> > > +++ b/hw/milkymist-ac97.c
> > > @@ -0,0 +1,335 @@
> > > +/*
> > > + *  QEMU model of the Milkymist System Controller.
> > > + *
> > > + *  Copyright (c) 2010 Michael Walle<michael@walle.cc>
> > > + *
> > > + * This library is free software; you can redistribute it and/or
> > > + * modify it under the terms of the GNU Lesser General Public
> > > + * License as published by the Free Software Foundation; either
> > > + * version 2 of the License, or (at your option) any later version.
> > > + *
> > > + * This library is distributed in the hope that it will be useful,
> > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > > + * Lesser General Public License for more details.
> > > + *
> > > + * You should have received a copy of the GNU Lesser General Public
> > > + * License along with this library; if not,
> > > see<http://www.gnu.org/licenses/>.
> > > + *
> > > + *
> > > + * Specification available at:
> > > + *   http://www.milkymist.org/socdoc/ac97.pdf
> > > + */
> > > +
> > > +#include "hw.h"
> > > +#include "sysbus.h"
> > > +#include "trace.h"
> > > +#include "audio/audio.h"
> > > +#include "qemu-error.h"
> > > +
> > > +enum {
> > > +    R_AC97_CTRL = 0,
> 
> Unneeded..
I wanted to point out, that the registers begin at offset 0. If i change this, 
i'll need to change all other models, too. Including the ones that have been 
committed.

> > > +    R_AC97_ADDR,
> > > +    R_AC97_DATAOUT,
> > > +    R_AC97_DATAIN,
> > > +    R_D_CTRL,
> > > +    R_D_ADDR,
> > > +    R_D_REMAINING,
> > > +    R_RESERVED,
> > > +    R_U_CTRL,
> > > +    R_U_ADDR,
> > > +    R_U_REMAINING,
> > > +    R_MAX
> > > +};
> > > +
> > > +enum {
> > > +    AC97_CTRL_RQEN  = (1<<0),
> 
> Oookay..
> 
> > > +    AC97_CTRL_WRITE = (1<<1),
> 
> Incinsistent(with previous enum formatting) comma (and C99 only at that)
> 
> > > +};
> > > +
> > > +enum {
> > > +    CTRL_EN = (1<<0),
> 
> Ditto x2
Ok, but it has a hidden agenda. R_MAX must always be the last entry, therefore 
i omitted the comma. Whereas the bit flags could still be extended. Again if 
this is a concern for you, i'll change that and all other models too.

> > > +};
> > > +
> > > +struct MilkymistAC97State {
> > > +    SysBusDevice busdev;
> > > +
> > > +    QEMUSoundCard card;
> > > +    SWVoiceIn *voice_in;
> > > +    SWVoiceOut *voice_out;
> > > +
> > > +    uint32_t regs[R_MAX];
> > > +
> > > +    qemu_irq crrequest_irq;
> > > +    qemu_irq crreply_irq;
> > > +    qemu_irq dmar_irq;
> > > +    qemu_irq dmaw_irq;
> > > +};
> > > +typedef struct MilkymistAC97State MilkymistAC97State;
> > > +
> > > +static void update_voices(MilkymistAC97State *s)
> > > +{
> > > +    if (s->regs[R_D_CTRL]&  CTRL_EN) {
> 
> Space before ampersand would be nice.
mh i think Alex email client messed this up. At least for me, there is one 
space before and one space after the ampersand in my original email.

-- 
Michael

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

* [Qemu-devel] Re: [PATCH 01/14] lm32: add Milkymist AC97 support
  2011-03-16 23:02       ` Michael Walle
@ 2011-03-16 23:49         ` Alexander Graf
  2011-03-17  0:10         ` malc
  1 sibling, 0 replies; 23+ messages in thread
From: Alexander Graf @ 2011-03-16 23:49 UTC (permalink / raw)
  To: Michael Walle; +Cc: Edgar E. Iglesias, qemu-devel@nongnu.org





On 17.03.2011, at 00:02, Michael Walle <michael@walle.cc> wrote:

> Am Mittwoch 16 März 2011, 19:12:44 schrieb malc:
>>>> diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
>>>> new file mode 100644
>>>> index 0000000..6c9e318
>>>> --- /dev/null
>>>> +++ b/hw/milkymist-ac97.c
>>>> @@ -0,0 +1,335 @@
>>>> +/*
>>>> + *  QEMU model of the Milkymist System Controller.
>>>> + *
>>>> + *  Copyright (c) 2010 Michael Walle<michael@walle.cc>
>>>> + *
>>>> + * This library is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU Lesser General Public
>>>> + * License as published by the Free Software Foundation; either
>>>> + * version 2 of the License, or (at your option) any later version.
>>>> + *
>>>> + * This library is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> + * Lesser General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU Lesser General Public
>>>> + * License along with this library; if not,
>>>> see<http://www.gnu.org/licenses/>.
>>>> + *
>>>> + *
>>>> + * Specification available at:
>>>> + *   http://www.milkymist.org/socdoc/ac97.pdf
>>>> + */
>>>> +
>>>> +#include "hw.h"
>>>> +#include "sysbus.h"
>>>> +#include "trace.h"
>>>> +#include "audio/audio.h"
>>>> +#include "qemu-error.h"
>>>> +
>>>> +enum {
>>>> +    R_AC97_CTRL = 0,
>> 
>> Unneeded..
> I wanted to point out, that the registers begin at offset 0. If i change this, 
> i'll need to change all other models, too. Including the ones that have been 
> committed.
> 
>>>> +    R_AC97_ADDR,
>>>> +    R_AC97_DATAOUT,
>>>> +    R_AC97_DATAIN,
>>>> +    R_D_CTRL,
>>>> +    R_D_ADDR,
>>>> +    R_D_REMAINING,
>>>> +    R_RESERVED,
>>>> +    R_U_CTRL,
>>>> +    R_U_ADDR,
>>>> +    R_U_REMAINING,
>>>> +    R_MAX
>>>> +};
>>>> +
>>>> +enum {
>>>> +    AC97_CTRL_RQEN  = (1<<0),
>> 
>> Oookay..
>> 
>>>> +    AC97_CTRL_WRITE = (1<<1),
>> 
>> Incinsistent(with previous enum formatting) comma (and C99 only at that)
>> 
>>>> +};
>>>> +
>>>> +enum {
>>>> +    CTRL_EN = (1<<0),
>> 
>> Ditto x2
> Ok, but it has a hidden agenda. R_MAX must always be the last entry, therefore 
> i omitted the comma. Whereas the bit flags could still be extended. Again if 
> this is a concern for you, i'll change that and all other models too.
> 
>>>> +};
>>>> +
>>>> +struct MilkymistAC97State {
>>>> +    SysBusDevice busdev;
>>>> +
>>>> +    QEMUSoundCard card;
>>>> +    SWVoiceIn *voice_in;
>>>> +    SWVoiceOut *voice_out;
>>>> +
>>>> +    uint32_t regs[R_MAX];
>>>> +
>>>> +    qemu_irq crrequest_irq;
>>>> +    qemu_irq crreply_irq;
>>>> +    qemu_irq dmar_irq;
>>>> +    qemu_irq dmaw_irq;
>>>> +};
>>>> +typedef struct MilkymistAC97State MilkymistAC97State;
>>>> +
>>>> +static void update_voices(MilkymistAC97State *s)
>>>> +{
>>>> +    if (s->regs[R_D_CTRL]&  CTRL_EN) {
>> 
>> Space before ampersand would be nice.
> mh i think Alex email client messed this up. At least for me, there is one 
> space before and one space after the ampersand in my original email.

Yes, thunderbird breaks those. Sorry :).

Alex

> 
> -- 
> Michael

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

* [Qemu-devel] Re: [PATCH 01/14] lm32: add Milkymist AC97 support
  2011-03-16 23:02       ` Michael Walle
  2011-03-16 23:49         ` Alexander Graf
@ 2011-03-17  0:10         ` malc
  1 sibling, 0 replies; 23+ messages in thread
From: malc @ 2011-03-17  0:10 UTC (permalink / raw)
  To: Michael Walle; +Cc: Edgar E. Iglesias, Alexander Graf, qemu-devel

On Thu, 17 Mar 2011, Michael Walle wrote:

> Am Mittwoch 16 M?rz 2011, 19:12:44 schrieb malc:
> > > > diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
> > > > new file mode 100644
> > > > index 0000000..6c9e318
> > > > --- /dev/null
> > > > +++ b/hw/milkymist-ac97.c
> > > > @@ -0,0 +1,335 @@
> > > > +/*
> > > > + *  QEMU model of the Milkymist System Controller.
> > > > + *
> > > > + *  Copyright (c) 2010 Michael Walle<michael@walle.cc>
> > > > + *
> > > > + * This library is free software; you can redistribute it and/or
> > > > + * modify it under the terms of the GNU Lesser General Public
> > > > + * License as published by the Free Software Foundation; either
> > > > + * version 2 of the License, or (at your option) any later version.
> > > > + *
> > > > + * This library is distributed in the hope that it will be useful,
> > > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > > > + * Lesser General Public License for more details.
> > > > + *
> > > > + * You should have received a copy of the GNU Lesser General Public
> > > > + * License along with this library; if not,
> > > > see<http://www.gnu.org/licenses/>.
> > > > + *
> > > > + *
> > > > + * Specification available at:
> > > > + *   http://www.milkymist.org/socdoc/ac97.pdf
> > > > + */
> > > > +
> > > > +#include "hw.h"
> > > > +#include "sysbus.h"
> > > > +#include "trace.h"
> > > > +#include "audio/audio.h"
> > > > +#include "qemu-error.h"
> > > > +
> > > > +enum {
> > > > +    R_AC97_CTRL = 0,
> > 
> > Unneeded..
> I wanted to point out, that the registers begin at offset 0. If i change 
> this, i'll need to change all other models, too. Including the ones that 
> have been committed.

And i just wanted to nitpick that it would be zero even without '= 0' part
(6.7.2.2#3 of ISO/IEC 9899:201x)

> 
> > > > +    R_AC97_ADDR,
> > > > +    R_AC97_DATAOUT,
> > > > +    R_AC97_DATAIN,
> > > > +    R_D_CTRL,
> > > > +    R_D_ADDR,
> > > > +    R_D_REMAINING,
> > > > +    R_RESERVED,
> > > > +    R_U_CTRL,
> > > > +    R_U_ADDR,
> > > > +    R_U_REMAINING,
> > > > +    R_MAX
> > > > +};
> > > > +
> > > > +enum {
> > > > +    AC97_CTRL_RQEN  = (1<<0),
> > 
> > Oookay..
> > 
> > > > +    AC97_CTRL_WRITE = (1<<1),
> > 
> > Incinsistent(with previous enum formatting) comma (and C99 only at that)
> > 
> > > > +};
> > > > +
> > > > +enum {
> > > > +    CTRL_EN = (1<<0),
> > 
> > Ditto x2
> Ok, but it has a hidden agenda. R_MAX must always be the last entry, therefore 
> i omitted the comma. Whereas the bit flags could still be extended. Again if 
> this is a concern for you, i'll change that and all other models too.
> 
> > > > +};
> > > > +
> > > > +struct MilkymistAC97State {
> > > > +    SysBusDevice busdev;
> > > > +
> > > > +    QEMUSoundCard card;
> > > > +    SWVoiceIn *voice_in;
> > > > +    SWVoiceOut *voice_out;
> > > > +
> > > > +    uint32_t regs[R_MAX];
> > > > +
> > > > +    qemu_irq crrequest_irq;
> > > > +    qemu_irq crreply_irq;
> > > > +    qemu_irq dmar_irq;
> > > > +    qemu_irq dmaw_irq;
> > > > +};
> > > > +typedef struct MilkymistAC97State MilkymistAC97State;
> > > > +
> > > > +static void update_voices(MilkymistAC97State *s)
> > > > +{
> > > > +    if (s->regs[R_D_CTRL]&  CTRL_EN) {
> > 
> > Space before ampersand would be nice.
> mh i think Alex email client messed this up. At least for me, there is one 
> space before and one space after the ampersand in my original email.
> 

Sorry for the noise then. (to Alexander: real men don't use crap MUA
you use)

-- 
mailto:av1474@comtv.ru

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

* Re: [Qemu-devel] Re: [PATCH 00/14] lm32: Milkymist board support
  2011-03-16 17:08 ` [Qemu-devel] Re: [PATCH 00/14] lm32: Milkymist board support Alexander Graf
@ 2011-03-24  9:28   ` Alexander Graf
  2011-04-04  8:46     ` Edgar E. Iglesias
  0 siblings, 1 reply; 23+ messages in thread
From: Alexander Graf @ 2011-03-24  9:28 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Edgar E. Iglesias, Michael Walle, qemu-devel


On 16.03.2011, at 18:08, Alexander Graf wrote:

> On 03/07/2011 11:32 PM, Michael Walle wrote:
>> This is the second (and last) patchset of the LatticeMico32 support. It
>> adds almost complete support for the opensource and openhardware Milkymist
>> One board [1].
>> 
>> [1] http://www.milkymist.org/mmone.html
>> 
> 
> From my side you get:
> 
> Acked-by: Alexander Graf <agraf@suse.de>
> 
> But it'd be great if the respective subsystem maintainers could also take a look at code affecting them.

Ping? Enough time passed for people to comment now, no?


Alex

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

* Re: [Qemu-devel] Re: [PATCH 00/14] lm32: Milkymist board support
  2011-03-24  9:28   ` Alexander Graf
@ 2011-04-04  8:46     ` Edgar E. Iglesias
  0 siblings, 0 replies; 23+ messages in thread
From: Edgar E. Iglesias @ 2011-04-04  8:46 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Michael Walle, qemu-devel

On Thu, Mar 24, 2011 at 10:28:49AM +0100, Alexander Graf wrote:
> 
> On 16.03.2011, at 18:08, Alexander Graf wrote:
> 
> > On 03/07/2011 11:32 PM, Michael Walle wrote:
> >> This is the second (and last) patchset of the LatticeMico32 support. It
> >> adds almost complete support for the opensource and openhardware Milkymist
> >> One board [1].
> >> 
> >> [1] http://www.milkymist.org/mmone.html
> >> 
> > 
> > From my side you get:
> > 
> > Acked-by: Alexander Graf <agraf@suse.de>
> > 
> > But it'd be great if the respective subsystem maintainers could also take a look at code affecting them.
> 
> Ping? Enough time passed for people to comment now, no?

I've applied this now, thanks Michael and Alex.

Cheers

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

end of thread, other threads:[~2011-04-04  8:46 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-07 22:32 [Qemu-devel] [PATCH 00/14] lm32: Milkymist board support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 01/14] lm32: add Milkymist AC97 support Michael Walle
2011-03-16 16:50   ` [Qemu-devel] " Alexander Graf
2011-03-16 18:12     ` malc
2011-03-16 23:02       ` Michael Walle
2011-03-16 23:49         ` Alexander Graf
2011-03-17  0:10         ` malc
2011-03-07 22:32 ` [Qemu-devel] [PATCH 02/14] lm32: add Milkymist HPDMC support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 03/14] lm32: add Milkymist memory card support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 04/14] lm32: add Milkymist Minimac support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 05/14] lm32: add Milkymist PFPU support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 06/14] lm32: add Milkymist SoftUSB support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 07/14] lm32: add Milkymist System Controller support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 08/14] configure: add opengl detection Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 09/14] lm32: add Milkymist TMU2 support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 10/14] lm32: add Milkymist UART support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 11/14] lm32: add Milkymist VGAFB support Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 12/14] lm32: add milkymist hw support functions Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 13/14] lm32: add support for the Milkymist board Michael Walle
2011-03-07 22:32 ` [Qemu-devel] [PATCH 14/14] MAINTAINERS: add " Michael Walle
2011-03-16 17:08 ` [Qemu-devel] Re: [PATCH 00/14] lm32: Milkymist board support Alexander Graf
2011-03-24  9:28   ` Alexander Graf
2011-04-04  8:46     ` Edgar E. Iglesias

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).