[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 4/9] LabX: Support for some Lab X FPGA devices.
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH 4/9] LabX: Support for some Lab X FPGA devices. |
Date: |
Tue, 11 Sep 2012 20:22:56 +0000 |
On Mon, Sep 10, 2012 at 12:20 AM, <address@hidden> wrote:
> From: Chris Wulff <address@hidden>
>
> Signed-off-by: Chris Wulff <address@hidden>
Same comments as to other patches. Pointers to chip set documentation
would be nice.
> ---
> 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 1/9] NiosII: Add support for the Altera NiosII soft-core CPU., (continued)
- [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, 2012/09/09
- Re: [Qemu-devel] [PATCH 4/9] LabX: Support for some Lab X FPGA devices.,
Blue Swirl <=
- [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