* Refactor next-cube interrupt and register handling into a proper QOM device

-----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmAGlSsTHGh1dGhAdHV4
 ZmFtaWx5Lm9yZwAKCRAu2dd0/nAttS8oD/9i3nvvIXADUnumgRxVGZSJqzojstAt
 axwGNpW9Qu/yE6TC/tN1P6VDS+CzwFh/XnH9vRuqTTkYU5Zl4P/peHCYPgPpF2WK
 JYS8oZAuJhLIO0RGeHeDvhbiu2ZnRmgrOt99QQWv5XlO3d4Uj0EdPFhgwMYiXCJ8
 N6D7UO5elwSf2yTS0YUKdh+nDS3/zw1JJBmXD5d+cWKl9EXf1XG2WaYx9j/ZfF/j
 bsdYdm+n7knMAdKQEnpzNH8PRWIGABcd6qrbFMSePrAcS0WBqbjPnUSTwm50c9Jo
 mAEALeKo2orAxTSzwyPdWggQgwool63rwkfP7o9xvoUekgKVYtVxv1TcKdyYTLME
 QK77xG+gWbRfizzgkLs6kUljamlnwgmIW6ouENP75hOnsKtJLsJqfULEay4H3Vmb
 1NH1n6/EmO5UnSz8X2DpSa3Bm/Dt6E71Xh0TvRLbPyjuCRX/Omi89clN0PoXOZQC
 Z6hvLDiZ7+ceHGw2ThvFeNyY0x/UHkILtJ1ASOoF0oUqm38XvRefiW2ykKCzRnuX
 nzAdzCpFTVOYdpXlW7FdTpbXwXO4JuBnFP63hZQwwwUPAJaGr0BfNkuwhV94pU/1
 qNSJJdgnfgEukFw7Qaid185qXV3/4qYmqJkD9g0GVaZpltT2NRWz85wPuk0IR64p
 /A3nLPjy6bynsw==
 =hy5k
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2021-01-19' into staging

* Refactor next-cube interrupt and register handling into a proper QOM device

# gpg: Signature made Tue 19 Jan 2021 08:15:39 GMT
# gpg:                using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg:                issuer "huth@tuxfamily.org"
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full]
# gpg:                 aka "Thomas Huth <thuth@redhat.com>" [full]
# gpg:                 aka "Thomas Huth <huth@tuxfamily.org>" [full]
# gpg:                 aka "Thomas Huth <th.huth@posteo.de>" [unknown]
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3  EAB9 2ED9 D774 FE70 2DB5

* remotes/huth-gitlab/tags/pull-request-2021-01-19:
  hw/m68k/next-cube: Add missing header comment to next-cube.h
  hw/m68k/next-cube: Add vmstate for NeXTPC device
  hw/m68k/next-cube: Remove unused fields from NeXTState
  hw/m68k/next-cube: Move rtc into NeXTPC struct
  hw/m68k/next-cube: Make next_irq GPIO inputs to NEXT_PC device
  hw/m68k/next-cube: Move int_status and int_mask to NeXTPC struct
  hw/m68k/next-cube: Make next_irq take NeXTPC* as its opaque
  hw/m68k/next-cube: Move scr_ops into NeXTPC device
  hw/m68k/next-cube: Move mmio_ops into NeXTPC device
  hw/m68k/next-cube: Move register/interrupt functionality into a device
  hw/m68k/next-cube: Make next_irq() function static

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-01-19 11:57:07 +00:00
commit f1fcb6851a
2 changed files with 169 additions and 85 deletions

View File

