[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 4/9] LabX: Support for some Lab X FPGA devices.
From: |
crwulff |
Subject: |
[Qemu-devel] [PATCH 4/9] LabX: Support for some Lab X FPGA devices. |
Date: |
Sun, 9 Sep 2012 20:20:02 -0400 |
From: Chris Wulff <address@hidden>
Signed-off-by: Chris Wulff <address@hidden>
---
hw/Makefile.objs | 7 +
hw/labx_audio_depacketizer.c | 409 ++++++++++++++++++++++++++++
hw/labx_audio_packetizer.c | 397 +++++++++++++++++++++++++++
hw/labx_devices.h | 103 +++++++
hw/labx_dma.c | 241 +++++++++++++++++
hw/labx_ethernet.c | 615 ++++++++++++++++++++++++++++++++++++++++++
hw/labx_ptp.c | 291 ++++++++++++++++++++
7 files changed, 2063 insertions(+)
create mode 100644 hw/labx_audio_depacketizer.c
create mode 100644 hw/labx_audio_packetizer.c
create mode 100644 hw/labx_devices.h
create mode 100644 hw/labx_dma.c
create mode 100644 hw/labx_ethernet.c
create mode 100644 hw/labx_ptp.c
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 59dd2d5..ebbeb16 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -72,6 +72,13 @@ hw-obj-$(CONFIG_ALTERA) += altera_vic.o
hw-obj-$(CONFIG_ALTERA) += altera_uart.o
hw-obj-$(CONFIG_ALTERA) += altera_timer.o
+# Lab X devices
+hw-obj-$(CONFIG_LABX) += labx_audio_packetizer.o
+hw-obj-$(CONFIG_LABX) += labx_audio_depacketizer.o
+hw-obj-$(CONFIG_LABX) += labx_dma.o
+hw-obj-$(CONFIG_LABX) += labx_ethernet.o
+hw-obj-$(CONFIG_LABX) += labx_ptp.o
+
# PKUnity SoC devices
hw-obj-$(CONFIG_PUV3) += puv3_intc.o
hw-obj-$(CONFIG_PUV3) += puv3_ost.o
diff --git a/hw/labx_audio_depacketizer.c b/hw/labx_audio_depacketizer.c
new file mode 100644
index 0000000..5da3f47
--- /dev/null
+++ b/hw/labx_audio_depacketizer.c
@@ -0,0 +1,409 @@
+
+/*
+ * QEMU model of the LabX audio depacketizer.
+ *
+ * Copyright (c) 2010 Lab X Technologies, LLC
+ *
+ * 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.1 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/lgpl-2.1.html>
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+#include "labx_devices.h"
+
+#define min_bits qemu_fls
+#define RAM_INDEX(addr, size) (((addr)>>2)&((1<<min_bits((size)-1))-1))
+
+struct clock_domain_info {
+ uint32_t tsInterval;
+};
+
+typedef struct audio_depacketizer {
+ SysBusDevice busdev;
+
+ MemoryRegion mmio_depacketizer;
+ MemoryRegion mmio_clock_domain;
+ MemoryRegion mmio_microcode;
+
+ /* Device Configuration */
+ uint32_t baseAddress;
+ uint32_t clockDomains;
+ uint32_t cacheDataWords;
+ uint32_t paramWords;
+ uint32_t microcodeWords;
+ uint32_t maxStreamSlots;
+ uint32_t maxStreams;
+ uint32_t hasDMA;
+ uint32_t matchArch;
+
+ /* IRQ */
+ qemu_irq irq;
+
+ /* Values set by drivers */
+
+ /* Microcode buffer */
+ uint32_t *microcodeRam;
+
+ /* Clock domain information */
+ struct clock_domain_info *clockDomainInfo;
+
+ /* Attached DMA (if hasDMA > 0) */
+ DeviceState *dma;
+} depacketizer_t;
+
+/*
+ * Depacketizer registers
+ */
+static uint64_t depacketizer_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ depacketizer_t *p = opaque;
+
+ uint32_t retval = 0;
+
+ switch ((addr>>2) & 0xFF) {
+ case 0x00: /* control */
+ break;
+
+ case 0x01: /* vector bar */
+ break;
+
+ case 0x02: /* id select 0 */
+ break;
+
+ case 0x03: /* id select 1 */
+ break;
+
+ case 0x04: /* id select 2 */
+ break;
+
+ case 0x05: /* id select 3 */
+ break;
+
+ case 0x06: /* id config data */
+ break;
+
+ case 0x08: /* irq mask */
+ break;
+
+ case 0x09: /* irq flags */
+ break;
+
+ case 0x0A: /* sync */
+ break;
+
+ case 0x0B: /* relocate */
+ break;
+
+ case 0x0C: /* stream status 0 */
+ break;
+
+ case 0x0D: /* stream status 1 */
+ break;
+
+ case 0x0E: /* stream status 2 */
+ break;
+
+ case 0x0F: /* stream status 3 */
+ break;
+
+ case 0xFD: /* capabilities a */
+ retval = (p->maxStreamSlots & 0x7F);
+ break;
+
+ case 0xFE: /* capabilities b */
+ retval = ((p->matchArch & 0xFF) << 24) |
+ ((p->maxStreams & 0xFF) << 16) |
+ ((p->clockDomains & 0xFF) << 8) |
+ ((min_bits(p->paramWords-1) & 0x0F) << 4) |
+ ((min_bits(p->microcodeWords-1) & 0x0F));
+ break;
+
+ case 0xFF: /* revision */
+ retval = 0x00000014;
+ break;
+
+ default:
+ printf("labx-audio-depacketizer: Read of unknown register %08X\n",
+ addr);
+ break;
+ }
+
+ return retval;
+}
+
+static void depacketizer_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ /*depacketizer_t *p = opaque; */
+ uint32_t value = val64;
+
+ switch ((addr>>2) & 0xFF) {
+ case 0x00: /* control */
+ break;
+
+ case 0x01: /* vector bar */
+ break;
+
+ case 0x02: /* id select 0 */
+ break;
+
+ case 0x03: /* id select 1 */
+ break;
+
+ case 0x04: /* id select 2 */
+ break;
+
+ case 0x05: /* id select 3 */
+ break;
+
+ case 0x06: /* id config data */
+ break;
+
+ case 0x08: /* irq mask */
+ break;
+
+ case 0x09: /* irq flags */
+ break;
+
+ case 0x0A: /* sync */
+ break;
+
+ case 0x0B: /* relocate */
+ break;
+
+ case 0x0C: /* stream status 0 */
+ break;
+
+ case 0x0D: /* stream status 1 */
+ break;
+
+ case 0x0E: /* stream status 2 */
+ break;
+
+ case 0x0F: /* stream status 3 */
+ break;
+
+ case 0xFD: /* capabilities a */
+ break;
+
+ case 0xFE: /* capabilities b */
+ break;
+
+ case 0xFF: /* revision */
+ break;
+
+ default:
+ printf("labx-audio-depacketizer: Write of unknown register "
+ "%08X = %08X\n", addr, value);
+ break;
+ }
+}
+
+static const MemoryRegionOps depacketizer_regs_ops = {
+ .read = depacketizer_regs_read,
+ .write = depacketizer_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Clock domain registers
+ */
+static uint64_t clock_domain_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ depacketizer_t *p = opaque;
+
+ uint32_t retval = 0;
+ int domain = (addr>>6) & ((1<<min_bits(p->clockDomains-1))-1);
+
+ switch ((addr>>2)&0x10) {
+ case 0x00: /* recovery index */
+ break;
+
+ case 0x01: /* ts interval */
+ retval = p->clockDomainInfo[domain].tsInterval;
+ break;
+
+ case 0x08: /* DAC offset */
+ break;
+
+ case 0x09: /* DAC P coeff */
+ break;
+
+ case 0x0A: /* lock count */
+ break;
+
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static void clock_domain_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ depacketizer_t *p = opaque;
+ uint32_t value = val64;
+ int domain = (addr>>6) & ((1<<min_bits(p->clockDomains-1))-1);
+
+ switch ((addr>>2)&0x10) {
+ case 0x00: /* recovery index */
+ break;
+
+ case 0x01: /* ts interval */
+ p->clockDomainInfo[domain].tsInterval = value;
+ break;
+
+ case 0x08: /* DAC offset */
+ break;
+
+ case 0x09: /* DAC P coeff */
+ break;
+
+ case 0x0A: /* lock count */
+ break;
+
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps clock_domain_regs_ops = {
+ .read = clock_domain_regs_read,
+ .write = clock_domain_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Microcode RAM
+ */
+static uint64_t microcode_ram_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ depacketizer_t *p = opaque;
+
+ return p->microcodeRam[RAM_INDEX(addr, p->microcodeWords)];
+}
+
+static void microcode_ram_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ depacketizer_t *p = opaque;
+ uint32_t value = val64;
+
+ p->microcodeRam[RAM_INDEX(addr, p->microcodeWords)] = value;
+}
+
+static const MemoryRegionOps microcode_ram_ops = {
+ .read = microcode_ram_read,
+ .write = microcode_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+static int labx_audio_depacketizer_init(SysBusDevice *dev)
+{
+ depacketizer_t *p = FROM_SYSBUS(typeof(*p), dev);
+
+ /* Initialize defaults */
+ p->microcodeRam = g_malloc0(p->microcodeWords*4);
+ p->clockDomainInfo = g_malloc0(sizeof(struct clock_domain_info) *
+ p->clockDomains);
+
+ /* Set up the IRQ */
+ sysbus_init_irq(dev, &p->irq);
+
+ /* Set up memory regions */
+ memory_region_init_io(&p->mmio_depacketizer, &depacketizer_regs_ops, p,
+ "labx,audio-depacketizer-regs",
+ 0x100 * 4);
+ memory_region_init_io(&p->mmio_clock_domain, &clock_domain_regs_ops, p,
+ "labx,audio-depacketizer-cd-regs",
+ 0x10 * 4 * p->clockDomains);
+ memory_region_init_io(&p->mmio_microcode, µcode_ram_ops, p,
+ "labx,audio-depacketizer-microcode",
+ 4 * p->microcodeWords);
+
+ sysbus_init_mmio(dev, &p->mmio_depacketizer);
+ sysbus_init_mmio(dev, &p->mmio_clock_domain);
+ sysbus_init_mmio(dev, &p->mmio_microcode);
+
+ sysbus_mmio_map(dev, 0, p->baseAddress);
+ sysbus_mmio_map(dev, 1, p->baseAddress +
+ (1 << (min_bits(p->microcodeWords-1)+2)));
+ sysbus_mmio_map(dev, 2, p->baseAddress +
+ (2 << (min_bits(p->microcodeWords-1)+2)));
+
+ if (p->hasDMA) {
+ p->dma = labx_dma_create(p->baseAddress +
+ (4 << (min_bits(p->microcodeWords-1)+2)),
+ 1024);
+ }
+
+ return 0;
+}
+
+static Property labx_audio_depacketizer_properties[] = {
+ DEFINE_PROP_UINT32("baseAddress", depacketizer_t, baseAddress, 0),
+ DEFINE_PROP_UINT32("clockDomains", depacketizer_t, clockDomains, 1),
+ DEFINE_PROP_UINT32("cacheDataWords", depacketizer_t, cacheDataWords, 1024),
+ DEFINE_PROP_UINT32("paramWords", depacketizer_t, paramWords, 1024),
+ DEFINE_PROP_UINT32("microcodeWords", depacketizer_t, microcodeWords, 1024),
+ DEFINE_PROP_UINT32("maxStreamSlots", depacketizer_t, maxStreamSlots, 32),
+ DEFINE_PROP_UINT32("maxStreams", depacketizer_t, maxStreams, 128),
+ DEFINE_PROP_UINT32("hasDMA", depacketizer_t, hasDMA, 1),
+ DEFINE_PROP_UINT32("matchArch", depacketizer_t, matchArch, 255),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void labx_audio_depacketizer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = labx_audio_depacketizer_init;
+ dc->props = labx_audio_depacketizer_properties;
+}
+
+static TypeInfo labx_audio_depacketizer_info = {
+ .name = "labx,audio-depacketizer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(depacketizer_t),
+ .class_init = labx_audio_depacketizer_class_init,
+};
+
+static void labx_audio_depacketizer_register(void)
+{
+ type_register_static(&labx_audio_depacketizer_info);
+}
+
+type_init(labx_audio_depacketizer_register)
+
diff --git a/hw/labx_audio_packetizer.c b/hw/labx_audio_packetizer.c
new file mode 100644
index 0000000..120cce0
--- /dev/null
+++ b/hw/labx_audio_packetizer.c
@@ -0,0 +1,397 @@
+
+/*
+ * QEMU model of the LabX audio packetizer.
+ *
+ * Copyright (c) 2010 Lab X Technologies, LLC
+ *
+ * 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.1 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/lgpl-2.1.html>
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+
+#define min_bits qemu_fls
+#define RAM_INDEX(addr, size) (((addr)>>2)&((1<<min_bits((size)-1))-1))
+
+struct clock_domain_info {
+ uint32_t tsInterval;
+ uint32_t domainEnabled;
+};
+
+typedef struct audio_packetizer {
+ SysBusDevice busdev;
+
+ MemoryRegion mmio_packetizer;
+ MemoryRegion mmio_clock_domain;
+ MemoryRegion mmio_template;
+ MemoryRegion mmio_microcode;
+
+ /* Device Configuration */
+ uint32_t baseAddress;
+ uint32_t clockDomains;
+ uint32_t cacheDataWords;
+ uint32_t templateWords;
+ uint32_t microcodeWords;
+ uint32_t shaperFractionBits;
+ uint32_t maxStreamSlots;
+ uint32_t dualOutput;
+
+ /* IRQ */
+ qemu_irq irq;
+
+ /* Values set by drivers */
+ uint32_t tsOffset;
+ uint32_t sendSlope;
+ uint32_t idleSlope;
+
+ /* Microcode buffer */
+ uint32_t *microcodeRam;
+
+ /* Template buffer */
+ uint32_t *templateRam;
+
+ /* Clock domain information */
+ struct clock_domain_info *clockDomainInfo;
+} packetizer_t;
+
+/*
+ * Packetizer registers
+ */
+static uint64_t packetizer_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ packetizer_t *p = opaque;
+
+ uint32_t retval = 0;
+
+ switch ((addr>>2) & 0xFF) {
+ case 0x00: /* control */
+ break;
+
+ case 0x01: /* start vector */
+ break;
+
+ case 0x02: /* ts offset */
+ break;
+
+ case 0x03: /* irq mask */
+ break;
+
+ case 0x04: /* irq flags */
+ break;
+
+ case 0x05: /* sync reg */
+ break;
+
+ case 0x06: /* send slope */
+ break;
+
+ case 0x07: /* idle slope */
+ break;
+
+ case 0xFD: /* capabilities a */
+ retval = (p->maxStreamSlots & 0x7F) | ((p->dualOutput) ? 0x80 : 0x00);
+ break;
+
+ case 0xFE: /* capabilities b */
+ retval = ((p->shaperFractionBits & 0x7F) << 24) |
+ ((p->clockDomains & 0xFF) << 16) |
+ ((min_bits(p->templateWords-1) & 0xFF) << 8) |
+ ((min_bits(p->microcodeWords-1) & 0xFF));
+ break;
+
+ case 0xFF: /* revision */
+ retval = 0x00000013;
+ break;
+
+ default:
+ printf("labx-audio-packetizer: Read of unknown register %08X\n", addr);
+ break;
+ }
+
+ return retval;
+}
+
+static void packetizer_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ packetizer_t *p = opaque;
+ uint32_t value = val64;
+
+ switch ((addr>>2) & 0xFF) {
+ case 0x00: /* control */
+ break;
+
+ case 0x01: /* start vector */
+ break;
+
+ case 0x02: /* ts offset */
+ p->tsOffset = value;
+ break;
+
+ case 0x03: /* irq mask */
+ break;
+
+ case 0x04: /* irq flags */
+ break;
+
+ case 0x05: /* sync reg */
+ break;
+
+ case 0x06: /* send slope */
+ p->sendSlope = value;
+ break;
+
+ case 0x07: /* idle slope */
+ p->idleSlope = value;
+ break;
+
+ case 0xFD: /* capabilities a */
+ break;
+
+ case 0xFE: /* capabilities b */
+ break;
+
+ case 0xFF: /* revision */
+ break;
+
+ default:
+ printf("labx-audio-packetizer: Write of unknown register "
+ "%08X = %08X\n", addr, value);
+ break;
+ }
+}
+
+static const MemoryRegionOps packetizer_regs_ops = {
+ .read = packetizer_regs_read,
+ .write = packetizer_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Clock domain registers
+ */
+static uint64_t clock_domain_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ packetizer_t *p = opaque;
+
+ uint32_t retval = 0;
+ int domain = (addr>>3) & ((1<<min_bits(p->clockDomains-1))-1);
+
+ switch ((addr>>2)&0x01) {
+ case 0x00: /* ts interval */
+ retval = p->clockDomainInfo[domain].tsInterval;
+ break;
+
+ case 0x01: /* domain enable */
+ retval = p->clockDomainInfo[domain].domainEnabled;
+ break;
+
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static void clock_domain_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ packetizer_t *p = opaque;
+ uint32_t value = val64;
+
+ int domain = (addr>>3) & ((1<<min_bits(p->clockDomains-1))-1);
+
+ switch ((addr>>2)&0x01) {
+ case 0x00: /* ts interval */
+ p->clockDomainInfo[domain].tsInterval = value;
+ break;
+
+ case 0x01: /* domain enable */
+ p->clockDomainInfo[domain].domainEnabled = value;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps clock_domain_regs_ops = {
+ .read = clock_domain_regs_read,
+ .write = clock_domain_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Template RAM
+ */
+static uint64_t template_ram_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ packetizer_t *p = opaque;
+
+ return p->templateRam[RAM_INDEX(addr, p->templateWords)];
+}
+
+static void template_ram_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ packetizer_t *p = opaque;
+ uint32_t value = val64;
+
+ p->templateRam[RAM_INDEX(addr, p->templateWords)] = value;
+}
+
+static const MemoryRegionOps template_ram_ops = {
+ .read = template_ram_read,
+ .write = template_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Microcode RAM
+ */
+static uint64_t microcode_ram_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ packetizer_t *p = opaque;
+
+ return p->microcodeRam[RAM_INDEX(addr, p->microcodeWords)];
+}
+
+static void microcode_ram_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ packetizer_t *p = opaque;
+ uint32_t value = val64;
+
+ p->microcodeRam[RAM_INDEX(addr, p->microcodeWords)] = value;
+}
+
+static const MemoryRegionOps microcode_ram_ops = {
+ .read = microcode_ram_read,
+ .write = microcode_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+static int labx_audio_packetizer_init(SysBusDevice *dev)
+{
+ packetizer_t *p = FROM_SYSBUS(typeof(*p), dev);
+
+ /* Initialize defaults */
+ p->tsOffset = 0x00000000;
+ p->sendSlope = 0x00000000;
+ p->idleSlope = 0x00000000;
+ p->templateRam = g_malloc0(p->templateWords*4);
+ p->microcodeRam = g_malloc0(p->microcodeWords*4);
+ p->clockDomainInfo = g_malloc0(sizeof(struct clock_domain_info) *
+ p->clockDomains);
+
+ /* Set up the IRQ */
+ sysbus_init_irq(dev, &p->irq);
+
+ /* Set up memory regions */
+ memory_region_init_io(&p->mmio_packetizer, &packetizer_regs_ops, p,
+ "labx,audio-packetizer-regs",
+ 0x100 * 4);
+ memory_region_init_io(&p->mmio_clock_domain, &clock_domain_regs_ops, p,
+ "labx,audio-packetizer-cd-regs",
+ 2 * 4 * p->clockDomains);
+ memory_region_init_io(&p->mmio_template, &template_ram_ops, p,
+ "labx,audio-packetizer-template",
+ 4 * p->templateWords);
+ memory_region_init_io(&p->mmio_microcode, µcode_ram_ops, p,
+ "labx,audio-packetizer-microcode",
+ 4 * p->microcodeWords);
+
+ sysbus_init_mmio(dev, &p->mmio_packetizer);
+ sysbus_init_mmio(dev, &p->mmio_clock_domain);
+ sysbus_init_mmio(dev, &p->mmio_template);
+ sysbus_init_mmio(dev, &p->mmio_microcode);
+
+ sysbus_mmio_map(dev, 0, p->baseAddress);
+ sysbus_mmio_map(dev, 1, p->baseAddress +
+ (1 << (min_bits(p->microcodeWords-1)+2)));
+ sysbus_mmio_map(dev, 2, p->baseAddress +
+ (2 << (min_bits(p->microcodeWords-1)+2)));
+ sysbus_mmio_map(dev, 3, p->baseAddress +
+ (3 << (min_bits(p->microcodeWords-1)+2)));
+
+ return 0;
+}
+
+static Property labx_audio_packetizer_properties[] = {
+ DEFINE_PROP_UINT32("baseAddress", packetizer_t, baseAddress,
+ 0),
+ DEFINE_PROP_UINT32("clockDomains", packetizer_t, clockDomains,
+ 1),
+ DEFINE_PROP_UINT32("cacheDataWords", packetizer_t, cacheDataWords,
+ 1024),
+ DEFINE_PROP_UINT32("templateWords", packetizer_t, templateWords,
+ 1024),
+ DEFINE_PROP_UINT32("microcodeWords", packetizer_t, microcodeWords,
+ 1024),
+ DEFINE_PROP_UINT32("shaperFractionBits", packetizer_t, shaperFractionBits,
+ 16),
+ DEFINE_PROP_UINT32("maxStreamSlots", packetizer_t, maxStreamSlots,
+ 32),
+ DEFINE_PROP_UINT32("dualOutput", packetizer_t, dualOutput,
+ 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void labx_audio_packetizer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = labx_audio_packetizer_init;
+ dc->props = labx_audio_packetizer_properties;
+}
+
+static TypeInfo labx_audio_packetizer_info = {
+ .name = "labx,audio-packetizer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(packetizer_t),
+ .class_init = labx_audio_packetizer_class_init,
+};
+
+static void labx_audio_packetizer_register(void)
+{
+ type_register_static(&labx_audio_packetizer_info);
+}
+
+type_init(labx_audio_packetizer_register)
+
diff --git a/hw/labx_devices.h b/hw/labx_devices.h
new file mode 100644
index 0000000..317341e
--- /dev/null
+++ b/hw/labx_devices.h
@@ -0,0 +1,103 @@
+/*
+ * Lab X device types header.
+ *
+ * Copyright (c) 2010 Lab X Technologies, LLC
+ *
+ * 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.1 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/lgpl-2.1.html>
+ */
+
+#include <net.h>
+
+/* Audio packetizer */
+static inline DeviceState *
+labx_audio_packetizer_create(target_phys_addr_t base, qemu_irq irq,
+ int clockDomains, int cacheDataWords)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "labx,audio-packetizer");
+ qdev_prop_set_uint32(dev, "baseAddress", base);
+ qdev_prop_set_uint32(dev, "clockDomains", clockDomains);
+ qdev_prop_set_uint32(dev, "cacheDataWords", cacheDataWords);
+ qdev_init_nofail(dev);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+ return dev;
+}
+
+/* Audio depacketizer */
+static inline DeviceState *
+labx_audio_depacketizer_create(target_phys_addr_t base, qemu_irq irq,
+ int clockDomains, int cacheDataWords, int
hasDMA)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "labx,audio-depacketizer");
+ qdev_prop_set_uint32(dev, "baseAddress", base);
+ qdev_prop_set_uint32(dev, "clockDomains", clockDomains);
+ qdev_prop_set_uint32(dev, "cacheDataWords", cacheDataWords);
+ qdev_prop_set_uint32(dev, "hasDMA", hasDMA);
+ qdev_init_nofail(dev);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+ return dev;
+}
+
+/* DMA */
+static inline DeviceState *
+labx_dma_create(target_phys_addr_t base, int microcodeWords)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "labx,dma");
+ qdev_prop_set_uint32(dev, "baseAddress", base);
+ qdev_prop_set_uint32(dev, "microcodeWords", microcodeWords);
+ qdev_init_nofail(dev);
+ return dev;
+}
+
+/* Ethernet */
+static inline DeviceState *
+labx_ethernet_create(NICInfo *nd, target_phys_addr_t base, qemu_irq hostIrq,
+ qemu_irq fifoIrq, qemu_irq phyIrq)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ qemu_check_nic_model(nd, "labx-ethernet");
+
+ dev = qdev_create(NULL, "labx,ethernet");
+ qdev_prop_set_uint32(dev, "baseAddress", base);
+ qdev_set_nic_properties(dev, nd);
+ qdev_init_nofail(dev);
+
+ s = sysbus_from_qdev(dev);
+ sysbus_connect_irq(s, 0, hostIrq);
+ sysbus_connect_irq(s, 1, fifoIrq);
+ sysbus_connect_irq(s, 2, phyIrq);
+
+ return dev;
+}
+
+/* PTP */
+static inline DeviceState *
+labx_ptp_create(target_phys_addr_t base)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "labx,ptp");
+ qdev_prop_set_uint32(dev, "baseAddress", base);
+ qdev_init_nofail(dev);
+ return dev;
+}
+
diff --git a/hw/labx_dma.c b/hw/labx_dma.c
new file mode 100644
index 0000000..9d8058c
--- /dev/null
+++ b/hw/labx_dma.c
@@ -0,0 +1,241 @@
+
+/*
+ * QEMU model of the LabX DMA Engine.
+ *
+ * Copyright (c) 2010 Lab X Technologies, LLC
+ *
+ * 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.1 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/lgpl-2.1.html>
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+
+#define min_bits qemu_fls
+#define RAM_INDEX(addr, size) (((addr)>>2)&((1<<min_bits((size)-1))-1))
+
+
+struct labx_dma {
+ SysBusDevice busdev;
+
+ MemoryRegion mmio_dma;
+ MemoryRegion mmio_microcode;
+
+ /* Device Configuration */
+ uint32_t baseAddress;
+ uint32_t paramWords;
+ uint32_t microcodeWords;
+ uint32_t numIndexRegs;
+ uint32_t numChannels;
+ uint32_t numAlus;
+
+ /* Values set by drivers */
+
+ /* Microcode buffer */
+ uint32_t *microcodeRam;
+};
+
+/*
+ * DMA registers
+ */
+static uint64_t dma_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ struct labx_dma *p = opaque;
+
+ uint32_t retval = 0;
+
+ if ((addr>>2) & 0x80) {
+ /* vector */
+ } else {
+ switch ((addr>>2) & 0x7F) {
+ case 0x00: /* control */
+ break;
+
+ case 0x01: /* channel enable */
+ break;
+
+ case 0x02: /* channel start */
+ break;
+
+ case 0x03: /* channel irq enable */
+ break;
+
+ case 0x04: /* channel irq */
+ break;
+
+ case 0x05: /* sync */
+ break;
+
+ case 0x7E: /* capabilities */
+ retval = ((p->numIndexRegs & 0x0F) << 12) |
+ ((p->numChannels & 0x03) << 10) |
+ ((p->numAlus & 0x03) << 8) |
+ ((min_bits(p->paramWords-1) & 0x0F) << 4) |
+ ((min_bits(p->microcodeWords-1) & 0x0F));
+ break;
+
+ case 0x7F: /* revision */
+ retval = 0x00000011;
+ break;
+
+ default:
+ printf("labx-dma: Read of unknown register %08X\n", addr);
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static void dma_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ /*struct labx_dma *p = opaque; */
+ uint32_t value = val64;
+
+ if ((addr>>2) & 0x80) {
+ /* vector */
+ } else {
+ switch ((addr>>2) & 0x7F) {
+ case 0x00: /* control */
+ break;
+
+ case 0x01: /* channel enable */
+ break;
+
+ case 0x02: /* channel start */
+ break;
+
+ case 0x03: /* channel irq enable */
+ break;
+
+ case 0x04: /* channel irq */
+ break;
+
+ case 0x05: /* sync */
+ break;
+
+ case 0x7E: /* capabilities */
+ break;
+
+ case 0x7F: /* revision */
+ break;
+
+ default:
+ printf("labx-dma: Write of unknown register "
+ "%08X = %08X\n", addr, value);
+ break;
+ }
+ }
+}
+
+static const MemoryRegionOps dma_regs_ops = {
+ .read = dma_regs_read,
+ .write = dma_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Microcode RAM
+ */
+static uint64_t microcode_ram_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ struct labx_dma *p = opaque;
+
+ return p->microcodeRam[RAM_INDEX(addr, p->microcodeWords)];
+}
+
+static void microcode_ram_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ struct labx_dma *p = opaque;
+ uint32_t value = val64;
+
+ p->microcodeRam[RAM_INDEX(addr, p->microcodeWords)] = value;
+}
+
+static const MemoryRegionOps microcode_ram_ops = {
+ .read = microcode_ram_read,
+ .write = microcode_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+static int labx_dma_init(SysBusDevice *dev)
+{
+ struct labx_dma *p = FROM_SYSBUS(typeof(*p), dev);
+
+ /* Initialize defaults */
+ p->microcodeRam = g_malloc0(p->microcodeWords*4);
+
+ /* Set up memory regions */
+ memory_region_init_io(&p->mmio_dma, &dma_regs_ops, p,
+ "labx,dma-regs", 0x100 * 4);
+ memory_region_init_io(&p->mmio_microcode, µcode_ram_ops, p,
+ "labx,dma-microcode", 4 * p->microcodeWords);
+
+ sysbus_init_mmio(dev, &p->mmio_dma);
+ sysbus_init_mmio(dev, &p->mmio_microcode);
+
+ sysbus_mmio_map(dev, 0, p->baseAddress);
+ sysbus_mmio_map(dev, 1, p->baseAddress +
+ (1 << (min_bits(p->microcodeWords-1)+2)));
+
+ return 0;
+}
+
+static Property labx_dma_properties[] = {
+ DEFINE_PROP_UINT32("baseAddress", struct labx_dma, baseAddress, 0),
+ DEFINE_PROP_UINT32("paramWords", struct labx_dma, paramWords,
1024),
+ DEFINE_PROP_UINT32("microcodeWords", struct labx_dma, microcodeWords,
1024),
+ DEFINE_PROP_UINT32("numIndexRegs", struct labx_dma, numIndexRegs, 4),
+ DEFINE_PROP_UINT32("numChannels", struct labx_dma, numChannels, 1),
+ DEFINE_PROP_UINT32("numAlus", struct labx_dma, numAlus, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void labx_dma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = labx_dma_init;
+ dc->props = labx_dma_properties;
+}
+
+static TypeInfo labx_dma_info = {
+ .name = "labx,dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct labx_dma),
+ .class_init = labx_dma_class_init,
+};
+
+static void labx_dma_register(void)
+{
+ type_register_static(&labx_dma_info);
+}
+
+type_init(labx_dma_register)
+
diff --git a/hw/labx_ethernet.c b/hw/labx_ethernet.c
new file mode 100644
index 0000000..c47c91b
--- /dev/null
+++ b/hw/labx_ethernet.c
@@ -0,0 +1,615 @@
+
+/*
+ * QEMU model of the LabX legacy ethernet core.
+ *
+ * Copyright (c) 2010 Lab X Technologies, LLC
+ *
+ * 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.1 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/lgpl-2.1.html>
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+#include "net.h"
+
+#define FIFO_RAM_BYTES 2048
+#define LENGTH_FIFO_WORDS 16
+
+struct labx_ethernet {
+ SysBusDevice busdev;
+ qemu_irq hostIrq;
+ qemu_irq fifoIrq;
+ qemu_irq phyIrq;
+ NICState *nic;
+ NICConf conf;
+
+ MemoryRegion mmio_ethernet;
+ MemoryRegion mmio_mac;
+ MemoryRegion mmio_fifo;
+
+ /* Device Configuration */
+ uint32_t baseAddress;
+
+ /* Values set by drivers */
+ uint32_t hostRegs[0x10];
+ uint32_t fifoRegs[0x10];
+
+ /* Tx buffers */
+ uint32_t *txBuffer;
+ uint32_t txPushIndex;
+ uint32_t txPopIndex;
+
+ uint32_t *txLengthBuffer;
+ uint32_t txLengthPushIndex;
+ uint32_t txLengthPopIndex;
+
+ /* Rx buffers */
+ uint32_t *rxBuffer;
+ uint32_t rxPushIndex;
+ uint32_t rxPopIndex;
+
+ uint32_t *rxLengthBuffer;
+ uint32_t rxLengthPushIndex;
+ uint32_t rxLengthPopIndex;
+};
+
+/*
+ * Legacy ethernet registers
+ */
+static void update_host_irq(struct labx_ethernet *p)
+{
+ if ((p->hostRegs[0x03] & p->hostRegs[2]) != 0) {
+ qemu_irq_raise(p->hostIrq);
+ } else {
+ qemu_irq_lower(p->hostIrq);
+ }
+}
+
+static void mdio_xfer(struct labx_ethernet *p, int readWrite,
+ int phyAddr, int regAddr)
+{
+ printf("MDIO %s: addr=%d, reg=%d\n", (readWrite) ? "READ" : "WRITE",
+ phyAddr, regAddr);
+ if (readWrite) {
+ /* TODO: PHY info */
+ p->hostRegs[0x01] = 0x0000FFFF;
+ }
+ p->hostRegs[0x03] |= 1;
+ update_host_irq(p);
+}
+
+static uint64_t ethernet_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ struct labx_ethernet *p = opaque;
+
+ uint32_t retval = 0;
+
+ switch ((addr>>2) & 0x0F) {
+ case 0x00: /* mdio control */
+ case 0x01: /* mdio data */
+ case 0x02: /* irq mask */
+ case 0x03: /* irq flags */
+ case 0x04: /* vlan mask */
+ case 0x05: /* filter select */
+ retval = p->hostRegs[(addr>>2) & 0x0F];
+ break;
+
+ case 0x06: /* filter control */
+ retval = 0x20000000;
+ break;
+
+ case 0x0F: /* revision */
+ retval = 0x00000C13;
+ break;
+
+ case 0x07: /* filter load */
+ retval = p->hostRegs[(addr>>2) & 0x0F];
+ break;
+
+ case 0x08: /* bad packet */
+ retval = 0;
+ break;
+
+ default:
+ printf("labx-ethernet: Read of unknown register %08X\n", addr);
+ break;
+ }
+
+ return retval;
+}
+
+static void ethernet_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ struct labx_ethernet *p = opaque;
+ uint32_t value = val64;
+
+ switch ((addr>>2) & 0x0F) {
+ case 0x00: /* mdio control */
+ p->hostRegs[0x00] = (value & 0x000007FF);
+ mdio_xfer(p, (value >> 10) & 1, (value >> 5) & 0x1F, value & 0x1F);
+ break;
+
+ case 0x01: /* mdio data */
+ p->hostRegs[0x01] = (value & 0x0000FFFF);
+ break;
+
+ case 0x02: /* irq mask */
+ p->hostRegs[0x02] = (value & 0x00000003);
+ update_host_irq(p);
+ break;
+
+ case 0x03: /* irq flags */
+ p->hostRegs[0x03] &= ~(value & 0x00000003);
+ update_host_irq(p);
+ break;
+
+ case 0x04: /* vlan mask */
+ break;
+
+ case 0x05: /* filter select */
+ break;
+
+ case 0x06: /* filter control */
+ break;
+
+ case 0x07: /* filter load */
+ break;
+
+ case 0x08: /* bad packet */
+ break;
+
+ case 0x0F: /* revision */
+ break;
+
+ default:
+ printf("labx-ethernet: Write of unknown register %08X = %08X\n",
+ addr, value);
+ break;
+ }
+}
+
+static const MemoryRegionOps ethernet_regs_ops = {
+ .read = ethernet_regs_read,
+ .write = ethernet_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * MAC registers
+ */
+static uint64_t mac_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ /*struct labx_ethernet *p = opaque; */
+
+ uint32_t retval = 0;
+
+ switch ((addr>>2) & 0x0F) {
+ case 0x01: /* host rx config */
+ break;
+
+ case 0x02: /* host tx config */
+ break;
+
+ case 0x04: /* host speed config */
+ break;
+
+ case 0x05: /* host mdio config */
+ break;
+
+ default:
+ printf("labx-ethernet: Read of unknown mac register %08X\n", addr);
+ break;
+ }
+
+ return retval;
+}
+
+static void mac_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ /*struct labx_ethernet *p = opaque; */
+ uint32_t value = val64;
+
+ switch ((addr>>2) & 0x0F) {
+ case 0x01: /* host rx config */
+ break;
+
+ case 0x02: /* host tx config */
+ break;
+
+ case 0x04: /* host speed config */
+ break;
+
+ case 0x05: /* host mdio config */
+ break;
+
+ default:
+ printf("labx-ethernet: Write of unknown mac register %08X = %08X\n",
+ addr, value);
+ break;
+ }
+}
+
+static const MemoryRegionOps mac_regs_ops = {
+ .read = mac_regs_read,
+ .write = mac_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * FIFO registers
+ */
+
+#define FIFO_INT_STATUS_ADDRESS 0x0
+#define FIFO_INT_ENABLE_ADDRESS 0x1
+# define FIFO_INT_RPURE 0x80000000
+# define FIFO_INT_RPORE 0x40000000
+# define FIFO_INT_RPUE 0x20000000
+# define FIFO_INT_TPOE 0x10000000
+# define FIFO_INT_TC 0x08000000
+# define FIFO_INT_RC 0x04000000
+# define FIFO_INT_MASK 0xFC000000
+#define FIFO_TX_RESET_ADDRESS 0x2
+# define FIFO_RESET_MAGIC 0xA5
+#define FIFO_TX_VACANCY_ADDRESS 0x3
+#define FIFO_TX_DATA_ADDRESS 0x4
+#define FIFO_TX_LENGTH_ADDRESS 0x5
+#define FIFO_RX_RESET_ADDRESS 0x6
+#define FIFO_RX_OCCUPANCY_ADDRESS 0x7
+#define FIFO_RX_DATA_ADDRESS 0x8
+#define FIFO_RX_LENGTH_ADDRESS 0x9
+
+static void update_fifo_irq(struct labx_ethernet *p)
+{
+ if ((p->fifoRegs[FIFO_INT_STATUS_ADDRESS] &
+ p->fifoRegs[FIFO_INT_ENABLE_ADDRESS]) != 0) {
+ qemu_irq_raise(p->fifoIrq);
+ } else {
+ qemu_irq_lower(p->fifoIrq);
+ }
+}
+
+static void send_packet(struct labx_ethernet *p)
+{
+ while (p->txLengthPopIndex != p->txLengthPushIndex) {
+ int i;
+ uint32_t packetBuf[512];
+
+ int length = p->txLengthBuffer[p->txLengthPopIndex];
+ p->txLengthPopIndex = (p->txLengthPopIndex + 1) % LENGTH_FIFO_WORDS;
+
+ for (i = 0; i < ((length+3)/4); i++) {
+ packetBuf[i] = be32_to_cpu(p->txBuffer[p->txPopIndex]);
+ p->txPopIndex = (p->txPopIndex + 1) % (FIFO_RAM_BYTES/4);
+ }
+
+ qemu_send_packet(&p->nic->nc, (void *)packetBuf, length);
+ }
+
+ p->fifoRegs[FIFO_INT_STATUS_ADDRESS] |= FIFO_INT_TC;
+ update_fifo_irq(p);
+}
+
+static uint64_t fifo_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ struct labx_ethernet *p = opaque;
+
+ uint32_t retval = 0;
+
+ switch ((addr>>2) & 0x0F) {
+ case FIFO_INT_STATUS_ADDRESS:
+ case FIFO_INT_ENABLE_ADDRESS:
+ case FIFO_TX_RESET_ADDRESS:
+ retval = p->fifoRegs[(addr>>2) & 0x0F];
+ break;
+
+ case FIFO_TX_VACANCY_ADDRESS:
+ retval = (p->txPopIndex - p->txPushIndex) - 1;
+ if ((int32_t)retval < 0) {
+ retval += (FIFO_RAM_BYTES/4);
+ }
+
+ if (((p->txLengthPushIndex + 1) % LENGTH_FIFO_WORDS) ==
+ p->txLengthPopIndex) {
+ /* Full length fifo */
+ retval = 0;
+ }
+ break;
+
+ case FIFO_TX_DATA_ADDRESS:
+ case FIFO_TX_LENGTH_ADDRESS:
+ case FIFO_RX_RESET_ADDRESS:
+ retval = p->fifoRegs[(addr>>2) & 0x0F];
+ break;
+
+ case FIFO_RX_OCCUPANCY_ADDRESS:
+ retval = p->rxPushIndex - p->rxPopIndex;
+ if ((int32_t)retval < 0) {
+ retval += (FIFO_RAM_BYTES/4);
+ }
+ break;
+
+ case FIFO_RX_DATA_ADDRESS:
+ retval = p->rxBuffer[p->rxPopIndex];
+ if (p->rxPopIndex != p->rxPushIndex) {
+ p->rxPopIndex = (p->rxPopIndex+1) % (FIFO_RAM_BYTES/4);
+ } else {
+ p->fifoRegs[FIFO_INT_STATUS_ADDRESS] |= FIFO_INT_RPURE;
+ update_fifo_irq(p);
+ }
+ break;
+
+ case FIFO_RX_LENGTH_ADDRESS:
+ retval = p->rxLengthBuffer[p->rxLengthPopIndex];
+ if (p->rxLengthPopIndex != p->rxLengthPushIndex) {
+ p->rxLengthPopIndex = (p->rxLengthPopIndex+1) % LENGTH_FIFO_WORDS;
+ } else {
+ p->fifoRegs[FIFO_INT_STATUS_ADDRESS] |= FIFO_INT_RPURE;
+ update_fifo_irq(p);
+ }
+ break;
+
+ default:
+ printf("labx-ethernet: Read of unknown fifo register %08X\n", addr);
+ break;
+ }
+
+ /* printf("FIFO REG READ %08X (%d) = %08X\n",
+ addr, (addr>>2) & 0x0F, retval); */
+
+ return retval;
+}
+
+static void fifo_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ struct labx_ethernet *p = opaque;
+ uint32_t value = val64;
+
+ /* printf("FIFO REG WRITE %08X (%d) = %08X\n",
+ addr, (addr>>2) & 0x0F, value); */
+
+ switch ((addr>>2) & 0x0F) {
+ case FIFO_INT_STATUS_ADDRESS:
+ p->fifoRegs[FIFO_INT_STATUS_ADDRESS] &= ~(value & FIFO_INT_MASK);
+ update_fifo_irq(p);
+ break;
+
+ case FIFO_INT_ENABLE_ADDRESS:
+ p->fifoRegs[FIFO_INT_ENABLE_ADDRESS] = (value & FIFO_INT_MASK);
+ update_fifo_irq(p);
+ break;
+
+ case FIFO_TX_RESET_ADDRESS:
+ if (value == FIFO_RESET_MAGIC) {
+ p->txPushIndex = 0;
+ p->txPopIndex = 0;
+ p->txLengthPushIndex = 0;
+ p->txLengthPopIndex = 0;
+ }
+ break;
+
+ case FIFO_TX_VACANCY_ADDRESS:
+ break;
+
+ case FIFO_TX_DATA_ADDRESS:
+ if ((((p->txLengthPushIndex + 1) % LENGTH_FIFO_WORDS) ==
+ p->txLengthPopIndex) ||
+ (((p->txPushIndex + 1) % (FIFO_RAM_BYTES/4)) == p->txPopIndex)) {
+ /* Full length fifo or data fifo */
+ p->fifoRegs[FIFO_INT_STATUS_ADDRESS] |= FIFO_INT_TPOE;
+ update_fifo_irq(p);
+ } else {
+ /* Push back the data */
+ p->txBuffer[p->txPushIndex] = value;
+ p->txPushIndex = (p->txPushIndex + 1) % (FIFO_RAM_BYTES/4);
+ }
+ break;
+
+ case FIFO_TX_LENGTH_ADDRESS:
+ if (((p->txLengthPushIndex + 1) % LENGTH_FIFO_WORDS) ==
+ p->txLengthPopIndex) {
+ /* Full length fifo */
+ p->fifoRegs[FIFO_INT_STATUS_ADDRESS] |= FIFO_INT_TPOE;
+ update_fifo_irq(p);
+ } else {
+ /* Push back the length */
+ p->txLengthBuffer[p->txLengthPushIndex] = value;
+ p->txLengthPushIndex = (p->txLengthPushIndex + 1) %
+ LENGTH_FIFO_WORDS;
+ send_packet(p);
+ }
+ break;
+
+ case FIFO_RX_RESET_ADDRESS:
+ if (value == FIFO_RESET_MAGIC) {
+ p->rxPushIndex = 0;
+ p->rxPopIndex = 0;
+ p->rxLengthPushIndex = 0;
+ p->rxLengthPopIndex = 0;
+ }
+ break;
+
+ case FIFO_RX_OCCUPANCY_ADDRESS:
+ break;
+
+ case FIFO_RX_DATA_ADDRESS:
+ break;
+
+ case FIFO_RX_LENGTH_ADDRESS:
+ break;
+
+ default:
+ printf("labx-ethernet: Write of unknown fifo register %08X = %08X\n",
+ addr, value);
+ break;
+ }
+}
+
+static const MemoryRegionOps fifo_regs_ops = {
+ .read = fifo_regs_read,
+ .write = fifo_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+static int eth_can_rx(NetClientState *nc)
+{
+ /*struct labx_ethernet *s = DO_UPCAST(NICState, nc, nc)->opaque; */
+
+ return 1;
+}
+
+static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+ struct labx_ethernet *p = DO_UPCAST(NICState, nc, nc)->opaque;
+ int i;
+ const uint32_t *wbuf = (const uint32_t *)buf;
+ int rxPushIndexStart = p->rxPushIndex;
+
+ for (i = 0; i < ((size+3)/4); i++) {
+ p->rxBuffer[p->rxPushIndex] = cpu_to_be32(wbuf[i]);
+ p->rxPushIndex = (p->rxPushIndex + 1) % (FIFO_RAM_BYTES/4);
+ if (p->rxPushIndex == p->rxPopIndex) {
+ /* Packet didn't fit */
+ p->rxPushIndex = rxPushIndexStart;
+ return -1;
+ }
+ }
+
+ if ((p->rxLengthPushIndex + 1) % LENGTH_FIFO_WORDS == p->rxLengthPopIndex)
{
+ /* Length didn't fit */
+ p->rxPushIndex = rxPushIndexStart;
+ return -1;
+ }
+
+ p->rxLengthBuffer[p->rxLengthPushIndex] = size;
+ p->rxLengthPushIndex = (p->rxLengthPushIndex + 1) % LENGTH_FIFO_WORDS;
+
+ p->fifoRegs[FIFO_INT_STATUS_ADDRESS] |= FIFO_INT_RC;
+ update_fifo_irq(p);
+
+ return size;
+}
+
+static void eth_cleanup(NetClientState *nc)
+{
+ struct labx_ethernet *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+ s->nic = NULL;
+}
+
+static NetClientInfo net_labx_ethernet_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = eth_can_rx,
+ .receive = eth_rx,
+ .cleanup = eth_cleanup,
+};
+
+static int labx_ethernet_init(SysBusDevice *dev)
+{
+ struct labx_ethernet *p = FROM_SYSBUS(typeof(*p), dev);
+
+ /* Initialize defaults */
+ p->txBuffer = g_malloc0(FIFO_RAM_BYTES);
+ p->txLengthBuffer = g_malloc0(LENGTH_FIFO_WORDS*4);
+ p->rxBuffer = g_malloc0(FIFO_RAM_BYTES);
+ p->rxLengthBuffer = g_malloc0(LENGTH_FIFO_WORDS*4);
+
+ p->txPushIndex = 0;
+ p->txPopIndex = 0;
+ p->txLengthPushIndex = 0;
+ p->txLengthPopIndex = 0;
+ p->rxPushIndex = 0;
+ p->rxPopIndex = 0;
+ p->rxLengthPushIndex = 0;
+ p->rxLengthPopIndex = 0;
+
+ /* Set up memory regions */
+ memory_region_init_io(&p->mmio_ethernet, ðernet_regs_ops, p,
+ "labx,ethernet-regs", 0x10 * 4);
+ memory_region_init_io(&p->mmio_mac, &mac_regs_ops, p,
+ "labx,ethernet-mac-regs", 0x10 * 4);
+ memory_region_init_io(&p->mmio_fifo, &fifo_regs_ops, p,
+ "labx,ethernet-fifo-regs", 0x10 * 4);
+
+ sysbus_init_mmio(dev, &p->mmio_ethernet);
+ sysbus_init_mmio(dev, &p->mmio_mac);
+ sysbus_init_mmio(dev, &p->mmio_fifo);
+
+ sysbus_mmio_map(dev, 0, p->baseAddress);
+ sysbus_mmio_map(dev, 1, p->baseAddress + (1 << (10+2)));
+ sysbus_mmio_map(dev, 2, p->baseAddress + (2 << (10+2)));
+
+ /* Initialize the irqs */
+ sysbus_init_irq(dev, &p->hostIrq);
+ sysbus_init_irq(dev, &p->fifoIrq);
+ sysbus_init_irq(dev, &p->phyIrq);
+
+ /* Set up the NIC */
+ qemu_macaddr_default_if_unset(&p->conf.macaddr);
+ p->nic = qemu_new_nic(&net_labx_ethernet_info, &p->conf,
+ object_get_typename(OBJECT(p)), dev->qdev.id, p);
+ qemu_format_nic_info_str(&p->nic->nc, p->conf.macaddr.a);
+ return 0;
+}
+
+static Property labx_ethernet_properties[] = {
+ DEFINE_PROP_UINT32("baseAddress", struct labx_ethernet, baseAddress, 0),
+ DEFINE_NIC_PROPERTIES(struct labx_ethernet, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void labx_ethernet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = labx_ethernet_init;
+ dc->props = labx_ethernet_properties;
+}
+
+static TypeInfo labx_ethernet_info = {
+ .name = "labx,ethernet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct labx_ethernet),
+ .class_init = labx_ethernet_class_init,
+};
+
+static void labx_ethernet_register(void)
+{
+ type_register_static(&labx_ethernet_info);
+}
+
+type_init(labx_ethernet_register)
+
diff --git a/hw/labx_ptp.c b/hw/labx_ptp.c
new file mode 100644
index 0000000..68d4b54
--- /dev/null
+++ b/hw/labx_ptp.c
@@ -0,0 +1,291 @@
+
+/*
+ * QEMU model of the LabX PTP.
+ *
+ * Copyright (c) 2010 Lab X Technologies, LLC
+ *
+ * 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.1 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/lgpl-2.1.html>
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+
+#define min_bits qemu_fls
+#define RAM_INDEX(addr, size) (((addr)>>2)&((1<<min_bits((size)-1))-1))
+
+#define PTP_MAX_PACKETS 8
+#define PTP_MAX_PACKET_BYTES 256
+#define PTP_RAM_BYTES (PTP_MAX_PACKETS*PTP_MAX_PACKET_BYTES)
+#define PTP_HOST_RAM_WORDS (PTP_RAM_BYTES/4)
+
+struct labx_ptp {
+ SysBusDevice busdev;
+
+ MemoryRegion mmio_ptp;
+ MemoryRegion mmio_tx;
+ MemoryRegion mmio_rx;
+
+ /* Device Configuration */
+ uint32_t baseAddress;
+
+ /* Values set by drivers */
+
+ /* Tx buffers */
+ uint32_t *txRam;
+
+ /* Rx buffers */
+ uint32_t *rxRam;
+};
+
+/*
+ * PTP registers
+ */
+static uint64_t ptp_regs_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ /*struct labx_ptp *p = opaque; */
+
+ uint32_t retval = 0;
+
+ switch ((addr>>2) & 0x0F) {
+ case 0x00: /* rx */
+ break;
+
+ case 0x01: /* tx */
+ break;
+
+ case 0x02: /* irq mask */
+ break;
+
+ case 0x03: /* irq flags */
+ break;
+
+ case 0x04: /* rtc increment */
+ break;
+
+ case 0x05: /* seconds high */
+ break;
+
+ case 0x06: /* seconds low */
+ break;
+
+ case 0x07: /* nanoseconds */
+ break;
+
+ case 0x08: /* timer */
+ break;
+
+ case 0x09: /* local seconds high */
+ break;
+
+ case 0x0A: /* local seconds low */
+ break;
+
+ case 0x0B: /* local nanoseconds */
+ break;
+
+ case 0x0F: /* revision */
+ retval = 0x00000111; /* Report 1 port, revision 1.1 */
+ break;
+
+ default:
+ printf("labx-ptp: Read of unknown register %08X\n", addr);
+ break;
+ }
+
+ return retval;
+}
+
+static void ptp_regs_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ /*struct labx_ptp *p = opaque; */
+ uint32_t value = val64;
+
+ switch ((addr>>2) & 0x0F) {
+ case 0x00: /* rx */
+ break;
+
+ case 0x01: /* tx */
+ break;
+
+ case 0x02: /* irq mask */
+ break;
+
+ case 0x03: /* irq flags */
+ break;
+
+ case 0x04: /* rtc increment */
+ break;
+
+ case 0x05: /* seconds high */
+ break;
+
+ case 0x06: /* seconds low */
+ break;
+
+ case 0x07: /* nanoseconds */
+ break;
+
+ case 0x08: /* timer */
+ break;
+
+ case 0x09: /* local seconds high */
+ break;
+
+ case 0x0A: /* local seconds low */
+ break;
+
+ case 0x0B: /* local nanoseconds */
+ break;
+
+ case 0x0F: /* revision */
+ break;
+
+ default:
+ printf("labx-ptp: Write of unknown register %08X = %08X\n",
+ addr, value);
+ break;
+ }
+}
+
+static const MemoryRegionOps ptp_regs_ops = {
+ .read = ptp_regs_read,
+ .write = ptp_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Tx Ram
+ */
+static uint64_t tx_ram_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ struct labx_ptp *p = opaque;
+
+ return p->txRam[RAM_INDEX(addr, PTP_HOST_RAM_WORDS)];
+}
+
+static void tx_ram_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ struct labx_ptp *p = opaque;
+ uint32_t value = val64;
+
+ p->txRam[RAM_INDEX(addr, PTP_HOST_RAM_WORDS)] = value;
+}
+
+static const MemoryRegionOps tx_ram_ops = {
+ .read = tx_ram_read,
+ .write = tx_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+/*
+ * Rx Ram
+ */
+static uint64_t rx_ram_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ struct labx_ptp *p = opaque;
+
+ return p->rxRam[RAM_INDEX(addr, PTP_HOST_RAM_WORDS)];
+}
+
+static void rx_ram_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val64, unsigned int size)
+{
+ struct labx_ptp *p = opaque;
+ uint32_t value = val64;
+
+ p->rxRam[RAM_INDEX(addr, PTP_HOST_RAM_WORDS)] = value;
+}
+
+static const MemoryRegionOps rx_ram_ops = {
+ .read = rx_ram_read,
+ .write = rx_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+
+static int labx_ptp_init(SysBusDevice *dev)
+{
+ struct labx_ptp *p = FROM_SYSBUS(typeof(*p), dev);
+
+ /* Initialize defaults */
+ p->txRam = g_malloc0(PTP_RAM_BYTES);
+ p->rxRam = g_malloc0(PTP_RAM_BYTES);
+
+ /* Set up memory regions */
+ memory_region_init_io(&p->mmio_ptp, &ptp_regs_ops, p, "labx,ptp-regs",
+ 0x100 * 4);
+ memory_region_init_io(&p->mmio_tx, &tx_ram_ops, p, "labx,ptp-tx",
+ PTP_RAM_BYTES);
+ memory_region_init_io(&p->mmio_rx, &rx_ram_ops, p, "labx,ptp-rx",
+ PTP_RAM_BYTES);
+
+ sysbus_init_mmio(dev, &p->mmio_ptp);
+ sysbus_init_mmio(dev, &p->mmio_tx);
+ sysbus_init_mmio(dev, &p->mmio_rx);
+
+ sysbus_mmio_map(dev, 0, p->baseAddress);
+ sysbus_mmio_map(dev, 1, p->baseAddress + (1 << min_bits(PTP_RAM_BYTES-1)));
+ sysbus_mmio_map(dev, 2, p->baseAddress + (2 << min_bits(PTP_RAM_BYTES-1)));
+
+ return 0;
+}
+
+static Property labx_ptp_properties[] = {
+ DEFINE_PROP_UINT32("baseAddress", struct labx_ptp, baseAddress, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void labx_ptp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = labx_ptp_init;
+ dc->props = labx_ptp_properties;
+}
+
+static TypeInfo labx_ptp_info = {
+ .name = "labx,ptp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct labx_ptp),
+ .class_init = labx_ptp_class_init,
+};
+
+static void labx_ptp_register(void)
+{
+ type_register_static(&labx_ptp_info);
+}
+
+type_init(labx_ptp_register)
+
--
1.7.9.5
- [Qemu-devel] [PATCH 6/9] NiosII: Build system and documentation integration., (continued)
- [Qemu-devel] [PATCH 6/9] NiosII: Build system and documentation integration., crwulff, 2012/09/09
- [Qemu-devel] [PATCH 1/9] NiosII: Add support for the Altera NiosII soft-core CPU., crwulff, 2012/09/09
- [Qemu-devel] [PATCH 9/9] xilinx_timer: Fix a compile error if debug messages are enabled., crwulff, 2012/09/09
- [Qemu-devel] [PATCH 4/9] LabX: Support for some Lab X FPGA devices.,
crwulff <=
- [Qemu-devel] [PATCH 8/9] MicroBlaze: Add a config that is dynamically set up by a device tree file., crwulff, 2012/09/09
- Re: [Qemu-devel] [PATCH 8/9] MicroBlaze: Add a config that is dynamically set up by a device tree file., Peter Crosthwaite, 2012/09/11
- [Qemu-devel] [PATCH 2/9] NiosII: Disassembly of NiosII instructions ported from GDB., crwulff, 2012/09/09
- Re: [Qemu-devel] [PATCH 0/9] Altera NiosII support, Peter Crosthwaite, 2012/09/11