diff options
Diffstat (limited to 'qemu/hw/dma/puv3_dma.c')
-rw-r--r-- | qemu/hw/dma/puv3_dma.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/qemu/hw/dma/puv3_dma.c b/qemu/hw/dma/puv3_dma.c new file mode 100644 index 000000000..101bd7f8a --- /dev/null +++ b/qemu/hw/dma/puv3_dma.c @@ -0,0 +1,113 @@ +/* + * DMA device simulation in PKUnity SoC + * + * Copyright (C) 2010-2012 Guan Xuetao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation, or any later version. + * See the COPYING file in the top-level directory. + */ +#include "hw/hw.h" +#include "hw/sysbus.h" + +#undef DEBUG_PUV3 +#include "hw/unicore32/puv3.h" + +#define PUV3_DMA_CH_NR (6) +#define PUV3_DMA_CH_MASK (0xff) +#define PUV3_DMA_CH(offset) ((offset) >> 8) + +#define TYPE_PUV3_DMA "puv3_dma" +#define PUV3_DMA(obj) OBJECT_CHECK(PUV3DMAState, (obj), TYPE_PUV3_DMA) + +typedef struct PUV3DMAState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + uint32_t reg_CFG[PUV3_DMA_CH_NR]; +} PUV3DMAState; + +static uint64_t puv3_dma_read(void *opaque, hwaddr offset, + unsigned size) +{ + PUV3DMAState *s = opaque; + uint32_t ret = 0; + + assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR); + + switch (offset & PUV3_DMA_CH_MASK) { + case 0x10: + ret = s->reg_CFG[PUV3_DMA_CH(offset)]; + break; + default: + DPRINTF("Bad offset 0x%x\n", offset); + } + DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); + + return ret; +} + +static void puv3_dma_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PUV3DMAState *s = opaque; + + assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR); + + switch (offset & PUV3_DMA_CH_MASK) { + case 0x10: + s->reg_CFG[PUV3_DMA_CH(offset)] = value; + break; + default: + DPRINTF("Bad offset 0x%x\n", offset); + } + DPRINTF("offset 0x%x, value 0x%x\n", offset, value); +} + +static const MemoryRegionOps puv3_dma_ops = { + .read = puv3_dma_read, + .write = puv3_dma_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int puv3_dma_init(SysBusDevice *dev) +{ + PUV3DMAState *s = PUV3_DMA(dev); + int i; + + for (i = 0; i < PUV3_DMA_CH_NR; i++) { + s->reg_CFG[i] = 0x0; + } + + memory_region_init_io(&s->iomem, OBJECT(s), &puv3_dma_ops, s, "puv3_dma", + PUV3_REGS_OFFSET); + sysbus_init_mmio(dev, &s->iomem); + + return 0; +} + +static void puv3_dma_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = puv3_dma_init; +} + +static const TypeInfo puv3_dma_info = { + .name = TYPE_PUV3_DMA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PUV3DMAState), + .class_init = puv3_dma_class_init, +}; + +static void puv3_dma_register_type(void) +{ + type_register_static(&puv3_dma_info); +} + +type_init(puv3_dma_register_type) |