@ -28,6 +28,7 @@
#include "qapi/error.h"
#include "ui/console.h"
#include "target/m68k/cpu.h"
#include "migration/vmstate.h"
/* #define DEBUG_NEXT */
#ifdef DEBUG_NEXT
@ -73,19 +74,27 @@ typedef struct NextRtc {
struct NeXTState {
MachineState parent;
uint32_t int_mask;
uint32_t int_status;
uint8_t scsi_csr_1;
uint8_t scsi_csr_2;
next_dma dma[10];
qemu_irq *scsi_irq;
qemu_irq scsi_dma;
qemu_irq scsi_reset;
qemu_irq *fd_irq;
};
#define TYPE_NEXT_PC "next-pc"
OBJECT_DECLARE_SIMPLE_TYPE(NeXTPC, NEXT_PC)
/* NeXT Peripheral Controller */
struct NeXTPC {
SysBusDevice parent_obj;
M68kCPU *cpu;
MemoryRegion mmiomem;
MemoryRegion scrmem;
uint32_t scr1;
uint32_t scr2;
uint8_t scsi_csr_1;
uint8_t scsi_csr_2;
uint32_t int_mask;
uint32_t int_status;
NextRtc rtc;
};
@ -110,7 +119,7 @@ static const uint8_t rtc_ram2[32] = {
#define SCR2_RTDATA 0x4
#define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10))
static void nextscr2_write(NeXTState *s, uint32_t val, int size)
static void nextscr2_write(NeXTPC *s, uint32_t val, int size)
{
static int led;
static int phase;
@ -244,7 +253,7 @@ static void nextscr2_write(NeXTState *s, uint32_t val, int size)
old_scr2 = scr2_2;
}
static uint32_t mmio_readb(NeXTState *s, hwaddr addr)
static uint32_t mmio_readb(NeXTPC *s, hwaddr addr)
{
switch (addr) {
case 0xc000:
@ -274,7 +283,7 @@ static uint32_t mmio_readb(NeXTState *s, hwaddr addr)
}
}
static uint32_t mmio_readw(NeXTState *s, hwaddr addr)
static uint32_t mmio_readw(NeXTPC *s, hwaddr addr)
{
switch (addr) {
default:
@ -283,7 +292,7 @@ static uint32_t mmio_readw(NeXTState *s, hwaddr addr)
}
}
static uint32_t mmio_readl(NeXTState *s, hwaddr addr)
static uint32_t mmio_readl(NeXTPC *s, hwaddr addr)
{
switch (addr) {
case 0x7000:
@ -306,7 +315,7 @@ static uint32_t mmio_readl(NeXTState *s, hwaddr addr)
}
}
static void mmio_writeb(NeXTState *s, hwaddr addr, uint32_t val)
static void mmio_writeb(NeXTPC *s, hwaddr addr, uint32_t val)
{
switch (addr) {
case 0xd003:
@ -318,12 +327,12 @@ static void mmio_writeb(NeXTState *s, hwaddr addr, uint32_t val)
}
static void mmio_writew(NeXTState *s, hwaddr addr, uint32_t val)
static void mmio_writew(NeXTPC *s, hwaddr addr, uint32_t val)
{
DPRINTF("MMIO Write W\n");
}
static void mmio_writel(NeXTState *s, hwaddr addr, uint32_t val)
static void mmio_writel(NeXTPC *s, hwaddr addr, uint32_t val)
{
switch (addr) {
case 0x7000:
@ -348,15 +357,15 @@ static void mmio_writel(NeXTState *s, hwaddr addr, uint32_t val)
static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size)
{
NeXTState *ns = NEXT_MACHINE(opaque);
NeXTPC *s = NEXT_PC(opaque);
switch (size) {
case 1:
return mmio_readb(ns, addr);
return mmio_readb(s, addr);
case 2:
return mmio_readw(ns, addr);
return mmio_readw(s, addr);
case 4:
return mmio_readl(ns, addr);
return mmio_readl(s, addr);
default:
g_assert_not_reached();
}
@ -365,17 +374,17 @@ static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size)
static void mmio_writefn(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
NeXTState *ns = NEXT_MACHINE(opaque);
NeXTPC *s = NEXT_PC(opaque);
switch (size) {
case 1:
mmio_writeb(ns, addr, value);
mmio_writeb(s, addr, value);
break;
case 2:
mmio_writew(ns, addr, value);
mmio_writew(s, addr, value);
break;
case 4:
mmio_writel(ns, addr, value);
mmio_writel(s, addr, value);
break;
default:
g_assert_not_reached();
@ -390,7 +399,7 @@ static const MemoryRegionOps mmio_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static uint32_t scr_readb(NeXTState *s, hwaddr addr)
static uint32_t scr_readb(NeXTPC *s, hwaddr addr)
{
switch (addr) {
case 0x14108:
@ -424,13 +433,13 @@ static uint32_t scr_readb(NeXTState *s, hwaddr addr)
}
}
static uint32_t scr_readw(NeXTState *s, hwaddr addr)
static uint32_t scr_readw(NeXTPC *s, hwaddr addr)
{
DPRINTF("BMAP Read W @ %x\n", (unsigned int)addr);
return 0;
}
static uint32_t scr_readl(NeXTState *s, hwaddr addr)
static uint32_t scr_readl(NeXTPC *s, hwaddr addr)
{
DPRINTF("BMAP Read L @ %x\n", (unsigned int)addr);
return 0;
@ -443,7 +452,7 @@ static uint32_t scr_readl(NeXTState *s, hwaddr addr)
#define SCSICSR_CPUDMA 0x10 /* if set, dma enabled */
#define SCSICSR_INTMASK 0x20 /* if set, interrupt enabled */
static void scr_writeb(NeXTState *s, hwaddr addr, uint32_t value)
static void scr_writeb(NeXTPC *s, hwaddr addr, uint32_t value)
{
switch (addr) {
case 0x14108:
@ -521,27 +530,27 @@ static void scr_writeb(NeXTState *s, hwaddr addr, uint32_t value)
}
}
static void scr_writew(NeXTState *s, hwaddr addr, uint32_t value)
static void scr_writew(NeXTPC *s, hwaddr addr, uint32_t value)
{
DPRINTF("BMAP Write W @ %x with %x\n", (unsigned int)addr, value);
}
static void scr_writel(NeXTState *s, hwaddr addr, uint32_t value)
static void scr_writel(NeXTPC *s, hwaddr addr, uint32_t value)
{
DPRINTF("BMAP Write L @ %x with %x\n", (unsigned int)addr, value);
}
static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size)
{
NeXTState *ns = NEXT_MACHINE(opaque);
NeXTPC *s = NEXT_PC(opaque);
switch (size) {
case 1:
return scr_readb(ns, addr);
return scr_readb(s, addr);
case 2:
return scr_readw(ns, addr);
return scr_readw(s, addr);
case 4:
return scr_readl(ns, addr);
return scr_readl(s, addr);
default:
g_assert_not_reached();
}
@ -550,17 +559,17 @@ static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size)
static void scr_writefn(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
NeXTState *ns = NEXT_MACHINE(opaque);
NeXTPC *s = NEXT_PC(opaque);
switch (size) {
case 1:
scr_writeb(ns, addr, value);
scr_writeb(s, addr, value);
break;
case 2:
scr_writew(ns, addr, value);
scr_writew(s, addr, value);
break;
case 4:
scr_writel(ns, addr, value);
scr_writel(s, addr, value);
break;
default:
g_assert_not_reached();
@ -720,15 +729,11 @@ static const MemoryRegionOps dma_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
/*
* TODO: set the shift numbers as values in the enum, so the first switch
* will not be needed
*/
void next_irq(void *opaque, int number, int level)
static void next_irq(void *opaque, int number, int level)
{
M68kCPU *cpu = opaque;
NeXTPC *s = NEXT_PC(opaque);
M68kCPU *cpu = s->cpu;
int shift = 0;
NeXTState *ns = NEXT_MACHINE(qdev_get_machine());
/* first switch sets interupt status */
/* DPRINTF("IRQ %i\n",number); */
@ -783,14 +788,14 @@ void next_irq(void *opaque, int number, int level)
* this HAS to be wrong, the interrupt handlers in mach and together
* int_status and int_mask and return if there is a hit
*/
if (ns->int_mask & (1 << shift)) {
if (s->int_mask & (1 << shift)) {
DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc);
/* return; */
}
/* second switch triggers the correct interrupt */
if (level) {
ns->int_status |= 1 << shift;
s->int_status |= 1 << shift;
switch (number) {
/* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
@ -819,24 +824,13 @@ void next_irq(void *opaque, int number, int level)
break;
}
} else {
ns->int_status &= ~(1 << shift);
s->int_status &= ~(1 << shift);
cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
}
static void next_serial_irq(void *opaque, int n, int level)
static void next_escc_init(DeviceState *pcdev)
{
/* DPRINTF("SCC IRQ NUM %i\n",n); */
if (n) {
next_irq(opaque, NEXT_SCC_DMA_I, level);
} else {
next_irq(opaque, NEXT_SCC_I, level);
}
}
static void next_escc_init(M68kCPU *cpu)
{
qemu_irq *ser_irq = qemu_allocate_irqs(next_serial_irq, cpu, 2);
DeviceState *dev;
SysBusDevice *s;
@ -852,25 +846,113 @@ static void next_escc_init(M68kCPU *cpu)
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_connect_irq(s, 0, ser_irq[0]);
sysbus_connect_irq(s, 1, ser_irq[1]);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(pcdev, NEXT_SCC_I));
sysbus_connect_irq(s, 1, qdev_get_gpio_in(pcdev, NEXT_SCC_DMA_I));
sysbus_mmio_map(s, 0, 0x2118000);
}
static void next_pc_reset(DeviceState *dev)
{
NeXTPC *s = NEXT_PC(dev);
/* Set internal registers to initial values */
/* 0x0000XX00 << vital bits */
s->scr1 = 0x00011102;
s->scr2 = 0x00ff0c80;
s->rtc.status = 0x90;
/* Load RTC RAM - TODO: provide possibility to load contents from file */
memcpy(s->rtc.ram, rtc_ram2, 32);
}
static void next_pc_realize(DeviceState *dev, Error **errp)
{
NeXTPC *s = NEXT_PC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
qdev_init_gpio_in(dev, next_irq, NEXT_NUM_IRQS);
memory_region_init_io(&s->mmiomem, OBJECT(s), &mmio_ops, s,
"next.mmio", 0xD0000);
memory_region_init_io(&s->scrmem, OBJECT(s), &scr_ops, s,
"next.scr", 0x20000);
sysbus_init_mmio(sbd, &s->mmiomem);
sysbus_init_mmio(sbd, &s->scrmem);
}
/*
* If the m68k CPU implemented its inbound irq lines as GPIO lines
* rather than via the m68k_set_irq_level() function we would not need
* this cpu link property and could instead provide outbound IRQ lines
* that the board could wire up to the CPU.
*/
static Property next_pc_properties[] = {
DEFINE_PROP_LINK("cpu", NeXTPC, cpu, TYPE_M68K_CPU, M68kCPU *),
DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription next_rtc_vmstate = {
.name = "next-rtc",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(ram, NextRtc, 32),
VMSTATE_UINT8(command, NextRtc),
VMSTATE_UINT8(value, NextRtc),
VMSTATE_UINT8(status, NextRtc),
VMSTATE_UINT8(control, NextRtc),
VMSTATE_UINT8(retval, NextRtc),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription next_pc_vmstate = {
.name = "next-pc",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(scr1, NeXTPC),
VMSTATE_UINT32(scr2, NeXTPC),
VMSTATE_UINT32(int_mask, NeXTPC),
VMSTATE_UINT32(int_status, NeXTPC),
VMSTATE_UINT8(scsi_csr_1, NeXTPC),
VMSTATE_UINT8(scsi_csr_2, NeXTPC),
VMSTATE_STRUCT(rtc, NeXTPC, 0, next_rtc_vmstate, NextRtc),
VMSTATE_END_OF_LIST()
},
};
static void next_pc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "NeXT Peripheral Controller";
dc->realize = next_pc_realize;
dc->reset = next_pc_reset;
device_class_set_props(dc, next_pc_properties);
dc->vmsd = &next_pc_vmstate;
}
static const TypeInfo next_pc_info = {
.name = TYPE_NEXT_PC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(NeXTPC),
.class_init = next_pc_class_init,
};
static void next_cube_init(MachineState *machine)
{
M68kCPU *cpu;
CPUM68KState *env;
MemoryRegion *rom = g_new(MemoryRegion, 1);
MemoryRegion *mmiomem = g_new(MemoryRegion, 1);
MemoryRegion *scrmem = g_new(MemoryRegion, 1);
MemoryRegion *dmamem = g_new(MemoryRegion, 1);
MemoryRegion *bmapm1 = g_new(MemoryRegion, 1);
MemoryRegion *bmapm2 = g_new(MemoryRegion, 1);
MemoryRegion *sysmem = get_system_memory();
const char *bios_name = machine->firmware ?: ROM_FILE;
NeXTState *ns = NEXT_MACHINE(machine);
DeviceState *dev;
DeviceState *pcdev;
/* Initialize the cpu core */
cpu = M68K_CPU(cpu_create(machine->cpu_type));
@ -884,14 +966,10 @@ static void next_cube_init(MachineState *machine)
env->vbr = 0;
env->sr = 0x2700;
/* Set internal registers to initial values */
/* 0x0000XX00 << vital bits */
ns->scr1 = 0x00011102;
ns->scr2 = 0x00ff0c80;
ns->rtc.status = 0x90;
/* Load RTC RAM - TODO: provide possibility to load contents from file */
memcpy(ns->rtc.ram, rtc_ram2, 32);
/* Peripheral Controller */
pcdev = qdev_new(TYPE_NEXT_PC);
object_property_set_link(OBJECT(pcdev), "cpu", OBJECT(cpu), &error_abort);
sysbus_realize_and_unref(SYS_BUS_DEVICE(pcdev), &error_fatal);
/* 64MB RAM starting at 0x04000000 */
memory_region_add_subregion(sysmem, 0x04000000, machine->ram);
@ -902,9 +980,10 @@ static void next_cube_init(MachineState *machine)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000);
/* MMIO */
memory_region_init_io(mmiomem, NULL, &mmio_ops, machine, "next.mmio",
0xD0000);
memory_region_add_subregion(sysmem, 0x02000000, mmiomem);
sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000);
/* BMAP IO - acts as a catch-all for now */
sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000);
/* BMAP memory */
memory_region_init_ram_shared_nomigrate(bmapm1, NULL, "next.bmapmem", 64,
@ -914,11 +993,6 @@ static void next_cube_init(MachineState *machine)
memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64);
memory_region_add_subregion(sysmem, 0x820c0000, bmapm2);
/* BMAP IO - acts as a catch-all for now */
memory_region_init_io(scrmem, NULL, &scr_ops, machine, "next.scr",
0x20000);
memory_region_add_subregion(sysmem, 0x02100000, scrmem);
/* KBD */
dev = qdev_new(TYPE_NEXTKBD);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@ -946,7 +1020,7 @@ static void next_cube_init(MachineState *machine)
}
/* Serial */
next_escc_init(cpu);
next_escc_init(pcdev);
/* TODO: */
/* Network */
@ -978,6 +1052,7 @@ static const TypeInfo next_typeinfo = {
static void next_register_type(void)
{
type_register_static(&next_typeinfo);
type_register_static(&next_pc_info);
}
type_init(next_register_type)

View File

@ -1,3 +1,13 @@
/*
* NeXT Cube
*
* Copyright (c) 2011 Bryce Lanham
*
* This code 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.
*/
#ifndef NEXT_CUBE_H
#define NEXT_CUBE_H
@ -39,9 +49,8 @@ enum next_irqs {
NEXT_ENRX_DMA_I,
NEXT_SCSI_DMA_I,
NEXT_SCC_DMA_I,
NEXT_SND_I
NEXT_SND_I,
NEXT_NUM_IRQS
};
void next_irq(void *opaque, int number, int level);
#endif /* NEXT_CUBE_H */