Add hw/xbox sources from XQEMU 1.x @ 4d9107e

This commit is contained in:
Matt Borgerson
2018-06-26 15:08:01 -07:00
parent 4743c23509
commit 3f557e6d45
44 changed files with 29269 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
obj-y += xbox.o chihiro.o
obj-y += xbox_pci.o acpi_xbox.o
obj-y += amd_smbus.o smbus_xbox_smc.o smbus_cx25871.o smbus_adm1032.o
obj-y += nvnet.o
obj-y += nv2a.o nv2a_vsh.o nv2a_psh.o nv2a_shaders.o nv2a_debug.o
obj-y += swizzle.o g-lru-cache.o
obj-y += mcpx_apu.o mcpx_aci.o
obj-y += lpc47m157.o
obj-y += xid.o
obj-y += chihiro-usb.o
obj-y += dsp/
+118
View File
@@ -0,0 +1,118 @@
/*
* Xbox ACPI implementation
*
* Copyright (c) 2012 espes
*
* Based on acpi.c, acpi_ich9.c, acpi_piix4.c
* Copyright (c) 2006 Fabrice Bellard
* Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
* VA Linux Systems Japan K.K.
* Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "hw/acpi/acpi.h"
#include "hw/xbox/xbox_pci.h"
#include "hw/xbox/acpi_xbox.h"
#define DEBUG
#ifdef DEBUG
# define XBOX_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define XBOX_DPRINTF(format, ...) do { } while (0)
#endif
#define XBOX_PM_GPIO_BASE 0xC0
#define XBOX_PM_GPIO_LEN 26
static int field_pin = 0;
static uint64_t xbox_pm_gpio_read(void *opaque, hwaddr addr, unsigned width)
{
uint64_t r = 0;
switch (addr) {
case 0:
// field pin from tv encoder?
field_pin = (field_pin+1)&1;
r = field_pin << 5;
break;
default:
break;
}
XBOX_DPRINTF("pm gpio read [0x%llx] -> 0x%llx\n", addr, r);
return r;
}
static void xbox_pm_gpio_write(void *opaque, hwaddr addr, uint64_t val,
unsigned width)
{
XBOX_DPRINTF("pm gpio write [0x%llx] = 0x%llx\n", addr, val);
}
static const MemoryRegionOps xbox_pm_gpio_ops = {
.read = xbox_pm_gpio_read,
.write = xbox_pm_gpio_write,
};
static void pm_update_sci(XBOX_PMRegs *pm)
{
int sci_level, pm1a_sts;
pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs);
sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) &
(ACPI_BITMASK_RT_CLOCK_ENABLE |
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
ACPI_BITMASK_TIMER_ENABLE)) != 0);
qemu_set_irq(pm->irq, sci_level);
/* schedule a timer interruption if needed */
acpi_pm_tmr_update(&pm->acpi_regs,
(pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
!(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
}
static void xbox_pm_update_sci_fn(ACPIREGS *regs)
{
XBOX_PMRegs *pm = container_of(regs, XBOX_PMRegs, acpi_regs);
pm_update_sci(pm);
}
#define XBOX_PM_BASE_BAR 0
void xbox_pm_init(PCIDevice *dev, XBOX_PMRegs *pm, qemu_irq sci_irq) {
memory_region_init(&pm->io, OBJECT(dev), "xbox-pm", 256);
pci_register_bar(dev, XBOX_PM_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
&pm->io);
acpi_pm_tmr_init(&pm->acpi_regs, xbox_pm_update_sci_fn, &pm->io);
acpi_pm1_evt_init(&pm->acpi_regs, xbox_pm_update_sci_fn, &pm->io);
acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, 2);
memory_region_init_io(&pm->io_gpio, OBJECT(dev), &xbox_pm_gpio_ops, pm,
"xbox-pm-gpio", XBOX_PM_GPIO_LEN);
memory_region_add_subregion(&pm->io, XBOX_PM_GPIO_BASE, &pm->io_gpio);
pm->irq = sci_irq;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* QEMU Xbox PM Emulation
*
* Copyright (c) 2012 espes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#ifndef HW_ACPI_XBOX_H
#define HW_ACPI_XBOX_H
#include "hw/acpi/acpi.h"
typedef struct XBOX_PMRegs {
ACPIREGS acpi_regs;
MemoryRegion io;
MemoryRegion io_gpio;
qemu_irq irq;
} XBOX_PMRegs;
void xbox_pm_init(PCIDevice *dev, XBOX_PMRegs *pm, qemu_irq sci_irq);
//void xbox_pm_iospace_update(MCPX_PMRegs *pm, uint32_t pm_io_base);
#endif
+256
View File
@@ -0,0 +1,256 @@
/*
* AMD756 SMBus implementation
*
* Copyright (C) 2012 espes
*
* Based on pm_smbus.c
* Copyright (c) 2006 Fabrice Bellard
* Based on Linux drivers/i2c/busses/i2c-amd756.c
* Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/xbox/amd_smbus.h"
#include "hw/i2c/smbus.h"
/* AMD756 SMBus address offsets */
#define SMB_ADDR_OFFSET 0xE0
#define SMB_IOSIZE 16
#define SMB_GLOBAL_STATUS 0x0
#define SMB_GLOBAL_ENABLE 0x2
#define SMB_HOST_ADDRESS 0x4
#define SMB_HOST_DATA 0x6
#define SMB_HOST_COMMAND 0x8
#define SMB_HOST_BLOCK_DATA 0x9
#define SMB_HAS_DATA 0xA
#define SMB_HAS_DEVICE_ADDRESS 0xC
#define SMB_HAS_HOST_ADDRESS 0xE
#define SMB_SNOOP_ADDRESS 0xF
/* AMD756 constants */
#define AMD756_QUICK 0x00
#define AMD756_BYTE 0x01
#define AMD756_BYTE_DATA 0x02
#define AMD756_WORD_DATA 0x03
#define AMD756_PROCESS_CALL 0x04
#define AMD756_BLOCK_DATA 0x05
/*
SMBUS event = I/O 28-29 bit 11
see E0 for the status bits and enabled in E2
*/
#define GS_ABRT_STS (1 << 0)
#define GS_COL_STS (1 << 1)
#define GS_PRERR_STS (1 << 2)
#define GS_HST_STS (1 << 3)
#define GS_HCYC_STS (1 << 4)
#define GS_TO_STS (1 << 5)
#define GS_SMB_STS (1 << 11)
#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
GS_HCYC_STS | GS_TO_STS )
#define GE_CYC_TYPE_MASK (7)
#define GE_HOST_STC (1 << 3)
#define GE_HCYC_EN (1 << 4)
#define GE_ABORT (1 << 5)
//#define DEBUG
#ifdef DEBUG
# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define SMBUS_DPRINTF(format, ...) do { } while (0)
#endif
static void amd756_smb_transaction(AMD756SMBus *s)
{
uint8_t prot = s->smb_ctl & GE_CYC_TYPE_MASK;
uint8_t read = s->smb_addr & 0x01;
uint8_t cmd = s->smb_cmd;
uint8_t addr = (s->smb_addr >> 1) & 0x7f;
i2c_bus *bus = s->smbus;
SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
switch(prot) {
case AMD756_QUICK:
smbus_quick_command(bus, addr, read);
break;
case AMD756_BYTE:
if (read) {
s->smb_data0 = smbus_receive_byte(bus, addr);
} else {
smbus_send_byte(bus, addr, cmd);
}
break;
case AMD756_BYTE_DATA:
if (read) {
s->smb_data0 = smbus_read_byte(bus, addr, cmd);
} else {
smbus_write_byte(bus, addr, cmd, s->smb_data0);
}
break;
case AMD756_WORD_DATA:
if (read) {
uint16_t val;
val = smbus_read_word(bus, addr, cmd);
s->smb_data0 = val;
s->smb_data1 = val >> 8;
} else {
smbus_write_word(bus, addr, cmd, s->smb_data0);
}
break;
case AMD756_BLOCK_DATA:
if (read) {
s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
} else {
smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
}
break;
default:
goto error;
}
s->smb_stat |= GS_HCYC_STS;
return;
error:
s->smb_stat |= GS_PRERR_STS;
}
void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
{
AMD756SMBus *s = opaque;
addr &= 0x3f;
SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
switch(addr) {
case SMB_GLOBAL_STATUS:
if (s->irq) {
/* Raise an irq if interrupts are enabled and a new
* status is being set */
if ((s->smb_ctl & GE_HCYC_EN)
&& ((val & GS_CLEAR_STS)
& (~(s->smb_stat & GS_CLEAR_STS)))) {
qemu_irq_raise(s->irq);
} else {
qemu_irq_lower(s->irq);
}
}
if (val & GS_CLEAR_STS) {
s->smb_stat = 0;
s->smb_index = 0;
} else if (val & GS_HCYC_STS) {
s->smb_stat = GS_HCYC_STS;
s->smb_index = 0;
} else {
s->smb_stat = GS_HCYC_STS;
s->smb_index = 0;
}
break;
case SMB_GLOBAL_ENABLE:
s->smb_ctl = val;
if (val & GE_ABORT)
s->smb_stat |= GS_ABRT_STS;
if (val & GE_HOST_STC) {
amd756_smb_transaction(s);
if (s->irq
&& (val & GE_HCYC_EN)
&& (s->smb_stat & GS_CLEAR_STS)) {
qemu_irq_raise(s->irq);
}
}
break;
case SMB_HOST_COMMAND:
s->smb_cmd = val;
break;
case SMB_HOST_ADDRESS:
s->smb_addr = val;
break;
case SMB_HOST_DATA:
s->smb_data0 = val;
break;
case SMB_HOST_DATA+1:
s->smb_data1 = val;
break;
case SMB_HOST_BLOCK_DATA:
s->smb_data[s->smb_index++] = val;
if (s->smb_index > 31)
s->smb_index = 0;
break;
default:
break;
}
}
uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr)
{
AMD756SMBus *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case SMB_GLOBAL_STATUS:
val = s->smb_stat;
break;
case SMB_GLOBAL_ENABLE:
//s->smb_index = 0;
val = s->smb_ctl & 0x1f;
break;
case SMB_HOST_COMMAND:
val = s->smb_cmd;
break;
case SMB_HOST_ADDRESS:
val = s->smb_addr;
break;
case SMB_HOST_DATA:
val = s->smb_data0;
break;
case SMB_HOST_DATA+1:
val = s->smb_data1;
break;
case SMB_HOST_BLOCK_DATA:
val = s->smb_data[s->smb_index++];
if (s->smb_index > 31)
s->smb_index = 0;
break;
default:
val = 0;
break;
}
SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val);
return val;
}
void amd756_smbus_init(DeviceState *parent, AMD756SMBus *smb, qemu_irq irq)
{
smb->smbus = i2c_init_bus(parent, "i2c");
smb->smb_stat = 0;
smb->irq = irq;
}
+45
View File
@@ -0,0 +1,45 @@
/*
* AMD756 SMBus implementation
*
* Copyright (C) 2012 espes
*
* Based on pm_smbus.c
* Copyright (c) 2006 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AMD_SMBUS_H
#define AMD_SMBUS_H
typedef struct AMD756SMBus {
i2c_bus *smbus;
uint8_t smb_stat;
uint8_t smb_ctl;
uint8_t smb_cmd;
uint8_t smb_addr;
uint8_t smb_data0;
uint8_t smb_data1;
uint8_t smb_data[32];
uint8_t smb_index;
qemu_irq irq;
} AMD756SMBus;
void amd756_smbus_init(DeviceState *parent, AMD756SMBus *smb, qemu_irq irq);
void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val);
uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr);
#endif /* !AMD_SMBUS_H */
+331
View File
@@ -0,0 +1,331 @@
/*
* QEMU Chihiro USB Devices
*
* Copyright (c) 2016 espes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/hw.h"
#include "ui/console.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
#define DEBUG_CUSB
#ifdef DEBUG_CUSB
#define DPRINTF(s, ...) printf("chihiro-usb: " s, ## __VA_ARGS__)
#else
#define DPRINTF(...)
#endif
typedef struct ChihiroUSBState {
USBDevice dev;
} ChihiroUSBState;
enum chihiro_usb_strings {
STRING_SERIALNUMBER,
STRING_MANUFACTURER,
STRING_PRODUCT,
};
static const USBDescStrings chihiro_usb_stringtable = {
[STRING_SERIALNUMBER] = "\x00",
[STRING_MANUFACTURER] = "SEGA",
[STRING_PRODUCT] = "BASEBD" // different for qc?
};
static const USBDescIface desc_iface_chihiro_an2131qc = {
.bInterfaceNumber = 0,
.bNumEndpoints = 10,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_OUT | 0x02,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_OUT | 0x03,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_OUT | 0x04,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_OUT | 0x05,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x02,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x03,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x04,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x05,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
},
};
static const USBDescDevice desc_device_chihiro_an2131qc = {
.bcdUSB = 0x0100,
.bMaxPacketSize0 = 0x40,
.bNumConfigurations = 1,
.confs = (USBDescConfig[]) {
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = 0x80,
.bMaxPower = 0x96,
.nif = 1,
.ifs = &desc_iface_chihiro_an2131qc,
},
},
};
static const USBDesc desc_chihiro_an2131qc = {
.id = {
.idVendor = 0x0CA3,
.idProduct = 0x0002,
.bcdDevice = 0x0108,
.iManufacturer = STRING_MANUFACTURER,
.iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIALNUMBER,
},
.full = &desc_device_chihiro_an2131qc,
.str = chihiro_usb_stringtable,
};
static const USBDescIface desc_iface_chihiro_an2131sc = {
.bInterfaceNumber = 0,
.bNumEndpoints = 6,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_OUT | 0x02,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_OUT | 0x03,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x02,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
{
.bEndpointAddress = USB_DIR_IN | 0x03,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0,
},
},
};
static const USBDescDevice desc_device_chihiro_an2131sc = {
.bcdUSB = 0x0100,
.bMaxPacketSize0 = 0x40,
.bNumConfigurations = 1,
.confs = (USBDescConfig[]) {
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = 0x80,
.bMaxPower = 0x96,
.nif = 1,
.ifs = &desc_iface_chihiro_an2131sc,
},
},
};
static const USBDesc desc_chihiro_an2131sc = {
.id = {
.idVendor = 0x0CA3,
.idProduct = 0x0003,
.bcdDevice = 0x0110,
.iManufacturer = STRING_MANUFACTURER,
.iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIALNUMBER,
},
.full = &desc_device_chihiro_an2131sc,
.str = chihiro_usb_stringtable,
};
static void handle_reset(USBDevice *dev)
{
DPRINTF("usb reset\n");
}
static void handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
DPRINTF("handle control %d %d %d %d\n", request, value, index, length);
int ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
DPRINTF("handled by usb_desc_handle_control: %d\n", ret);
return;
}
}
static void handle_data(USBDevice *dev, USBPacket *p)
{
DPRINTF("handle_data 0x%x %d 0x%zx\n", p->pid, p->ep->nr, p->iov.size);
}
static void handle_destroy(USBDevice *dev)
{
DPRINTF("usb reset\n");
}
static int chihiro_an2131qc_initfn(USBDevice *dev)
{
// ChihiroUSBState *s = DO_UPCAST(ChihiroUSBState, dev, dev);
usb_desc_init(dev);
return 0;
}
static void chihiro_an2131qc_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->init = chihiro_an2131qc_initfn;
uc->product_desc = "Chihiro an2131qc";
uc->usb_desc = &desc_chihiro_an2131qc;
uc->handle_reset = handle_reset;
uc->handle_control = handle_control;
uc->handle_data = handle_data;
uc->handle_destroy = handle_destroy;
uc->handle_attach = usb_desc_attach;
//dc->vmsd = &vmstate_usb_kbd;
}
static const TypeInfo chihiro_an2131qc_info = {
.name = "chihiro-an2131qc",
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(ChihiroUSBState),
.class_init = chihiro_an2131qc_class_initfn,
};
static int chihiro_an2131sc_initfn(USBDevice *dev)
{
// ChihiroUSBState *s = DO_UPCAST(ChihiroUSBState, dev, dev);
usb_desc_init(dev);
return 0;
}
static void chihiro_an2131sc_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->init = chihiro_an2131sc_initfn;
uc->product_desc = "Chihiro an2131sc";
uc->usb_desc = &desc_chihiro_an2131sc;
uc->handle_reset = handle_reset;
uc->handle_control = handle_control;
uc->handle_data = handle_data;
uc->handle_destroy = handle_destroy;
uc->handle_attach = usb_desc_attach;
//dc->vmsd = &vmstate_usb_kbd;
}
static const TypeInfo chihiro_an2131sc_info = {
.name = "chihiro-an2131sc",
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(ChihiroUSBState),
.class_init = chihiro_an2131sc_class_initfn,
};
static void chihiro_usb_register_types(void)
{
type_register_static(&chihiro_an2131qc_info);
type_register_static(&chihiro_an2131sc_info);
}
type_init(chihiro_usb_register_types)
+292
View File
@@ -0,0 +1,292 @@
/*
* QEMU Chihiro emulation
*
* Copyright (c) 2013 espes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/boards.h"
#include "hw/ide.h"
#include "hw/loader.h"
#include "hw/isa/isa.h"
#include "exec/memory.h"
#include "qemu/config-file.h"
#include "sysemu/blockdev.h"
#include "block/blkmemory.h"
#include "hw/xbox/xbox.h"
#define SEGA_CHIP_REVISION 0xF0
# define SEGA_CHIP_REVISION_CHIP_ID 0xFF00
# define SEGA_CHIP_REVISION_FPGA_CHIP_ID 0x0000
# define SEGA_CHIP_REVISION_ASIC_CHIP_ID 0x0100
# define SEGA_CHIP_REVISION_REVISION_ID_MASK 0x00FF
#define SEGA_DIMM_SIZE 0xF4
# define SEGA_DIMM_SIZE_128M 0
# define SEGA_DIMM_SIZE_256M 1
# define SEGA_DIMM_SIZE_512M 2
# define SEGA_DIMM_SIZE_1024M 3
//#define DEBUG_CHIHIRO
typedef struct ChihiroLPCState {
ISADevice dev;
MemoryRegion ioport;
} ChihiroLPCState;
#define CHIHIRO_LPC_DEVICE(obj) \
OBJECT_CHECK(ChihiroLPCState, (obj), "chihiro-lpc")
static uint64_t chhiro_lpc_io_read(void *opaque, hwaddr addr,
unsigned size)
{
uint64_t r = 0;
switch (addr) {
case SEGA_CHIP_REVISION:
r = SEGA_CHIP_REVISION_ASIC_CHIP_ID;
break;
case SEGA_DIMM_SIZE:
r = SEGA_DIMM_SIZE_128M;
break;
}
#ifdef DEBUG_CHIHIRO
printf("chihiro lpc read [0x%llx] -> 0x%llx\n", addr, r);
#endif
return r;
}
static void chhiro_lpc_io_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
#ifdef DEBUG_CHIHIRO
printf("chihiro lpc write [0x%llx] = 0x%llx\n", addr, val);
#endif
}
static const MemoryRegionOps chihiro_lpc_io_ops = {
.read = chhiro_lpc_io_read,
.write = chhiro_lpc_io_write,
.impl = {
.min_access_size = 2,
.max_access_size = 2,
},
};
static void chihiro_lpc_realize(DeviceState *dev, Error **errp)
{
ChihiroLPCState *s = CHIHIRO_LPC_DEVICE(dev);
ISADevice *isa = ISA_DEVICE(dev);
memory_region_init_io(&s->ioport, OBJECT(dev), &chihiro_lpc_io_ops, s,
"chihiro-lpc-io", 0x100);
isa_register_ioport(isa, &s->ioport, 0x4000);
}
static void chihiro_lpc_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = chihiro_lpc_realize;
dc->desc = "Chihiro LPC";
}
static const TypeInfo chihiro_lpc_info = {
.name = "chihiro-lpc",
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(ChihiroLPCState),
.class_init = chihiro_lpc_class_initfn,
};
static void chihiro_register_types(void)
{
type_register_static(&chihiro_lpc_info);
}
type_init(chihiro_register_types)
/* The chihiro baseboard communicates with the xbox by acting as an IDE
* device. The device maps the boot rom from the mediaboard, a communication
* area for interfacing with the network board, and the ram on the baseboard.
* The baseboard ram is populated at boot from the gd-rom drive on the
* mediaboard containing something like a combined disc+hdd image.
*/
#define FILESYSTEM_START 0
#define ROM_START 0x8000000
#define ROM_SECTORS 0x2000
#define COMMUNICATION_START 0x9000000
#define COMMUNICATION_SECTORS 0x10000
#define SECTOR_SIZE 512
static void chihiro_ide_interface_init(const char *rom_file,
const char *filesystem_file)
{
if (drive_get(IF_IDE, 0, 1)) {
fprintf(stderr, "chihiro ide interface needs to be attached "
"to IDE device 1 but it's already in use.");
exit(1);
}
MemoryRegion *interface, *rom, *filesystem;
interface = g_malloc(sizeof(*interface));
memory_region_init(interface, NULL, "chihiro.interface",
(uint64_t)0x10000000 * SECTOR_SIZE);
rom = g_malloc(sizeof(*rom));
memory_region_init_ram(rom, NULL, "chihiro.interface.rom",
ROM_SECTORS * SECTOR_SIZE);
memory_region_add_subregion(interface,
(uint64_t)ROM_START * SECTOR_SIZE, rom);
/* limited by the size of the board ram, which we emulate as 128M for now */
filesystem = g_malloc(sizeof(*filesystem));
memory_region_init_ram(filesystem, NULL, "chihiro.interface.filesystem",
128 * 1024 * 1024);
memory_region_add_subregion(interface,
(uint64_t)FILESYSTEM_START * SECTOR_SIZE,
filesystem);
AddressSpace *interface_space;
interface_space = g_malloc(sizeof(*interface_space));
address_space_init(interface_space, interface, "chihiro-interface");
/* read files */
int rc, fd = -1;
if (!rom_file) rom_file = "fpr21042_m29w160et.bin";
char *rom_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom_file);
if (rom_filename) {
int rom_size = get_image_size(rom_filename);
assert(rom_size < memory_region_size(rom));
fd = open(rom_filename, O_RDONLY | O_BINARY);
assert(fd != -1);
rc = read(fd, memory_region_get_ram_ptr(rom), rom_size);
assert(rc == rom_size);
close(fd);
}
if (filesystem_file) {
assert(access(filesystem_file, R_OK) == 0);
int filesystem_size = get_image_size(filesystem_file);
assert(filesystem_size < memory_region_size(filesystem));
fd = open(filesystem_file, O_RDONLY | O_BINARY);
assert(fd != -1);
rc = read(fd, memory_region_get_ram_ptr(rom), filesystem_size);
assert(rc == filesystem_size);
close(fd);
}
/* create the device */
DriveInfo *dinfo;
dinfo = g_malloc0(sizeof(*dinfo));
dinfo->id = g_strdup("chihiro-interface");
dinfo->bdrv = bdrv_new(dinfo->id);
dinfo->type = IF_IDE;
dinfo->bus = 0;
dinfo->unit = 1;
dinfo->refcount = 1;
assert(!bdrv_memory_open(dinfo->bdrv, interface_space,
memory_region_size(interface)));
drive_append(dinfo);
}
static void chihiro_init(QEMUMachineInitArgs *args)
{
/* Placeholder blank eeprom for chihiro:
* Serial number 000000000000
* Mac address 00:00:00:00:00:00
* ...etc.
*/
const uint8_t eeprom[] = {
0xA7, 0x65, 0x60, 0x76, 0xB7, 0x2F, 0xFE, 0xD8,
0x20, 0xBC, 0x8B, 0x15, 0x13, 0xBF, 0x73, 0x9C,
0x8C, 0x3F, 0xD8, 0x07, 0x75, 0x55, 0x5F, 0x8B,
0x09, 0xD1, 0x25, 0xD1, 0x1A, 0xA2, 0xD5, 0xB7,
0x01, 0x7D, 0x9A, 0x31, 0xCD, 0x9C, 0x83, 0x6B,
0x2C, 0xAB, 0xAD, 0x6F, 0xAC, 0x36, 0xDE, 0xEF,
0x6F, 0x6E, 0x2F, 0x6F, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
QemuOpts *machine_opts = qemu_opts_find(qemu_find_opts("machine"), NULL);
if (machine_opts) {
const char *mediaboard_rom_file =
qemu_opt_get(machine_opts, "mediaboard_rom");
const char *mediaboard_filesystem_file =
qemu_opt_get(machine_opts, "mediaboard_filesystem");
if (mediaboard_rom_file || mediaboard_filesystem_file) {
chihiro_ide_interface_init(mediaboard_rom_file,
mediaboard_filesystem_file);
}
}
ISABus *isa_bus;
xbox_init_common(args, (uint8_t*)eeprom, &isa_bus);
isa_create_simple(isa_bus, "chihiro-lpc");
}
static QEMUMachine chihiro_machine = {
.name = "chihiro",
.desc = "Sega Chihiro",
.init = chihiro_init,
.max_cpus = 1,
.no_floppy = 1,
.no_cdrom = 1,
.no_sdcard = 1,
PC_DEFAULT_MACHINE_OPTIONS
};
static void chihiro_machine_init(void) {
qemu_register_machine(&chihiro_machine);
}
machine_init(chihiro_machine_init);
+1
View File
@@ -0,0 +1 @@
obj-y += dsp.o dsp_cpu.o dsp_dma.o
+476
View File
@@ -0,0 +1,476 @@
/*
* MCPX DSP emulator
*
* Copyright (c) 2015 espes
*
* Adapted from Hatari DSP M56001 emulation
* (C) 2001-2008 ARAnyM developer team
* Adaption to Hatari (C) 2008 by Thomas Huth
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include "qemu-common.h"
#include "dsp_cpu.h"
#include "dsp_dma.h"
#include "dsp.h"
/* Defines */
#define BITMASK(x) ((1<<(x))-1)
#define ARRAYSIZE(x) (int)(sizeof(x)/sizeof(x[0]))
#define INTERRUPT_ABORT_FRAME (1 << 0)
#define INTERRUPT_START_FRAME (1 << 1)
#define INTERRUPT_DMA_EOL (1 << 7)
#define DPRINTF(s, ...) printf(s, ## __VA_ARGS__)
struct DSPState {
dsp_core_t core;
DSPDMAState dma;
int save_cycles;
uint32_t interrupts;
};
static uint32_t read_peripheral(dsp_core_t* core, uint32_t address);
static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value);
DSPState* dsp_init(void* scratch_rw_opaque, dsp_scratch_rw_func scratch_rw)
{
DPRINTF("dsp_init\n");
DSPState* dsp = (DSPState*)malloc(sizeof(DSPState));
memset(dsp, 0, sizeof(*dsp));
dsp->core.read_peripheral = read_peripheral;
dsp->core.write_peripheral = write_peripheral;
dsp->dma.core = &dsp->core;
dsp->dma.scratch_rw_opaque = scratch_rw_opaque;
dsp->dma.scratch_rw = scratch_rw;
dsp_reset(dsp);
return dsp;
}
void dsp_reset(DSPState* dsp)
{
dsp56k_reset_cpu(&dsp->core);
dsp->save_cycles = 0;
}
void dsp_destroy(DSPState* dsp)
{
free(dsp);
}
static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) {
DSPState* dsp = container_of(core, DSPState, core);
// printf("read_peripheral 0x%06x\n", address);
uint32_t v = 0xababa;
switch(address) {
case 0xFFFFC5:
v = dsp->interrupts;
if (dsp->dma.eol) {
v |= INTERRUPT_DMA_EOL;
}
break;
case 0xFFFFD4:
v = dsp_dma_read(&dsp->dma, DMA_NEXT_BLOCK);
break;
case 0xFFFFD5:
v = dsp_dma_read(&dsp->dma, DMA_START_BLOCK);
break;
case 0xFFFFD6:
v = dsp_dma_read(&dsp->dma, DMA_CONTROL);
break;
case 0xFFFFD7:
v = dsp_dma_read(&dsp->dma, DMA_CONFIGURATION);
break;
}
// printf(" -> 0x%06x\n", v);
return v;
}
static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value) {
DSPState* dsp = container_of(core, DSPState, core);
// printf("write_peripheral [0x%06x] = 0x%06x\n", address, value);
switch(address) {
case 0xFFFFC5:
dsp->interrupts &= ~value;
if (value & INTERRUPT_DMA_EOL) {
dsp->dma.eol = false;
}
break;
case 0xFFFFD4:
dsp_dma_write(&dsp->dma, DMA_NEXT_BLOCK, value);
break;
case 0xFFFFD5:
dsp_dma_write(&dsp->dma, DMA_START_BLOCK, value);
break;
case 0xFFFFD6:
dsp_dma_write(&dsp->dma, DMA_CONTROL, value);
break;
case 0xFFFFD7:
dsp_dma_write(&dsp->dma, DMA_CONFIGURATION, value);
break;
}
}
void dsp_step(DSPState* dsp)
{
dsp56k_execute_instruction(&dsp->core);
}
void dsp_run(DSPState* dsp, int cycles)
{
dsp->save_cycles += cycles;
if (dsp->save_cycles <= 0) return;
// if (unlikely(bDspDebugging)) {
// while (dsp->core.save_cycles > 0)
// {
// dsp56k_execute_instruction();
// dsp->core.save_cycles -= dsp->core.instr_cycle;
// DebugDsp_Check();
// }
// } else {
// printf("--> %d\n", dsp->core.save_cycles);
while (dsp->save_cycles > 0)
{
dsp56k_execute_instruction(&dsp->core);
dsp->save_cycles -= dsp->core.instr_cycle;
}
}
void dsp_bootstrap(DSPState* dsp)
{
// scratch memory is dma'd in to pram by the bootrom
dsp->dma.scratch_rw(dsp->dma.scratch_rw_opaque,
(uint8_t*)dsp->core.pram, 0, 0x800*4, false);
}
void dsp_start_frame(DSPState* dsp)
{
dsp->interrupts |= INTERRUPT_START_FRAME;
}
/**
* Disassemble DSP code between given addresses, return next PC address
*/
uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr)
{
uint32_t dsp_pc;
for (dsp_pc=lowerAdr; dsp_pc<=UpperAdr; dsp_pc++) {
dsp_pc += dsp56k_execute_one_disasm_instruction(&dsp->core, out, dsp_pc);
}
return dsp_pc;
}
uint32_t dsp_read_memory(DSPState* dsp, char space_id, uint32_t address)
{
int space;
switch (space_id) {
case 'X':
space = DSP_SPACE_X;
break;
case 'Y':
space = DSP_SPACE_Y;
break;
case 'P':
space = DSP_SPACE_P;
break;
default:
assert(false);
}
return dsp56k_read_memory(&dsp->core, space, address);
}
/**
* Output memory values between given addresses in given DSP address space.
* Return next DSP address value.
*/
uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space)
{
uint32_t mem, value;
for (mem = dsp_memdump_addr; mem <= dsp_memdump_upper; mem++) {
value = dsp_read_memory(dsp, space, mem);
printf("%04x %06x\n", mem, value);
}
return dsp_memdump_upper+1;
}
/**
* Show information on DSP core state which isn't
* shown by any of the other commands (dd, dm, dr).
*/
void dsp_info(DSPState* dsp)
{
int i, j;
const char *stackname[] = { "SSH", "SSL" };
printf("DSP core information:\n");
for (i = 0; i < ARRAYSIZE(stackname); i++) {
printf("- %s stack:", stackname[i]);
for (j = 0; j < ARRAYSIZE(dsp->core.stack[0]); j++) {
printf(" %04x", dsp->core.stack[i][j]);
}
printf("\n");
}
printf("- Interrupt IPL:");
for (i = 0; i < ARRAYSIZE(dsp->core.interrupt_ipl); i++) {
printf(" %04x", dsp->core.interrupt_ipl[i]);
}
printf("\n");
printf("- Pending ints: ");
for (i = 0; i < ARRAYSIZE(dsp->core.interrupt_is_pending); i++) {
printf(" %04hx", dsp->core.interrupt_is_pending[i]);
}
printf("\n");
}
/**
* Show DSP register contents
*/
void dsp_print_registers(DSPState* dsp)
{
uint32_t i;
printf("A: A2: %02x A1: %06x A0: %06x\n",
dsp->core.registers[DSP_REG_A2], dsp->core.registers[DSP_REG_A1], dsp->core.registers[DSP_REG_A0]);
printf("B: B2: %02x B1: %06x B0: %06x\n",
dsp->core.registers[DSP_REG_B2], dsp->core.registers[DSP_REG_B1], dsp->core.registers[DSP_REG_B0]);
printf("X: X1: %06x X0: %06x\n", dsp->core.registers[DSP_REG_X1], dsp->core.registers[DSP_REG_X0]);
printf("Y: Y1: %06x Y0: %06x\n", dsp->core.registers[DSP_REG_Y1], dsp->core.registers[DSP_REG_Y0]);
for (i=0; i<8; i++) {
printf("R%01x: %04x N%01x: %04x M%01x: %04x\n",
i, dsp->core.registers[DSP_REG_R0+i],
i, dsp->core.registers[DSP_REG_N0+i],
i, dsp->core.registers[DSP_REG_M0+i]);
}
printf("LA: %04x LC: %04x PC: %04x\n", dsp->core.registers[DSP_REG_LA], dsp->core.registers[DSP_REG_LC], dsp->core.pc);
printf("SR: %04x OMR: %02x\n", dsp->core.registers[DSP_REG_SR], dsp->core.registers[DSP_REG_OMR]);
printf("SP: %02x SSH: %04x SSL: %04x\n",
dsp->core.registers[DSP_REG_SP], dsp->core.registers[DSP_REG_SSH], dsp->core.registers[DSP_REG_SSL]);
}
/**
* Get given DSP register address and required bit mask.
* Works for A0-2, B0-2, LA, LC, M0-7, N0-7, R0-7, X0-1, Y0-1, PC, SR, SP,
* OMR, SSH & SSL registers, but note that the SP, SSH & SSL registers
* need special handling (in DSP*SetRegister()) when they are set.
* Return the register width in bits or zero for an error.
*/
int dsp_get_register_address(DSPState* dsp, const char *regname, uint32_t **addr, uint32_t *mask)
{
#define MAX_REGNAME_LEN 4
typedef struct {
const char name[MAX_REGNAME_LEN];
uint32_t *addr;
size_t bits;
uint32_t mask;
} reg_addr_t;
/* sorted by name so that this can be bisected */
const reg_addr_t registers[] = {
/* 56-bit A register */
{ "A0", &dsp->core.registers[DSP_REG_A0], 32, BITMASK(24) },
{ "A1", &dsp->core.registers[DSP_REG_A1], 32, BITMASK(24) },
{ "A2", &dsp->core.registers[DSP_REG_A2], 32, BITMASK(8) },
/* 56-bit B register */
{ "B0", &dsp->core.registers[DSP_REG_B0], 32, BITMASK(24) },
{ "B1", &dsp->core.registers[DSP_REG_B1], 32, BITMASK(24) },
{ "B2", &dsp->core.registers[DSP_REG_B2], 32, BITMASK(8) },
/* 16-bit LA & LC registers */
{ "LA", &dsp->core.registers[DSP_REG_LA], 32, BITMASK(16) },
{ "LC", &dsp->core.registers[DSP_REG_LC], 32, BITMASK(16) },
/* 16-bit M registers */
{ "M0", &dsp->core.registers[DSP_REG_M0], 32, BITMASK(16) },
{ "M1", &dsp->core.registers[DSP_REG_M1], 32, BITMASK(16) },
{ "M2", &dsp->core.registers[DSP_REG_M2], 32, BITMASK(16) },
{ "M3", &dsp->core.registers[DSP_REG_M3], 32, BITMASK(16) },
{ "M4", &dsp->core.registers[DSP_REG_M4], 32, BITMASK(16) },
{ "M5", &dsp->core.registers[DSP_REG_M5], 32, BITMASK(16) },
{ "M6", &dsp->core.registers[DSP_REG_M6], 32, BITMASK(16) },
{ "M7", &dsp->core.registers[DSP_REG_M7], 32, BITMASK(16) },
/* 16-bit N registers */
{ "N0", &dsp->core.registers[DSP_REG_N0], 32, BITMASK(16) },
{ "N1", &dsp->core.registers[DSP_REG_N1], 32, BITMASK(16) },
{ "N2", &dsp->core.registers[DSP_REG_N2], 32, BITMASK(16) },
{ "N3", &dsp->core.registers[DSP_REG_N3], 32, BITMASK(16) },
{ "N4", &dsp->core.registers[DSP_REG_N4], 32, BITMASK(16) },
{ "N5", &dsp->core.registers[DSP_REG_N5], 32, BITMASK(16) },
{ "N6", &dsp->core.registers[DSP_REG_N6], 32, BITMASK(16) },
{ "N7", &dsp->core.registers[DSP_REG_N7], 32, BITMASK(16) },
{ "OMR", &dsp->core.registers[DSP_REG_OMR], 32, 0x5f },
/* 16-bit program counter */
{ "PC", (uint32_t*)(&dsp->core.pc), 24, BITMASK(24) },
/* 16-bit DSP R (address) registers */
{ "R0", &dsp->core.registers[DSP_REG_R0], 32, BITMASK(16) },
{ "R1", &dsp->core.registers[DSP_REG_R1], 32, BITMASK(16) },
{ "R2", &dsp->core.registers[DSP_REG_R2], 32, BITMASK(16) },
{ "R3", &dsp->core.registers[DSP_REG_R3], 32, BITMASK(16) },
{ "R4", &dsp->core.registers[DSP_REG_R4], 32, BITMASK(16) },
{ "R5", &dsp->core.registers[DSP_REG_R5], 32, BITMASK(16) },
{ "R6", &dsp->core.registers[DSP_REG_R6], 32, BITMASK(16) },
{ "R7", &dsp->core.registers[DSP_REG_R7], 32, BITMASK(16) },
{ "SSH", &dsp->core.registers[DSP_REG_SSH], 32, BITMASK(16) },
{ "SSL", &dsp->core.registers[DSP_REG_SSL], 32, BITMASK(16) },
{ "SP", &dsp->core.registers[DSP_REG_SP], 32, BITMASK(6) },
/* 16-bit status register */
{ "SR", &dsp->core.registers[DSP_REG_SR], 32, 0xefff },
/* 48-bit X register */
{ "X0", &dsp->core.registers[DSP_REG_X0], 32, BITMASK(24) },
{ "X1", &dsp->core.registers[DSP_REG_X1], 32, BITMASK(24) },
/* 48-bit Y register */
{ "Y0", &dsp->core.registers[DSP_REG_Y0], 32, BITMASK(24) },
{ "Y1", &dsp->core.registers[DSP_REG_Y1], 32, BITMASK(24) }
};
/* left, right, middle, direction */
int l, r, m, dir = 0;
unsigned int i, len;
char reg[MAX_REGNAME_LEN];
for (i = 0; i < sizeof(reg) && regname[i]; i++) {
reg[i] = toupper(regname[i]);
}
if (i < 2 || regname[i]) {
/* too short or longer than any of the names */
return 0;
}
len = i;
/* bisect */
l = 0;
r = ARRAYSIZE(registers) - 1;
do {
m = (l+r) >> 1;
for (i = 0; i < len; i++) {
dir = (int)reg[i] - registers[m].name[i];
if (dir) {
break;
}
}
if (dir == 0) {
*addr = registers[m].addr;
*mask = registers[m].mask;
return registers[m].bits;
}
if (dir < 0) {
r = m-1;
} else {
l = m+1;
}
} while (l <= r);
#undef MAX_REGNAME_LEN
return 0;
}
/**
* Set given DSP register value, return false if unknown register given
*/
bool dsp_disasm_set_register(DSPState* dsp, const char *arg, uint32_t value)
{
uint32_t *addr, mask, sp_value;
int bits;
/* first check registers needing special handling... */
if (arg[0]=='S' || arg[0]=='s') {
if (arg[1]=='P' || arg[1]=='p') {
dsp->core.registers[DSP_REG_SP] = value & BITMASK(6);
value &= BITMASK(4);
dsp->core.registers[DSP_REG_SSH] = dsp->core.stack[0][value];
dsp->core.registers[DSP_REG_SSL] = dsp->core.stack[1][value];
return true;
}
if (arg[1]=='S' || arg[1]=='s') {
sp_value = dsp->core.registers[DSP_REG_SP] & BITMASK(4);
if (arg[2]=='H' || arg[2]=='h') {
if (sp_value == 0) {
dsp->core.registers[DSP_REG_SSH] = 0;
dsp->core.stack[0][sp_value] = 0;
} else {
dsp->core.registers[DSP_REG_SSH] = value & BITMASK(16);
dsp->core.stack[0][sp_value] = value & BITMASK(16);
}
return true;
}
if (arg[2]=='L' || arg[2]=='l') {
if (sp_value == 0) {
dsp->core.registers[DSP_REG_SSL] = 0;
dsp->core.stack[1][sp_value] = 0;
} else {
dsp->core.registers[DSP_REG_SSL] = value & BITMASK(16);
dsp->core.stack[1][sp_value] = value & BITMASK(16);
}
return true;
}
}
}
/* ...then registers where address & mask are enough */
bits = dsp_get_register_address(dsp, arg, &addr, &mask);
switch (bits) {
case 32:
*addr = value & mask;
return true;
case 16:
*(uint16_t*)addr = value & mask;
return true;
}
return false;
}
+59
View File
@@ -0,0 +1,59 @@
/*
* MCPX DSP emulator
* Copyright (c) 2015 espes
* Adapted from Hatari DSP M56001 emulation
* (C) 2001-2008 ARAnyM developer team
* Adaption to Hatari (C) 2008 by Thomas Huth
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DSP_H
#define DSP_H
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
typedef struct DSPState DSPState;
typedef void (*dsp_scratch_rw_func)(
void* opaque, uint8_t* ptr, uint32_t addr, size_t len, bool dir);
/* Dsp commands */
DSPState* dsp_init(void* scratch_rw_opaque, dsp_scratch_rw_func scratch_rw);
void dsp_destroy(DSPState* dsp);
void dsp_reset(DSPState* dsp);
void dsp_step(DSPState* dsp);
void dsp_run(DSPState* dsp, int cycles);
void dsp_bootstrap(DSPState* dsp);
void dsp_start_frame(DSPState* dsp);
/* Dsp Debugger commands */
uint32_t dsp_read_memory(DSPState* dsp, char space, uint32_t addr);
uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space);
uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr);
void dsp_info(DSPState* dsp);
void dsp_print_registers(DSPState* dsp);
int dsp_get_register_address(DSPState* dsp, const char *arg, uint32_t **addr, uint32_t *mask);
bool dsp_disasm_set_register(DSPState* dsp, const char *arg, uint32_t value);
#endif /* DSP_H */
File diff suppressed because it is too large Load Diff
+257
View File
@@ -0,0 +1,257 @@
/*
* DSP56300 emulator
*
* Copyright (c) 2015 espes
*
* Adapted from Hatari DSP M56001 emulation
* (C) 2003-2008 ARAnyM developer team
* Adaption to Hatari (C) 2008 by Thomas Huth
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DSP_CPU_H
#define DSP_CPU_H
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#define DSP_OMR_MA 0x00
#define DSP_OMR_MB 0x01
#define DSP_OMR_DE 0x02
#define DSP_OMR_SD 0x06
#define DSP_OMR_EA 0x07
#define DSP_SR_C 0x00
#define DSP_SR_V 0x01
#define DSP_SR_Z 0x02
#define DSP_SR_N 0x03
#define DSP_SR_U 0x04
#define DSP_SR_E 0x05
#define DSP_SR_L 0x06
#define DSP_SR_I0 0x08
#define DSP_SR_I1 0x09
#define DSP_SR_S0 0x0a
#define DSP_SR_S1 0x0b
#define DSP_SR_T 0x0d
#define DSP_SR_LF 0x0f
#define DSP_SP_SE 0x04
#define DSP_SP_UF 0x05
/* Registers numbers in dsp.registers[] */
#define DSP_REG_X0 0x04
#define DSP_REG_X1 0x05
#define DSP_REG_Y0 0x06
#define DSP_REG_Y1 0x07
#define DSP_REG_A0 0x08
#define DSP_REG_B0 0x09
#define DSP_REG_A2 0x0a
#define DSP_REG_B2 0x0b
#define DSP_REG_A1 0x0c
#define DSP_REG_B1 0x0d
#define DSP_REG_A 0x0e
#define DSP_REG_B 0x0f
#define DSP_REG_R0 0x10
#define DSP_REG_R1 0x11
#define DSP_REG_R2 0x12
#define DSP_REG_R3 0x13
#define DSP_REG_R4 0x14
#define DSP_REG_R5 0x15
#define DSP_REG_R6 0x16
#define DSP_REG_R7 0x17
#define DSP_REG_N0 0x18
#define DSP_REG_N1 0x19
#define DSP_REG_N2 0x1a
#define DSP_REG_N3 0x1b
#define DSP_REG_N4 0x1c
#define DSP_REG_N5 0x1d
#define DSP_REG_N6 0x1e
#define DSP_REG_N7 0x1f
#define DSP_REG_M0 0x20
#define DSP_REG_M1 0x21
#define DSP_REG_M2 0x22
#define DSP_REG_M3 0x23
#define DSP_REG_M4 0x24
#define DSP_REG_M5 0x25
#define DSP_REG_M6 0x26
#define DSP_REG_M7 0x27
#define DSP_REG_SR 0x39
#define DSP_REG_OMR 0x3a
#define DSP_REG_SP 0x3b
#define DSP_REG_SSH 0x3c
#define DSP_REG_SSL 0x3d
#define DSP_REG_LA 0x3e
#define DSP_REG_LC 0x3f
#define DSP_REG_NULL 0x00
#define DSP_REG_LCSAVE 0x30
#define DSP_REG_MAX 0x40
/* Memory spaces for dsp.ram[], dsp.rom[] */
#define DSP_SPACE_X 0x00
#define DSP_SPACE_Y 0x01
#define DSP_SPACE_P 0x02
#define DSP_XRAM_SIZE 3072
#define DSP_YRAM_SIZE 2048
#define DSP_PRAM_SIZE 4096
#define DSP_MIXBUFFER_BASE 3072
#define DSP_MIXBUFFER_SIZE 1024
#define DSP_MIXBUFFER_READ_BASE 5120
#define DSP_PERIPH_BASE 0xFFFF80
#define DSP_PERIPH_SIZE 128
#define DSP_INTERRUPT_NONE 0x0
#define DSP_INTERRUPT_DISABLED 0x1
#define DSP_INTERRUPT_LONG 0x2
#define DSP_INTER_RESET 0x0
#define DSP_INTER_ILLEGAL 0x1
#define DSP_INTER_STACK_ERROR 0x2
#define DSP_INTER_TRACE 0x3
#define DSP_INTER_SWI 0x4
#define DSP_INTER_HOST_COMMAND 0x5
#define DSP_INTER_HOST_RCV_DATA 0x6
#define DSP_INTER_HOST_TRX_DATA 0x7
#define DSP_INTER_SSI_RCV_DATA_E 0x8
#define DSP_INTER_SSI_RCV_DATA 0x9
#define DSP_INTER_SSI_TRX_DATA_E 0xa
#define DSP_INTER_SSI_TRX_DATA 0xb
typedef enum {
DSP_TRACE_MODE,
DSP_DISASM_MODE
} dsp_trace_disasm_t;
typedef struct dsp_interrupt_s {
const uint16_t inter;
const uint16_t vectorAddr;
const uint16_t periph;
const char *name;
} dsp_interrupt_t;
typedef struct dsp_core_s dsp_core_t;
struct dsp_core_s {
/* DSP instruction Cycle counter */
uint16_t instr_cycle;
/* Registers */
uint32_t pc;
uint32_t registers[DSP_REG_MAX];
/* stack[0=ssh], stack[1=ssl] */
uint32_t stack[2][16];
uint32_t xram[DSP_XRAM_SIZE];
uint32_t yram[DSP_YRAM_SIZE];
uint32_t pram[DSP_PRAM_SIZE];
uint32_t mixbuffer[DSP_MIXBUFFER_SIZE];
/* peripheral space, x:0xffff80-0xffffff */
uint32_t periph[DSP_PERIPH_SIZE];
/* Misc */
uint32_t loop_rep; /* executing rep ? */
uint32_t pc_on_rep; /* True if PC is on REP instruction */
/* Interruptions */
uint16_t interrupt_state; /* NONE, FAST or LONG interrupt */
uint16_t interrupt_instr_fetch; /* vector of the current interrupt */
uint16_t interrupt_save_pc; /* save next pc value before interrupt */
uint16_t interrupt_counter; /* count number of pending interrupts */
uint16_t interrupt_ipl_to_raise; /* save the IPL level to save in the SR register */
uint16_t interrupt_pipeline_count; /* used to prefetch correctly the 2 inter instructions */
int16_t interrupt_ipl[12]; /* store the current IPL for each interrupt */
uint16_t interrupt_is_pending[12]; /* store if interrupt is pending for each interrupt */
/* callbacks */
uint32_t (*read_peripheral)(dsp_core_t* core, uint32_t address);
void (*write_peripheral)(dsp_core_t* core, uint32_t address, uint32_t value);
/* runtime data */
/* Instructions per second */
#ifdef DSP_COUNT_IPS
uint32_t start_time;
#endif
uint32_t num_inst;
/* Length of current instruction */
uint32_t cur_inst_len; /* =0:jump, >0:increment */
/* Current instruction */
uint32_t cur_inst;
/* DSP is in disasm mode ? */
/* If yes, stack overflow, underflow and illegal instructions messages are not displayed */
bool executing_for_disasm;
char str_disasm_memory[2][50]; /* Buffer for memory change text in disasm mode */
uint32_t disasm_memory_ptr; /* Pointer for memory change in disasm mode */
bool exception_debugging;
/* disasm data */
/* Previous instruction */
uint32_t disasm_prev_inst_pc;
bool disasm_is_looping;
/* Used to display dc instead of unknown instruction for illegal opcodes */
dsp_trace_disasm_t disasm_mode;
uint32_t disasm_cur_inst;
uint16_t disasm_cur_inst_len;
/* Current instruction */
char disasm_str_instr[128];
char disasm_str_instr2[128];
char disasm_parallelmove_name[64];
/**********************************
* Register change
**********************************/
uint32_t disasm_registers_save[64];
#ifdef DSP_DISASM_REG_PC
uint32_t pc_save;
#endif
};
/* Functions */
void dsp56k_reset_cpu(dsp_core_t* dsp); /* Set dsp_core to use */
void dsp56k_execute_instruction(dsp_core_t* dsp); /* Execute 1 instruction */
uint16_t dsp56k_execute_one_disasm_instruction(dsp_core_t* dsp, FILE *out, uint32_t pc); /* Execute 1 instruction in disasm mode */
uint32_t dsp56k_read_memory(dsp_core_t* dsp, int space, uint32_t address);
void dsp56k_write_memory(dsp_core_t* dsp, int space, uint32_t address, uint32_t value);
/* Interrupt relative functions */
void dsp56k_add_interrupt(dsp_core_t* dsp, uint16_t inter);
#endif /* DSP_CPU_H */
File diff suppressed because it is too large Load Diff
+247
View File
@@ -0,0 +1,247 @@
/*
* MCPX DSP DMA
*
* Copyright (c) 2015 espes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include "dsp_dma.h"
#define DMA_CONFIGURATION_AUTOSTART (1 << 0)
#define DMA_CONFIGURATION_AUTOREADY (1 << 1)
#define DMA_CONFIGURATION_IOC_CLEAR (1 << 2)
#define DMA_CONFIGURATION_EOL_CLEAR (1 << 3)
#define DMA_CONFIGURATION_ERR_CLEAR (1 << 4)
#define DMA_CONTROL_ACTION 0x7
#define DMA_CONTROL_ACTION_NOP 0
#define DMA_CONTROL_ACTION_START 1
#define DMA_CONTROL_ACTION_STOP 2
#define DMA_CONTROL_ACTION_FREEZE 3
#define DMA_CONTROL_ACTION_UNFREEZE 4
#define DMA_CONTROL_ACTION_ABORT 5
#define DMA_CONTROL_FROZEN (1 << 3)
#define DMA_CONTROL_RUNNING (1 << 4)
#define DMA_CONTROL_STOPPED (1 << 5)
#define NODE_POINTER_VAL 0x3fff
#define NODE_POINTER_EOL (1 << 14)
#define NODE_CONTROL_DIRECTION (1 << 1)
// #define DEBUG
#ifdef DEBUG
# define DPRINTF(s, ...) printf(s, ## __VA_ARGS__)
#else
# define DPRINTF(s, ...) do { } while (0)
#endif
static void dsp_dma_run(DSPDMAState *s)
{
if (!(s->control & DMA_CONTROL_RUNNING)
|| (s->control & DMA_CONTROL_FROZEN)) {
return;
}
while (!(s->next_block & NODE_POINTER_EOL)) {
uint32_t addr = s->next_block & NODE_POINTER_VAL;
assert((addr+6) < sizeof(s->core->xram));
uint32_t next_block = dsp56k_read_memory(s->core, DSP_SPACE_X, addr);
uint32_t control = dsp56k_read_memory(s->core, DSP_SPACE_X, addr+1);
uint32_t count = dsp56k_read_memory(s->core, DSP_SPACE_X, addr+2);
uint32_t dsp_offset = dsp56k_read_memory(s->core, DSP_SPACE_X, addr+3);
uint32_t scratch_offset = dsp56k_read_memory(s->core, DSP_SPACE_X, addr+4);
uint32_t scratch_base = dsp56k_read_memory(s->core, DSP_SPACE_X, addr+5);
uint32_t scratch_size = dsp56k_read_memory(s->core, DSP_SPACE_X, addr+6)+1;
s->next_block = next_block;
if (s->next_block & NODE_POINTER_EOL) {
s->eol = true;
}
DPRINTF("\n\n\nDMA addr %x, control %x, count %x, "
"dsp_offset %x, scratch_offset %x, base %x, size %x\n\n\n",
addr, control, count, dsp_offset,
scratch_offset, scratch_base, scratch_size);
uint32_t format = (control >> 10) & 7;
unsigned int item_size;
uint32_t item_mask = 0xffffffff;
switch(format) {
case 1:
item_size = 2;
break;
case 2: //big-endian?
case 6:
item_size = 4;
item_mask = 0x00FFFFFF;
break;
default:
fprintf(stderr, "Unknown dsp dma format: 0x%x\n", format);
assert(false);
break;
}
uint32_t buf_id = (control >> 5) & 0xf;
size_t scratch_addr;
if (buf_id == 0xe) { // 'circular'?
// assert(scratch_offset == 0);
// assert(scratch_offset + count * item_size < scratch_size);
if (scratch_offset + count * item_size >= scratch_size) {
// This happens during the startup sound effect.
// I think it might actually be a bug in the code...
DPRINTF("skipping bad dma...\n");
continue;
}
scratch_addr = scratch_base + scratch_offset; //??
} else {
// assert(buf_id == 0xf) // 'offset'
scratch_addr = scratch_offset;
}
uint32_t mem_address;
int mem_space;
if (dsp_offset < 0x1800) {
assert(dsp_offset+count < 0x1800);
mem_space = DSP_SPACE_X;
mem_address = dsp_offset;
} else if (dsp_offset >= 0x1800 && dsp_offset < 0x2000) { //?
assert(dsp_offset+count < 0x2000);
mem_space = DSP_SPACE_Y;
mem_address = dsp_offset - 0x1800;
} else if (dsp_offset >= 0x2800 && dsp_offset < 0x3800) { //?
assert(dsp_offset+count < 0x3800);
mem_space = DSP_SPACE_P;
mem_address = dsp_offset - 0x2800;
} else {
assert(false);
}
uint8_t* scratch_buf = calloc(count, item_size);
if (control & NODE_CONTROL_DIRECTION) {
int i;
for (i=0; i<count; i++) {
uint32_t v = dsp56k_read_memory(s->core,
mem_space, mem_address+i);
switch(item_size) {
case 2:
*(uint16_t*)(scratch_buf + i*2) = v;
break;
case 4:
*(uint32_t*)(scratch_buf + i*4) = v;
break;
default:
assert(false);
break;
}
}
// write to scratch memory
s->scratch_rw(s->scratch_rw_opaque,
scratch_buf, scratch_addr, count*item_size, 1);
} else {
// read from scratch memory
s->scratch_rw(s->scratch_rw_opaque,
scratch_buf, scratch_addr, count*item_size, 0);
int i;
for (i=0; i<count; i++) {
uint32_t v;
switch(item_size) {
case 2:
v = *(uint16_t*)(scratch_buf + i*2);
break;
case 4:
v = (*(uint32_t*)(scratch_buf + i*4)) & item_mask;
break;
default:
assert(false);
break;
}
// DPRINTF("... %06x\n", v);
dsp56k_write_memory(s->core, mem_space, mem_address+i, v);
}
}
free(scratch_buf);
}
}
uint32_t dsp_dma_read(DSPDMAState *s, DSPDMARegister reg)
{
switch (reg) {
case DMA_CONFIGURATION:
return s->configuration;
case DMA_CONTROL:
return s->control;
case DMA_START_BLOCK:
return s->start_block;
case DMA_NEXT_BLOCK:
return s->next_block;
default:
assert(false);
}
return 0;
}
void dsp_dma_write(DSPDMAState *s, DSPDMARegister reg, uint32_t v)
{
switch (reg) {
case DMA_CONFIGURATION:
s->configuration = v;
break;
case DMA_CONTROL:
switch(v & DMA_CONTROL_ACTION) {
case DMA_CONTROL_ACTION_START:
s->control |= DMA_CONTROL_RUNNING;
s->control &= ~DMA_CONTROL_STOPPED;
break;
case DMA_CONTROL_ACTION_STOP:
s->control |= DMA_CONTROL_STOPPED;
s->control &= ~DMA_CONTROL_RUNNING;
break;
case DMA_CONTROL_ACTION_FREEZE:
s->control |= DMA_CONTROL_FROZEN;
break;
case DMA_CONTROL_ACTION_UNFREEZE:
s->control &= ~DMA_CONTROL_FROZEN;
break;
default:
assert(false);
break;
}
dsp_dma_run(s);
break;
case DMA_START_BLOCK:
s->start_block = v;
break;
case DMA_NEXT_BLOCK:
s->next_block = v;
break;
default:
assert(false);
}
}
+54
View File
@@ -0,0 +1,54 @@
/*
* MCPX DSP DMA
*
* Copyright (c) 2015 espes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DSP_DMA_H
#define DSP_DMA_H
#include <stdint.h>
#include <stdbool.h>
#include "dsp.h"
#include "dsp_cpu.h"
typedef enum DSPDMARegister {
DMA_CONFIGURATION,
DMA_CONTROL,
DMA_START_BLOCK,
DMA_NEXT_BLOCK,
} DSPDMARegister;
typedef struct DSPDMAState {
dsp_core_t* core;
void* scratch_rw_opaque;
dsp_scratch_rw_func scratch_rw;
uint32_t configuration;
uint32_t control;
uint32_t start_block;
uint32_t next_block;
bool error;
bool eol;
} DSPDMAState;
uint32_t dsp_dma_read(DSPDMAState *s, DSPDMARegister reg);
void dsp_dma_write(DSPDMAState *s, DSPDMARegister reg, uint32_t v);
#endif
File diff suppressed because it is too large Load Diff
+338
View File
@@ -0,0 +1,338 @@
/* g-lru-cache.c
*
* Copyright (C) 2009 - Christian Hergert
*
* This 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 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Ideally, you want to use fast_get. This is because we are using a
* GStaticRWLock which is indeed slower than a mutex if you have lots of writer
* acquisitions. This doesn't make it a true LRU, though, as the oldest
* retrieval from strorage is the first item evicted.
*/
#include "g-lru-cache.h"
// #define DEBUG
#define LRU_CACHE_PRIVATE(object) \
(G_TYPE_INSTANCE_GET_PRIVATE((object), \
G_TYPE_LRU_CACHE, \
GLruCachePrivate))
struct _GLruCachePrivate
{
GStaticRWLock rw_lock;
guint max_size;
gboolean fast_get;
GHashTable *hash_table;
GEqualFunc key_equal_func;
GCopyFunc key_copy_func;
GList *newest;
GList *oldest;
GLookupFunc retrieve_func;
gpointer user_data;
GDestroyNotify user_destroy_func;
};
G_DEFINE_TYPE (GLruCache, g_lru_cache, G_TYPE_OBJECT);
static void
g_lru_cache_finalize (GObject *object)
{
GLruCachePrivate *priv = LRU_CACHE_PRIVATE (object);
if (priv->user_data && priv->user_destroy_func)
priv->user_destroy_func (priv->user_data);
priv->user_data = NULL;
priv->user_destroy_func = NULL;
g_hash_table_destroy (priv->hash_table);
priv->hash_table = NULL;
g_list_free (priv->newest);
priv->newest = NULL;
priv->oldest = NULL;
G_OBJECT_CLASS (g_lru_cache_parent_class)->finalize (object);
}
static void
g_lru_cache_class_init (GLruCacheClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = g_lru_cache_finalize;
g_type_class_add_private (object_class, sizeof (GLruCachePrivate));
}
static void
g_lru_cache_init (GLruCache *self)
{
self->priv = LRU_CACHE_PRIVATE (self);
self->priv->max_size = 1024;
self->priv->fast_get = FALSE;
g_static_rw_lock_init (&self->priv->rw_lock);
}
static void
g_lru_cache_evict_n_oldest_locked (GLruCache *self, gint n)
{
GList *victim;
gint i;
for (i = 0; i < n; i++)
{
victim = self->priv->oldest;
if (victim == NULL)
return;
if (victim->prev)
victim->prev->next = NULL;
self->priv->oldest = victim->prev;
g_hash_table_remove (self->priv->hash_table, victim->data);
if (self->priv->newest == victim)
self->priv->newest = NULL;
g_list_free1 (victim); /* victim->data is owned by hashtable */
}
#ifdef DEBUG
g_assert (g_hash_table_size (self->priv->hash_table) == g_list_length (self->priv->newest));
#endif
}
GLruCache*
g_lru_cache_new (GHashFunc hash_func,
GEqualFunc key_equal_func,
GCopyFunc key_copy_func,
GLookupFunc retrieve_func,
GDestroyNotify key_destroy_func,
GDestroyNotify value_destroy_func,
gpointer user_data,
GDestroyNotify user_destroy_func)
{
GLruCache *self = g_object_new (G_TYPE_LRU_CACHE, NULL);
self->priv->hash_table = g_hash_table_new_full (hash_func,
key_equal_func,
key_destroy_func,
value_destroy_func);
self->priv->key_equal_func = key_equal_func;
self->priv->key_copy_func = key_copy_func;
self->priv->retrieve_func = retrieve_func;
self->priv->user_data = user_data;
self->priv->user_destroy_func = user_destroy_func;
return self;
}
void
g_lru_cache_set_max_size (GLruCache *self, guint max_size)
{
g_return_if_fail (G_IS_LRU_CACHE (self));
guint old_max_size = self->priv->max_size;
g_static_rw_lock_writer_lock (&(self->priv->rw_lock));
self->priv->max_size = max_size;
if (old_max_size > max_size)
g_lru_cache_evict_n_oldest_locked (self, old_max_size - max_size);
g_static_rw_lock_writer_unlock (&(self->priv->rw_lock));
}
guint
g_lru_cache_get_max_size (GLruCache *self)
{
g_return_val_if_fail (G_IS_LRU_CACHE (self), -1);
return self->priv->max_size;
}
guint
g_lru_cache_get_size (GLruCache *self)
{
g_return_val_if_fail (G_IS_LRU_CACHE (self), -1);
return g_hash_table_size (self->priv->hash_table);
}
gpointer
g_lru_cache_get (GLruCache *self, gpointer key)
{
g_return_val_if_fail (G_IS_LRU_CACHE (self), NULL);
gpointer value;
g_static_rw_lock_reader_lock (&(self->priv->rw_lock));
value = g_hash_table_lookup (self->priv->hash_table, key);
#ifdef DEBUG
if (value)
g_debug ("Cache Hit!");
else
g_debug ("Cache miss");
#endif
g_static_rw_lock_reader_unlock (&(self->priv->rw_lock));
if (!value)
{
g_static_rw_lock_writer_lock (&(self->priv->rw_lock));
if (!g_hash_table_lookup (self->priv->hash_table, key))
{
if (g_hash_table_size (self->priv->hash_table) >= self->priv->max_size)
#ifdef DEBUG
{
g_debug ("We are at capacity, must evict oldest");
#endif
g_lru_cache_evict_n_oldest_locked (self, 1);
#ifdef DEBUG
}
g_debug ("Retrieving value from external resource");
#endif
value = self->priv->retrieve_func (key, self->priv->user_data);
if (self->priv->key_copy_func)
g_hash_table_insert (self->priv->hash_table,
self->priv->key_copy_func (key, self->priv->user_data),
value);
else
g_hash_table_insert (self->priv->hash_table, key, value);
self->priv->newest = g_list_prepend (self->priv->newest, key);
if (self->priv->oldest == NULL)
self->priv->oldest = self->priv->newest;
}
#ifdef DEBUG
else g_debug ("Lost storage race with another thread");
#endif
g_static_rw_lock_writer_unlock (&(self->priv->rw_lock));
}
/* fast_get means that we do not reposition the item to the head
* of the list. it essentially makes the lru, a lru from storage,
* not lru to user.
*/
else if (!self->priv->fast_get &&
!self->priv->key_equal_func (key, self->priv->newest->data))
{
#ifdef DEBUG
g_debug ("Making item most recent");
#endif
g_static_rw_lock_writer_lock (&(self->priv->rw_lock));
GList *list = self->priv->newest;
GList *tmp;
GEqualFunc equal = self->priv->key_equal_func;
for (tmp = list; tmp; tmp = tmp->next)
{
if (equal (key, tmp->data))
{
GList *tmp1 = g_list_remove_link (list, tmp);
self->priv->newest = g_list_prepend (tmp1, tmp);
break;
}
}
g_static_rw_lock_writer_unlock (&(self->priv->rw_lock));
}
return value;
}
void
g_lru_cache_evict (GLruCache *self, gpointer key)
{
g_return_if_fail (G_IS_LRU_CACHE (self));
GEqualFunc equal = self->priv->key_equal_func;
GList *list = NULL;
g_static_rw_lock_writer_lock (&(self->priv->rw_lock));
if (equal (key, self->priv->oldest))
{
g_lru_cache_evict_n_oldest_locked (self, 1);
}
else
{
for (list = self->priv->newest; list; list = list->next)
{
/* key, list->data is owned by hashtable */
if (equal (key, list->data))
{
self->priv->newest = g_list_remove_link (self->priv->newest, list);
g_list_free (list);
break;
}
}
g_hash_table_remove (self->priv->hash_table, key);
}
g_static_rw_lock_writer_unlock (&(self->priv->rw_lock));
}
void
g_lru_cache_clear (GLruCache *self)
{
g_return_if_fail (G_IS_LRU_CACHE (self));
g_static_rw_lock_writer_lock (&(self->priv->rw_lock));
g_hash_table_remove_all (self->priv->hash_table);
g_list_free (self->priv->newest);
self->priv->oldest = NULL;
self->priv->newest = NULL;
g_static_rw_lock_writer_unlock (&(self->priv->rw_lock));
}
void
g_lru_cache_set_fast_get (GLruCache *self, gboolean fast_get)
{
g_return_if_fail (G_IS_LRU_CACHE (self));
self->priv->fast_get = fast_get;
}
gboolean
g_lru_cache_get_fast_get (GLruCache *self)
{
g_return_val_if_fail (G_IS_LRU_CACHE (self), FALSE);
return self->priv->fast_get;
}
+80
View File
@@ -0,0 +1,80 @@
/* g-lru-cache.h
*
* Copyright (C) 2009 - Christian Hergert
*
* This 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 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __G_LRU_CACHE_H__
#define __G_LRU_CACHE_H__
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define G_TYPE_LRU_CACHE (g_lru_cache_get_type ())
#define G_LRU_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_LRU_CACHE, GLruCache))
#define G_LRU_CACHE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_LRU_CACHE, GLruCache const))
#define G_LRU_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_LRU_CACHE, GLruCacheClass))
#define G_IS_LRU_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_LRU_CACHE))
#define G_IS_LRU_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_LRU_CACHE))
#define G_LRU_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_LRU_CACHE, GLruCacheClass))
#define G_LOOKUP_FUNC(func) ((GLookupFunc)func)
typedef struct _GLruCache GLruCache;
typedef struct _GLruCacheClass GLruCacheClass;
typedef struct _GLruCachePrivate GLruCachePrivate;
typedef gpointer (*GLookupFunc) (gpointer key, gpointer user_data);
struct _GLruCache
{
GObject parent;
GLruCachePrivate *priv;
};
struct _GLruCacheClass
{
GObjectClass parent_class;
};
GType g_lru_cache_get_type (void) G_GNUC_CONST;
GLruCache* g_lru_cache_new (GHashFunc hash_func,
GEqualFunc key_equal_func,
GCopyFunc key_copy_func,
GLookupFunc retrieve_func,
GDestroyNotify key_destroy_func,
GDestroyNotify value_destroy_func,
gpointer user_data,
GDestroyNotify user_destroy_func);
void g_lru_cache_set_max_size (GLruCache *self, guint max_size);
guint g_lru_cache_get_max_size (GLruCache *self);
guint g_lru_cache_get_size (GLruCache *self);
gpointer g_lru_cache_get (GLruCache *self, gpointer key);
void g_lru_cache_evict (GLruCache *self, gpointer key);
void g_lru_cache_clear (GLruCache *self);
gboolean g_lru_cache_get_fast_get (GLruCache *self);
void g_lru_cache_set_fast_get (GLruCache *self, gboolean fast_get);
G_END_DECLS
#endif /* __G_LRU_CACHE_H__ */
+247
View File
@@ -0,0 +1,247 @@
/*
* QEMU SMSC LPC47M157 (Super I/O)
*
* Copyright (c) 2013 espes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/isa/isa.h"
#include "hw/char/serial.h"
#include "sysemu/sysemu.h"
#include "sysemu/char.h"
#include "qapi/qmp/qerror.h"
#define MAX_DEVICE 0xC
#define DEVICE_FDD 0x0
#define DEVICE_PARALLEL_PORT 0x3
#define DEVICE_SERIAL_PORT_1 0x4
#define DEVICE_SERIAL_PORT_2 0x5
#define DEVICE_KEYBOARD 0x7
#define DEVICE_GAME_PORT 0x9
#define DEVICE_PME 0xA
#define DEVICE_MPU_401 0xB
#define ENTER_CONFIG_KEY 0x55
#define EXIT_CONFIG_KEY 0xAA
#define MAX_CONFIG_REG 0x30
#define MAX_DEVICE_REGS 0xFF
#define CONFIG_DEVICE_NUMBER 0x07
#define CONFIG_PORT_LOW 0x26
#define CONFIG_PORT_HIGH 0x27
#define CONFIG_DEVICE_ACTIVATE 0x30
#define CONFIG_DEVICE_BASE_ADDRESS_HIGH 0x60
#define CONFIG_DEVICE_BASE_ADDRESS_LOW 0x61
#define CONFIG_DEVICE_INETRRUPT 0x70
#define DEBUG_LPC47M157
typedef struct LPC47M157State {
ISADevice dev;
MemoryRegion io;
bool configuration_mode;
uint32_t selected_reg;
uint8_t config_regs[MAX_CONFIG_REG];
uint8_t device_regs[MAX_DEVICE][MAX_DEVICE_REGS];
struct {
bool active;
SerialState state;
} serial[2];
} LPC47M157State;
#define LPC47M157_DEVICE(obj) \
OBJECT_CHECK(LPC47M157State, (obj), "lpc47m157")
static void update_devices(LPC47M157State *s)
{
ISADevice *isadev = ISA_DEVICE(s);
/* init serial devices */
int i;
for (i=0; i<2; i++) {
uint8_t *dev = s->device_regs[DEVICE_SERIAL_PORT_1 + i];
if (dev[CONFIG_DEVICE_ACTIVATE] && !s->serial[i].active) {
uint32_t iobase = (dev[CONFIG_DEVICE_BASE_ADDRESS_HIGH] << 8)
| dev[CONFIG_DEVICE_BASE_ADDRESS_LOW];
uint32_t irq = dev[CONFIG_DEVICE_INETRRUPT];
SerialState *ss = &s->serial[i].state;
if (irq != 0) {
isa_init_irq(isadev, &ss->irq, irq);
}
isa_register_ioport(isadev, &ss->io, iobase);
s->serial[i].active = true;
}
}
}
static void lpc47m157_io_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
{
LPC47M157State *s = opaque;
#ifdef DEBUG_LPC47M157
printf("lpc47m157 io write 0x%llx = 0x%llx\n", addr, val);
#endif
if (addr == 0) { //INDEX_PORT
if (val == ENTER_CONFIG_KEY) {
assert(!s->configuration_mode);
s->configuration_mode = true;
} else if (val == EXIT_CONFIG_KEY) {
assert(s->configuration_mode);
s->configuration_mode = false;
update_devices(s);
} else {
s->selected_reg = val;
}
} else if (addr == 1) { //DATA_PORT
if (s->selected_reg < MAX_CONFIG_REG) {
/* global configuration register */
s->config_regs[s->selected_reg] = val;
} else {
/* device register */
assert(s->config_regs[CONFIG_DEVICE_NUMBER] < MAX_DEVICE);
uint8_t* dev = s->device_regs[s->config_regs[CONFIG_DEVICE_NUMBER]];
dev[s->selected_reg] = val;
#ifdef DEBUG_LPC47M157
printf("lpc47m157 dev %x . %x = %llx\n", s->config_regs[CONFIG_DEVICE_NUMBER], s->selected_reg, val);
#endif
}
} else {
assert(false);
}
}
static uint64_t lpc47m157_io_read(void *opaque, hwaddr addr, unsigned int size)
{
LPC47M157State *s = opaque;
uint32_t val = 0;
if (addr == 0) { //INDEX_PORT
} else if (addr == 1) { //DATA_PORT
if (s->selected_reg < MAX_CONFIG_REG) {
val = s->config_regs[s->selected_reg];
} else {
assert(s->config_regs[CONFIG_DEVICE_NUMBER] < MAX_DEVICE);
uint8_t* dev = s->device_regs[s->config_regs[CONFIG_DEVICE_NUMBER]];
val = dev[s->selected_reg];
}
} else {
assert(false);
}
#ifdef DEBUG_LPC47M157
printf("lpc47m157 io read 0x%llx -> 0x%x\n", addr, val);
#endif
return val;
}
static const MemoryRegionOps lpc47m157_io_ops = {
.read = lpc47m157_io_read,
.write = lpc47m157_io_write,
.valid = {
.min_access_size = 1,
.max_access_size = 1,
},
};
static void lpc47m157_realize(DeviceState *dev, Error **errp)
{
LPC47M157State *s = LPC47M157_DEVICE(dev);
ISADevice *isa = ISA_DEVICE(dev);
const uint32_t iobase = 0x2e; //0x4e if SYSOPT pin, make it a property
s->config_regs[CONFIG_PORT_LOW] = iobase & 0xFF;
s->config_regs[CONFIG_PORT_HIGH] = iobase >> 8;
memory_region_init_io(&s->io, OBJECT(s),
&lpc47m157_io_ops, s, "lpc47m157", 2);
isa_register_ioport(isa, &s->io, iobase);
/* init serial cores */
int i;
for (i=0; i<2; i++) {
CharDriverState *chr = serial_hds[i];
if (chr == NULL) {
char name[5];
snprintf(name, sizeof(name), "ser%d", i);
chr = qemu_chr_new(name, "null", NULL);
}
SerialState *ss = &s->serial[i].state;
ss->chr = chr;
ss->baudbase = 115200;
Error *err = NULL;
serial_realize_core(ss, &err);
if (err != NULL) {
qerror_report_err(err);
error_free(err);
exit(1);
}
memory_region_init_io(&ss->io, OBJECT(s),
&serial_io_ops, ss, "serial", 8);
}
}
static const VMStateDescription vmstate_lpc47m157= {
.name = "lpc47m157",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(serial[0].state, LPC47M157State, 0,
vmstate_serial, SerialState),
VMSTATE_STRUCT(serial[1].state, LPC47M157State, 0,
vmstate_serial, SerialState),
VMSTATE_END_OF_LIST()
}
};
static void lpc47m157_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = lpc47m157_realize;
dc->vmsd = &vmstate_lpc47m157;
//dc->reset = pc87312_reset;
//dc->props = pc87312_properties;
}
static const TypeInfo lpc47m157_type_info = {
.name = "lpc47m157",
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(LPC47M157State),
.class_init = lpc47m157_class_init,
};
static void lpc47m157_register_types(void)
{
type_register_static(&lpc47m157_type_info);
}
type_init(lpc47m157_register_types)
+99
View File
@@ -0,0 +1,99 @@
/*
* QEMU MCPX Audio Codec Interface implementation
*
* Copyright (c) 2012 espes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/audio/ac97_int.h"
typedef struct MCPXACIState {
PCIDevice dev;
AC97LinkState ac97;
MemoryRegion io_nam, io_nabm;
MemoryRegion mmio;
MemoryRegion nam_mmio, nabm_mmio;
} MCPXACIState;
#define MCPX_ACI_DEVICE(obj) \
OBJECT_CHECK(MCPXACIState, (obj), "mcpx-aci")
static int mcpx_aci_initfn(PCIDevice *dev)
{
MCPXACIState *d = MCPX_ACI_DEVICE(dev);
dev->config[PCI_INTERRUPT_PIN] = 0x01;
//mmio
memory_region_init(&d->mmio, OBJECT(dev), "mcpx-aci-mmio", 0x1000);
memory_region_init_io(&d->io_nam, OBJECT(dev), &ac97_io_nam_ops, &d->ac97,
"mcpx-aci-nam", 0x100);
memory_region_init_io(&d->io_nabm, OBJECT(dev), &ac97_io_nabm_ops, &d->ac97,
"mcpx-aci-nabm", 0x80);
/*pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_nam);
pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io_nabm);
memory_region_init_alias(&d->nam_mmio, NULL, &d->io_nam, 0, 0x100);
memory_region_add_subregion(&d->mmio, 0x0, &d->nam_mmio);
memory_region_init_alias(&d->nabm_mmio, NULL, &d->io_nabm, 0, 0x80);
memory_region_add_subregion(&d->mmio, 0x100, &d->nabm_mmio);*/
memory_region_add_subregion(&d->mmio, 0x0, &d->io_nam);
memory_region_add_subregion(&d->mmio, 0x100, &d->io_nabm);
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
ac97_common_init(&d->ac97, &d->dev, pci_get_address_space(&d->dev));
return 0;
}
static void mcpx_aci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->vendor_id = PCI_VENDOR_ID_NVIDIA;
k->device_id = PCI_DEVICE_ID_NVIDIA_MCPX_ACI;
k->revision = 210;
k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
k->init = mcpx_aci_initfn;
dc->desc = "MCPX Audio Codec Interface";
}
static const TypeInfo mcpx_aci_info = {
.name = "mcpx-aci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MCPXACIState),
.class_init = mcpx_aci_class_init,
};
static void mcpx_aci_register(void)
{
type_register_static(&mcpx_aci_info);
}
type_init(mcpx_aci_register);

Some files were not shown because too many files have changed in this diff Show More