q800 pull request 20210908

mac_via: remove MAC_VIA device and prepare for Nubus IRQs
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmE42CcSHGxhdXJlbnRA
 dml2aWVyLmV1AAoJEPMMOL0/L748rb0P/Roslh9kkRTrSzVXmbZBtGBd0F5lnQa7
 nh/X77oXuPKu4WKpqExIv+urKtIPgwn7OmSIGqhhxpu2Xy8/JGraQoHhCxd7Hefz
 Pcm51xQNpXgz4u/rkh5kmDxlN3nFM/xrx5Zn2+MxQCNroLtzhlWKmvgbh6eRsPX1
 71rT/QyUDZ9HxYJ9i7oDeAVZ6MK86VegzqWRHwZ9AmcKdD1USwCzquYdLt4oXMkK
 AloTteOBt4K2Ul3X1pt4Wkbbj0wmXKB8QAzSEAhuZD29bCQVPPxudtkOd/paO1AT
 jPefTbdpIKOMcmIYuzu/hO67enEA870iXcdlBJwL9M3/kGFdSnfgCumHDUPA3F8T
 xZAPlRvBNUDlKhjUHqgiy4WY0zseDphETEFUcwYquhU6rYRWYc3ehaVNtRrCD5og
 OGDdNnOjQDXhAEY0GYGtdL7obGKTpGGMJ/1nnZrhbjRG9YnpXz5Pn3QvktgpdSMo
 dx092ehrqO0nRp3mqwQYy6uwwe6wVgktENH2wWwkiNu+cBfUPBPrm3nPeP8Yfr35
 x9Jg+42KzsyFdTZ5ApvHpzK1WUczprX0l+gDZTU98rIYNECu/zQ73C2m0rVVbhQZ
 Emz0a43IRDSnmgu115nKlT3m6QZa7wYI+eO0opSPTZwz9oBiTpUaY7tcPXJFWWZZ
 OVAZZsFHab3A
 =HVcY
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier/tags/q800-pull-request' into staging

q800 pull request 20210908

mac_via: remove MAC_VIA device and prepare for Nubus IRQs

# gpg: Signature made Wed 08 Sep 2021 16:35:03 BST
# gpg:                using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg:                issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier/tags/q800-pull-request:
  mac_via: add qdev gpios for nubus slot interrupts to VIA2
  mac_via: rename VIA2_IRQ_SLOT_BIT to VIA2_IRQ_NUBUS_BIT
  mac_via: remove explicit viaN prefix from VIA IRQ gpios
  mac_via: remove mac_via device
  mac_via: move VIA1 realize logic from mac_via_realize() to mos6522_q800_via1_realize()
  mac_via: move VIA1 reset logic from mac_via_reset() to mos6522_q800_via1_reset()
  mac_via: move q800 VIA1 timer variables to q800 VIA1 VMStateDescription
  mac_via: move ADB variables to MOS6522Q800VIA1State
  mac_via: move PRAM/RTC variables to MOS6522Q800VIA1State
  mac_via: move PRAM contents and block backend to MOS6522Q800VIA1State
  mac_via: move last_b variable into q800 VIA1 VMStateDescription
  mac_via: introduce new VMStateDescription for q800 VIA1 and VIA2

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-09-10 11:09:30 +01:00
commit 6d1272d3ef
3 changed files with 347 additions and 377 deletions

View File

@ -225,7 +225,7 @@ static void q800_init(MachineState *machine)
hwaddr parameters_base; hwaddr parameters_base;
CPUState *cs; CPUState *cs;
DeviceState *dev; DeviceState *dev;
DeviceState *via_dev; DeviceState *via1_dev, *via2_dev;
DeviceState *escc_orgate; DeviceState *escc_orgate;
SysBusESPState *sysbus_esp; SysBusESPState *sysbus_esp;
ESPState *esp; ESPState *esp;
@ -270,28 +270,30 @@ static void q800_init(MachineState *machine)
object_property_set_link(OBJECT(glue), "cpu", OBJECT(cpu), &error_abort); object_property_set_link(OBJECT(glue), "cpu", OBJECT(cpu), &error_abort);
sysbus_realize_and_unref(SYS_BUS_DEVICE(glue), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(glue), &error_fatal);
/* VIA */ /* VIA 1 */
via1_dev = qdev_new(TYPE_MOS6522_Q800_VIA1);
via_dev = qdev_new(TYPE_MAC_VIA);
dinfo = drive_get(IF_MTD, 0, 0); dinfo = drive_get(IF_MTD, 0, 0);
if (dinfo) { if (dinfo) {
qdev_prop_set_drive(via_dev, "drive", blk_by_legacy_dinfo(dinfo)); qdev_prop_set_drive(via1_dev, "drive", blk_by_legacy_dinfo(dinfo));
} }
sysbus = SYS_BUS_DEVICE(via_dev); sysbus = SYS_BUS_DEVICE(via1_dev);
sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, VIA_BASE); sysbus_mmio_map(sysbus, 1, VIA_BASE);
qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 0));
qdev_get_gpio_in(glue, 0));
qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1,
qdev_get_gpio_in(glue, 1));
adb_bus = qdev_get_child_bus(via1_dev, "adb.0");
adb_bus = qdev_get_child_bus(via_dev, "adb.0");
dev = qdev_new(TYPE_ADB_KEYBOARD); dev = qdev_new(TYPE_ADB_KEYBOARD);
qdev_realize_and_unref(dev, adb_bus, &error_fatal); qdev_realize_and_unref(dev, adb_bus, &error_fatal);
dev = qdev_new(TYPE_ADB_MOUSE); dev = qdev_new(TYPE_ADB_MOUSE);
qdev_realize_and_unref(dev, adb_bus, &error_fatal); qdev_realize_and_unref(dev, adb_bus, &error_fatal);
/* VIA 2 */
via2_dev = qdev_new(TYPE_MOS6522_Q800_VIA2);
sysbus = SYS_BUS_DEVICE(via2_dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 1, VIA_BASE + VIA_SIZE);
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 1));
/* MACSONIC */ /* MACSONIC */
if (nb_nics > 1) { if (nb_nics > 1) {
@ -375,12 +377,10 @@ static void q800_init(MachineState *machine)
sysbus = SYS_BUS_DEVICE(dev); sysbus = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in_named(via_dev, sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(via2_dev,
"via2-irq", VIA2_IRQ_SCSI_BIT));
VIA2_IRQ_SCSI_BIT)); sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(via2_dev,
sysbus_connect_irq(sysbus, 1, VIA2_IRQ_SCSI_DATA_BIT));
qdev_get_gpio_in_named(via_dev, "via2-irq",
VIA2_IRQ_SCSI_DATA_BIT));
sysbus_mmio_map(sysbus, 0, ESP_BASE); sysbus_mmio_map(sysbus, 0, ESP_BASE);
sysbus_mmio_map(sysbus, 1, ESP_PDMA); sysbus_mmio_map(sysbus, 1, ESP_PDMA);

View File

@ -34,11 +34,9 @@
#include "qemu/log.h" #include "qemu/log.h"
/* /*
* VIAs: There are two in every machine, * VIAs: There are two in every machine
*/ */
#define VIA_SIZE (0x2000)
/* /*
* Not all of these are true post MacII I think. * Not all of these are true post MacII I think.
* CSA: probably the ones CHRP marks as 'unused' change purposes * CSA: probably the ones CHRP marks as 'unused' change purposes
@ -374,11 +372,10 @@ static void via2_irq_request(void *opaque, int irq, int level)
} }
static void pram_update(MacVIAState *m) static void pram_update(MOS6522Q800VIA1State *v1s)
{ {
if (m->blk) { if (v1s->blk) {
if (blk_pwrite(m->blk, 0, m->mos6522_via1.PRAM, if (blk_pwrite(v1s->blk, 0, v1s->PRAM, sizeof(v1s->PRAM), 0) < 0) {
sizeof(m->mos6522_via1.PRAM), 0) < 0) {
qemu_log("pram_update: cannot write to file\n"); qemu_log("pram_update: cannot write to file\n");
} }
} }
@ -434,9 +431,8 @@ static int via1_rtc_compact_cmd(uint8_t value)
return REG_INVALID; return REG_INVALID;
} }
static void via1_rtc_update(MacVIAState *m) static void via1_rtc_update(MOS6522Q800VIA1State *v1s)
{ {
MOS6522Q800VIA1State *v1s = &m->mos6522_via1;
MOS6522State *s = MOS6522(v1s); MOS6522State *s = MOS6522(v1s);
int cmd, sector, addr; int cmd, sector, addr;
uint32_t time; uint32_t time;
@ -448,40 +444,40 @@ static void via1_rtc_update(MacVIAState *m)
if (s->dirb & VIA1B_vRTCData) { if (s->dirb & VIA1B_vRTCData) {
/* send bits to the RTC */ /* send bits to the RTC */
if (!(v1s->last_b & VIA1B_vRTCClk) && (s->b & VIA1B_vRTCClk)) { if (!(v1s->last_b & VIA1B_vRTCClk) && (s->b & VIA1B_vRTCClk)) {
m->data_out <<= 1; v1s->data_out <<= 1;
m->data_out |= s->b & VIA1B_vRTCData; v1s->data_out |= s->b & VIA1B_vRTCData;
m->data_out_cnt++; v1s->data_out_cnt++;
} }
trace_via1_rtc_update_data_out(m->data_out_cnt, m->data_out); trace_via1_rtc_update_data_out(v1s->data_out_cnt, v1s->data_out);
} else { } else {
trace_via1_rtc_update_data_in(m->data_in_cnt, m->data_in); trace_via1_rtc_update_data_in(v1s->data_in_cnt, v1s->data_in);
/* receive bits from the RTC */ /* receive bits from the RTC */
if ((v1s->last_b & VIA1B_vRTCClk) && if ((v1s->last_b & VIA1B_vRTCClk) &&
!(s->b & VIA1B_vRTCClk) && !(s->b & VIA1B_vRTCClk) &&
m->data_in_cnt) { v1s->data_in_cnt) {
s->b = (s->b & ~VIA1B_vRTCData) | s->b = (s->b & ~VIA1B_vRTCData) |
((m->data_in >> 7) & VIA1B_vRTCData); ((v1s->data_in >> 7) & VIA1B_vRTCData);
m->data_in <<= 1; v1s->data_in <<= 1;
m->data_in_cnt--; v1s->data_in_cnt--;
} }
return; return;
} }
if (m->data_out_cnt != 8) { if (v1s->data_out_cnt != 8) {
return; return;
} }
m->data_out_cnt = 0; v1s->data_out_cnt = 0;
trace_via1_rtc_internal_status(m->cmd, m->alt, m->data_out); trace_via1_rtc_internal_status(v1s->cmd, v1s->alt, v1s->data_out);
/* first byte: it's a command */ /* first byte: it's a command */
if (m->cmd == REG_EMPTY) { if (v1s->cmd == REG_EMPTY) {
cmd = via1_rtc_compact_cmd(m->data_out); cmd = via1_rtc_compact_cmd(v1s->data_out);
trace_via1_rtc_internal_cmd(cmd); trace_via1_rtc_internal_cmd(cmd);
if (cmd == REG_INVALID) { if (cmd == REG_INVALID) {
trace_via1_rtc_cmd_invalid(m->data_out); trace_via1_rtc_cmd_invalid(v1s->data_out);
return; return;
} }
@ -493,20 +489,20 @@ static void via1_rtc_update(MacVIAState *m)
* register 3 is highest-order byte * register 3 is highest-order byte
*/ */
time = m->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) time = v1s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
/ NANOSECONDS_PER_SECOND); / NANOSECONDS_PER_SECOND);
trace_via1_rtc_internal_time(time); trace_via1_rtc_internal_time(time);
m->data_in = (time >> ((cmd & 0x03) << 3)) & 0xff; v1s->data_in = (time >> ((cmd & 0x03) << 3)) & 0xff;
m->data_in_cnt = 8; v1s->data_in_cnt = 8;
trace_via1_rtc_cmd_seconds_read((cmd & 0x7f) - REG_0, trace_via1_rtc_cmd_seconds_read((cmd & 0x7f) - REG_0,
m->data_in); v1s->data_in);
break; break;
case REG_PRAM_ADDR...REG_PRAM_ADDR_LAST: case REG_PRAM_ADDR...REG_PRAM_ADDR_LAST:
/* PRAM address 0x00 -> 0x13 */ /* PRAM address 0x00 -> 0x13 */
m->data_in = v1s->PRAM[(cmd & 0x7f) - REG_PRAM_ADDR]; v1s->data_in = v1s->PRAM[(cmd & 0x7f) - REG_PRAM_ADDR];
m->data_in_cnt = 8; v1s->data_in_cnt = 8;
trace_via1_rtc_cmd_pram_read((cmd & 0x7f) - REG_PRAM_ADDR, trace_via1_rtc_cmd_pram_read((cmd & 0x7f) - REG_PRAM_ADDR,
m->data_in); v1s->data_in);
break; break;
case REG_PRAM_SECT...REG_PRAM_SECT_LAST: case REG_PRAM_SECT...REG_PRAM_SECT_LAST:
/* /*
@ -514,7 +510,7 @@ static void via1_rtc_update(MacVIAState *m)
* the only two-byte read command * the only two-byte read command
*/ */
trace_via1_rtc_internal_set_cmd(cmd); trace_via1_rtc_internal_set_cmd(cmd);
m->cmd = cmd; v1s->cmd = cmd;
break; break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
@ -524,9 +520,9 @@ static void via1_rtc_update(MacVIAState *m)
} }
/* this is a write command, needs a parameter */ /* this is a write command, needs a parameter */
if (cmd == REG_WPROTECT || !m->wprotect) { if (cmd == REG_WPROTECT || !v1s->wprotect) {
trace_via1_rtc_internal_set_cmd(cmd); trace_via1_rtc_internal_set_cmd(cmd);
m->cmd = cmd; v1s->cmd = cmd;
} else { } else {
trace_via1_rtc_internal_ignore_cmd(cmd); trace_via1_rtc_internal_ignore_cmd(cmd);
} }
@ -534,46 +530,47 @@ static void via1_rtc_update(MacVIAState *m)
} }
/* second byte: it's a parameter */ /* second byte: it's a parameter */
if (m->alt == REG_EMPTY) { if (v1s->alt == REG_EMPTY) {
switch (m->cmd & 0x7f) { switch (v1s->cmd & 0x7f) {
case REG_0...REG_3: /* seconds register */ case REG_0...REG_3: /* seconds register */
/* FIXME */ /* FIXME */
trace_via1_rtc_cmd_seconds_write(m->cmd - REG_0, m->data_out); trace_via1_rtc_cmd_seconds_write(v1s->cmd - REG_0, v1s->data_out);
m->cmd = REG_EMPTY; v1s->cmd = REG_EMPTY;
break; break;
case REG_TEST: case REG_TEST:
/* device control: nothing to do */ /* device control: nothing to do */
trace_via1_rtc_cmd_test_write(m->data_out); trace_via1_rtc_cmd_test_write(v1s->data_out);
m->cmd = REG_EMPTY; v1s->cmd = REG_EMPTY;
break; break;
case REG_WPROTECT: case REG_WPROTECT:
/* Write Protect register */ /* Write Protect register */
trace_via1_rtc_cmd_wprotect_write(m->data_out); trace_via1_rtc_cmd_wprotect_write(v1s->data_out);
m->wprotect = !!(m->data_out & 0x80); v1s->wprotect = !!(v1s->data_out & 0x80);
m->cmd = REG_EMPTY; v1s->cmd = REG_EMPTY;
break; break;
case REG_PRAM_ADDR...REG_PRAM_ADDR_LAST: case REG_PRAM_ADDR...REG_PRAM_ADDR_LAST:
/* PRAM address 0x00 -> 0x13 */ /* PRAM address 0x00 -> 0x13 */
trace_via1_rtc_cmd_pram_write(m->cmd - REG_PRAM_ADDR, m->data_out); trace_via1_rtc_cmd_pram_write(v1s->cmd - REG_PRAM_ADDR,
v1s->PRAM[m->cmd - REG_PRAM_ADDR] = m->data_out; v1s->data_out);
pram_update(m); v1s->PRAM[v1s->cmd - REG_PRAM_ADDR] = v1s->data_out;
m->cmd = REG_EMPTY; pram_update(v1s);
v1s->cmd = REG_EMPTY;
break; break;
case REG_PRAM_SECT...REG_PRAM_SECT_LAST: case REG_PRAM_SECT...REG_PRAM_SECT_LAST:
addr = (m->data_out >> 2) & 0x1f; addr = (v1s->data_out >> 2) & 0x1f;
sector = (m->cmd & 0x7f) - REG_PRAM_SECT; sector = (v1s->cmd & 0x7f) - REG_PRAM_SECT;
if (m->cmd & 0x80) { if (v1s->cmd & 0x80) {
/* it's a read */ /* it's a read */
m->data_in = v1s->PRAM[sector * 32 + addr]; v1s->data_in = v1s->PRAM[sector * 32 + addr];
m->data_in_cnt = 8; v1s->data_in_cnt = 8;
trace_via1_rtc_cmd_pram_sect_read(sector, addr, trace_via1_rtc_cmd_pram_sect_read(sector, addr,
sector * 32 + addr, sector * 32 + addr,
m->data_in); v1s->data_in);
m->cmd = REG_EMPTY; v1s->cmd = REG_EMPTY;
} else { } else {
/* it's a write, we need one more parameter */ /* it's a write, we need one more parameter */
trace_via1_rtc_internal_set_alt(addr, sector, addr); trace_via1_rtc_internal_set_alt(addr, sector, addr);
m->alt = addr; v1s->alt = addr;
} }
break; break;
default: default:
@ -584,22 +581,21 @@ static void via1_rtc_update(MacVIAState *m)
} }
/* third byte: it's the data of a REG_PRAM_SECT write */ /* third byte: it's the data of a REG_PRAM_SECT write */
g_assert(REG_PRAM_SECT <= m->cmd && m->cmd <= REG_PRAM_SECT_LAST); g_assert(REG_PRAM_SECT <= v1s->cmd && v1s->cmd <= REG_PRAM_SECT_LAST);
sector = m->cmd - REG_PRAM_SECT; sector = v1s->cmd - REG_PRAM_SECT;
v1s->PRAM[sector * 32 + m->alt] = m->data_out; v1s->PRAM[sector * 32 + v1s->alt] = v1s->data_out;
pram_update(m); pram_update(v1s);
trace_via1_rtc_cmd_pram_sect_write(sector, m->alt, sector * 32 + m->alt, trace_via1_rtc_cmd_pram_sect_write(sector, v1s->alt, sector * 32 + v1s->alt,
m->data_out); v1s->data_out);
m->alt = REG_EMPTY; v1s->alt = REG_EMPTY;
m->cmd = REG_EMPTY; v1s->cmd = REG_EMPTY;
} }
static void adb_via_poll(void *opaque) static void adb_via_poll(void *opaque)
{ {
MacVIAState *m = opaque; MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque);
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1);
MOS6522State *s = MOS6522(v1s); MOS6522State *s = MOS6522(v1s);
ADBBusState *adb_bus = &m->adb_bus; ADBBusState *adb_bus = &v1s->adb_bus;
uint8_t obuf[9]; uint8_t obuf[9];
uint8_t *data = &s->sr; uint8_t *data = &s->sr;
int olen; int olen;
@ -611,50 +607,50 @@ static void adb_via_poll(void *opaque)
*/ */
adb_autopoll_block(adb_bus); adb_autopoll_block(adb_bus);
if (m->adb_data_in_size > 0 && m->adb_data_in_index == 0) { if (v1s->adb_data_in_size > 0 && v1s->adb_data_in_index == 0) {
/* /*
* For older Linux kernels that switch to IDLE mode after sending the * For older Linux kernels that switch to IDLE mode after sending the
* ADB command, detect if there is an existing response and return that * ADB command, detect if there is an existing response and return that
* as a a "fake" autopoll reply or bus timeout accordingly * as a a "fake" autopoll reply or bus timeout accordingly
*/ */
*data = m->adb_data_out[0]; *data = v1s->adb_data_out[0];
olen = m->adb_data_in_size; olen = v1s->adb_data_in_size;
s->b &= ~VIA1B_vADBInt; s->b &= ~VIA1B_vADBInt;
qemu_irq_raise(m->adb_data_ready); qemu_irq_raise(v1s->adb_data_ready);
} else { } else {
/* /*
* Otherwise poll as normal * Otherwise poll as normal
*/ */
m->adb_data_in_index = 0; v1s->adb_data_in_index = 0;
m->adb_data_out_index = 0; v1s->adb_data_out_index = 0;
olen = adb_poll(adb_bus, obuf, adb_bus->autopoll_mask); olen = adb_poll(adb_bus, obuf, adb_bus->autopoll_mask);
if (olen > 0) { if (olen > 0) {
/* Autopoll response */ /* Autopoll response */
*data = obuf[0]; *data = obuf[0];
olen--; olen--;
memcpy(m->adb_data_in, &obuf[1], olen); memcpy(v1s->adb_data_in, &obuf[1], olen);
m->adb_data_in_size = olen; v1s->adb_data_in_size = olen;
s->b &= ~VIA1B_vADBInt; s->b &= ~VIA1B_vADBInt;
qemu_irq_raise(m->adb_data_ready); qemu_irq_raise(v1s->adb_data_ready);
} else { } else {
*data = m->adb_autopoll_cmd; *data = v1s->adb_autopoll_cmd;
obuf[0] = 0xff; obuf[0] = 0xff;
obuf[1] = 0xff; obuf[1] = 0xff;
olen = 2; olen = 2;
memcpy(m->adb_data_in, obuf, olen); memcpy(v1s->adb_data_in, obuf, olen);
m->adb_data_in_size = olen; v1s->adb_data_in_size = olen;
s->b &= ~VIA1B_vADBInt; s->b &= ~VIA1B_vADBInt;
qemu_irq_raise(m->adb_data_ready); qemu_irq_raise(v1s->adb_data_ready);
} }
} }
trace_via1_adb_poll(*data, (s->b & VIA1B_vADBInt) ? "+" : "-", trace_via1_adb_poll(*data, (s->b & VIA1B_vADBInt) ? "+" : "-",
adb_bus->status, m->adb_data_in_index, olen); adb_bus->status, v1s->adb_data_in_index, olen);
} }
static int adb_via_send_len(uint8_t data) static int adb_via_send_len(uint8_t data)
@ -687,11 +683,10 @@ static int adb_via_send_len(uint8_t data)
} }
} }
static void adb_via_send(MacVIAState *s, int state, uint8_t data) static void adb_via_send(MOS6522Q800VIA1State *v1s, int state, uint8_t data)
{ {
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&s->mos6522_via1);
MOS6522State *ms = MOS6522(v1s); MOS6522State *ms = MOS6522(v1s);
ADBBusState *adb_bus = &s->adb_bus; ADBBusState *adb_bus = &v1s->adb_bus;
uint16_t autopoll_mask; uint16_t autopoll_mask;
switch (state) { switch (state) {
@ -707,22 +702,22 @@ static void adb_via_send(MacVIAState *s, int state, uint8_t data)
ms->b &= ~VIA1B_vADBInt; ms->b &= ~VIA1B_vADBInt;
} else { } else {
ms->b |= VIA1B_vADBInt; ms->b |= VIA1B_vADBInt;
s->adb_data_out_index = 0; v1s->adb_data_out_index = 0;
s->adb_data_out[s->adb_data_out_index++] = data; v1s->adb_data_out[v1s->adb_data_out_index++] = data;
} }
trace_via1_adb_send(" NEW", data, (ms->b & VIA1B_vADBInt) ? "+" : "-"); trace_via1_adb_send(" NEW", data, (ms->b & VIA1B_vADBInt) ? "+" : "-");
qemu_irq_raise(s->adb_data_ready); qemu_irq_raise(v1s->adb_data_ready);
break; break;
case ADB_STATE_EVEN: case ADB_STATE_EVEN:
case ADB_STATE_ODD: case ADB_STATE_ODD:
ms->b |= VIA1B_vADBInt; ms->b |= VIA1B_vADBInt;
s->adb_data_out[s->adb_data_out_index++] = data; v1s->adb_data_out[v1s->adb_data_out_index++] = data;
trace_via1_adb_send(state == ADB_STATE_EVEN ? "EVEN" : " ODD", trace_via1_adb_send(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
data, (ms->b & VIA1B_vADBInt) ? "+" : "-"); data, (ms->b & VIA1B_vADBInt) ? "+" : "-");
qemu_irq_raise(s->adb_data_ready); qemu_irq_raise(v1s->adb_data_ready);
break; break;
case ADB_STATE_IDLE: case ADB_STATE_IDLE:
@ -730,40 +725,39 @@ static void adb_via_send(MacVIAState *s, int state, uint8_t data)
} }
/* If the command is complete, execute it */ /* If the command is complete, execute it */
if (s->adb_data_out_index == adb_via_send_len(s->adb_data_out[0])) { if (v1s->adb_data_out_index == adb_via_send_len(v1s->adb_data_out[0])) {
s->adb_data_in_size = adb_request(adb_bus, s->adb_data_in, v1s->adb_data_in_size = adb_request(adb_bus, v1s->adb_data_in,
s->adb_data_out, v1s->adb_data_out,
s->adb_data_out_index); v1s->adb_data_out_index);
s->adb_data_in_index = 0; v1s->adb_data_in_index = 0;
if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) { if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) {
/* /*
* Bus timeout (but allow first EVEN and ODD byte to indicate * Bus timeout (but allow first EVEN and ODD byte to indicate
* timeout via vADBInt and SRQ status) * timeout via vADBInt and SRQ status)
*/ */
s->adb_data_in[0] = 0xff; v1s->adb_data_in[0] = 0xff;
s->adb_data_in[1] = 0xff; v1s->adb_data_in[1] = 0xff;
s->adb_data_in_size = 2; v1s->adb_data_in_size = 2;
} }
/* /*
* If last command is TALK, store it for use by autopoll and adjust * If last command is TALK, store it for use by autopoll and adjust
* the autopoll mask accordingly * the autopoll mask accordingly
*/ */
if ((s->adb_data_out[0] & 0xc) == 0xc) { if ((v1s->adb_data_out[0] & 0xc) == 0xc) {
s->adb_autopoll_cmd = s->adb_data_out[0]; v1s->adb_autopoll_cmd = v1s->adb_data_out[0];
autopoll_mask = 1 << (s->adb_autopoll_cmd >> 4); autopoll_mask = 1 << (v1s->adb_autopoll_cmd >> 4);
adb_set_autopoll_mask(adb_bus, autopoll_mask); adb_set_autopoll_mask(adb_bus, autopoll_mask);
} }
} }
} }
static void adb_via_receive(MacVIAState *s, int state, uint8_t *data) static void adb_via_receive(MOS6522Q800VIA1State *v1s, int state, uint8_t *data)
{ {
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&s->mos6522_via1);
MOS6522State *ms = MOS6522(v1s); MOS6522State *ms = MOS6522(v1s);
ADBBusState *adb_bus = &s->adb_bus; ADBBusState *adb_bus = &v1s->adb_bus;
uint16_t pending; uint16_t pending;
switch (state) { switch (state) {
@ -777,16 +771,16 @@ static void adb_via_receive(MacVIAState *s, int state, uint8_t *data)
trace_via1_adb_receive("IDLE", *data, trace_via1_adb_receive("IDLE", *data,
(ms->b & VIA1B_vADBInt) ? "+" : "-", adb_bus->status, (ms->b & VIA1B_vADBInt) ? "+" : "-", adb_bus->status,
s->adb_data_in_index, s->adb_data_in_size); v1s->adb_data_in_index, v1s->adb_data_in_size);
break; break;
case ADB_STATE_EVEN: case ADB_STATE_EVEN:
case ADB_STATE_ODD: case ADB_STATE_ODD:
switch (s->adb_data_in_index) { switch (v1s->adb_data_in_index) {
case 0: case 0:
/* First EVEN byte: vADBInt indicates bus timeout */ /* First EVEN byte: vADBInt indicates bus timeout */
*data = s->adb_data_in[s->adb_data_in_index]; *data = v1s->adb_data_in[v1s->adb_data_in_index];
if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) { if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) {
ms->b &= ~VIA1B_vADBInt; ms->b &= ~VIA1B_vADBInt;
} else { } else {
@ -795,16 +789,16 @@ static void adb_via_receive(MacVIAState *s, int state, uint8_t *data)
trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD", trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
*data, (ms->b & VIA1B_vADBInt) ? "+" : "-", *data, (ms->b & VIA1B_vADBInt) ? "+" : "-",
adb_bus->status, s->adb_data_in_index, adb_bus->status, v1s->adb_data_in_index,
s->adb_data_in_size); v1s->adb_data_in_size);
s->adb_data_in_index++; v1s->adb_data_in_index++;
break; break;
case 1: case 1:
/* First ODD byte: vADBInt indicates SRQ */ /* First ODD byte: vADBInt indicates SRQ */
*data = s->adb_data_in[s->adb_data_in_index]; *data = v1s->adb_data_in[v1s->adb_data_in_index];
pending = adb_bus->pending & ~(1 << (s->adb_autopoll_cmd >> 4)); pending = adb_bus->pending & ~(1 << (v1s->adb_autopoll_cmd >> 4));
if (pending) { if (pending) {
ms->b &= ~VIA1B_vADBInt; ms->b &= ~VIA1B_vADBInt;
} else { } else {
@ -813,10 +807,10 @@ static void adb_via_receive(MacVIAState *s, int state, uint8_t *data)
trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD", trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
*data, (ms->b & VIA1B_vADBInt) ? "+" : "-", *data, (ms->b & VIA1B_vADBInt) ? "+" : "-",
adb_bus->status, s->adb_data_in_index, adb_bus->status, v1s->adb_data_in_index,
s->adb_data_in_size); v1s->adb_data_in_size);
s->adb_data_in_index++; v1s->adb_data_in_index++;
break; break;
default: default:
@ -826,11 +820,11 @@ static void adb_via_receive(MacVIAState *s, int state, uint8_t *data)
* end of the poll reply, so provide these extra bytes below to * end of the poll reply, so provide these extra bytes below to
* keep it happy * keep it happy
*/ */
if (s->adb_data_in_index < s->adb_data_in_size) { if (v1s->adb_data_in_index < v1s->adb_data_in_size) {
/* Next data byte */ /* Next data byte */
*data = s->adb_data_in[s->adb_data_in_index]; *data = v1s->adb_data_in[v1s->adb_data_in_index];
ms->b |= VIA1B_vADBInt; ms->b |= VIA1B_vADBInt;
} else if (s->adb_data_in_index == s->adb_data_in_size) { } else if (v1s->adb_data_in_index == v1s->adb_data_in_size) {
if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) { if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) {
/* Bus timeout (no more data) */ /* Bus timeout (no more data) */
*data = 0xff; *data = 0xff;
@ -849,23 +843,22 @@ static void adb_via_receive(MacVIAState *s, int state, uint8_t *data)
trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD", trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD",
*data, (ms->b & VIA1B_vADBInt) ? "+" : "-", *data, (ms->b & VIA1B_vADBInt) ? "+" : "-",
adb_bus->status, s->adb_data_in_index, adb_bus->status, v1s->adb_data_in_index,
s->adb_data_in_size); v1s->adb_data_in_size);
if (s->adb_data_in_index <= s->adb_data_in_size) { if (v1s->adb_data_in_index <= v1s->adb_data_in_size) {
s->adb_data_in_index++; v1s->adb_data_in_index++;
} }
break; break;
} }
qemu_irq_raise(s->adb_data_ready); qemu_irq_raise(v1s->adb_data_ready);
break; break;
} }
} }
static void via1_adb_update(MacVIAState *m) static void via1_adb_update(MOS6522Q800VIA1State *v1s)
{ {
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1);
MOS6522State *s = MOS6522(v1s); MOS6522State *s = MOS6522(v1s);
int oldstate, state; int oldstate, state;
@ -875,10 +868,10 @@ static void via1_adb_update(MacVIAState *m)
if (state != oldstate) { if (state != oldstate) {
if (s->acr & VIA1ACR_vShiftOut) { if (s->acr & VIA1ACR_vShiftOut) {
/* output mode */ /* output mode */
adb_via_send(m, state, s->sr); adb_via_send(v1s, state, s->sr);
} else { } else {
/* input mode */ /* input mode */
adb_via_receive(m, state, &s->sr); adb_via_receive(v1s, state, &s->sr);
} }
} }
} }
@ -896,7 +889,6 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size) unsigned size)
{ {
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque); MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque);
MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1);
MOS6522State *ms = MOS6522(v1s); MOS6522State *ms = MOS6522(v1s);
addr = (addr >> 9) & 0xf; addr = (addr >> 9) & 0xf;
@ -904,8 +896,8 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val,
switch (addr) { switch (addr) {
case VIA_REG_B: case VIA_REG_B:
via1_rtc_update(m); via1_rtc_update(v1s);
via1_adb_update(m); via1_adb_update(v1s);
v1s->last_b = ms->b; v1s->last_b = ms->b;
break; break;
@ -951,196 +943,35 @@ static const MemoryRegionOps mos6522_q800_via2_ops = {
}, },
}; };
static void mac_via_reset(DeviceState *dev) static void via1_postload_update_cb(void *opaque, bool running, RunState state)
{ {
MacVIAState *m = MAC_VIA(dev); MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque);
ADBBusState *adb_bus = &m->adb_bus;
adb_set_autopoll_enabled(adb_bus, true); qemu_del_vm_change_state_handler(v1s->vmstate);
v1s->vmstate = NULL;
m->cmd = REG_EMPTY; pram_update(v1s);
m->alt = REG_EMPTY;
} }
static void mac_via_realize(DeviceState *dev, Error **errp) static int via1_post_load(void *opaque, int version_id)
{ {
MacVIAState *m = MAC_VIA(dev); MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque);
MOS6522State *ms;
ADBBusState *adb_bus = &m->adb_bus;
struct tm tm;
int ret;
/* Init VIAs 1 and 2 */ if (v1s->blk) {
object_initialize_child(OBJECT(dev), "via1", &m->mos6522_via1, v1s->vmstate = qemu_add_vm_change_state_handler(
TYPE_MOS6522_Q800_VIA1); via1_postload_update_cb, v1s);
object_initialize_child(OBJECT(dev), "via2", &m->mos6522_via2,
TYPE_MOS6522_Q800_VIA2);
/* Pass through mos6522 output IRQs */
ms = MOS6522(&m->mos6522_via1);
object_property_add_alias(OBJECT(dev), "irq[0]", OBJECT(ms),
SYSBUS_DEVICE_GPIO_IRQ "[0]");
ms = MOS6522(&m->mos6522_via2);
object_property_add_alias(OBJECT(dev), "irq[1]", OBJECT(ms),
SYSBUS_DEVICE_GPIO_IRQ "[0]");
sysbus_realize(SYS_BUS_DEVICE(&m->mos6522_via1), &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&m->mos6522_via2), &error_abort);
/* Pass through mos6522 input IRQs */
qdev_pass_gpios(DEVICE(&m->mos6522_via1), dev, "via1-irq");
qdev_pass_gpios(DEVICE(&m->mos6522_via2), dev, "via2-irq");
/* VIA 1 */
m->mos6522_via1.one_second_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
via1_one_second,
&m->mos6522_via1);
via1_one_second_update(&m->mos6522_via1);
m->mos6522_via1.sixty_hz_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
via1_sixty_hz,
&m->mos6522_via1);
via1_sixty_hz_update(&m->mos6522_via1);
qemu_get_timedate(&tm, 0);
m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
adb_register_autopoll_callback(adb_bus, adb_via_poll, m);
m->adb_data_ready = qdev_get_gpio_in_named(dev, "via1-irq",
VIA1_IRQ_ADB_READY_BIT);
if (m->blk) {
int64_t len = blk_getlength(m->blk);
if (len < 0) {
error_setg_errno(errp, -len,
"could not get length of backing image");
return;
}
ret = blk_set_perm(m->blk,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
len = blk_pread(m->blk, 0, m->mos6522_via1.PRAM,
sizeof(m->mos6522_via1.PRAM));
if (len != sizeof(m->mos6522_via1.PRAM)) {
error_setg(errp, "can't read PRAM contents");
return;
}
}
}
static void mac_via_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
MacVIAState *m = MAC_VIA(obj);
/* MMIO */
memory_region_init(&m->mmio, obj, "mac-via", 2 * VIA_SIZE);
sysbus_init_mmio(sbd, &m->mmio);
memory_region_init_io(&m->via1mem, obj, &mos6522_q800_via1_ops,
&m->mos6522_via1, "via1", VIA_SIZE);
memory_region_add_subregion(&m->mmio, 0x0, &m->via1mem);
memory_region_init_io(&m->via2mem, obj, &mos6522_q800_via2_ops,
&m->mos6522_via2, "via2", VIA_SIZE);
memory_region_add_subregion(&m->mmio, VIA_SIZE, &m->via2mem);
/* ADB */
qbus_create_inplace((BusState *)&m->adb_bus, sizeof(m->adb_bus),
TYPE_ADB_BUS, DEVICE(obj), "adb.0");
}
static void postload_update_cb(void *opaque, bool running, RunState state)
{
MacVIAState *m = MAC_VIA(opaque);
qemu_del_vm_change_state_handler(m->vmstate);
m->vmstate = NULL;
pram_update(m);
}
static int mac_via_post_load(void *opaque, int version_id)
{
MacVIAState *m = MAC_VIA(opaque);
if (m->blk) {
m->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
m);
} }
return 0; return 0;
} }
static const VMStateDescription vmstate_mac_via = {
.name = "mac-via",
.version_id = 2,
.minimum_version_id = 2,
.post_load = mac_via_post_load,
.fields = (VMStateField[]) {
/* VIAs */
VMSTATE_STRUCT(mos6522_via1.parent_obj, MacVIAState, 0, vmstate_mos6522,
MOS6522State),
VMSTATE_UINT8(mos6522_via1.last_b, MacVIAState),
VMSTATE_BUFFER(mos6522_via1.PRAM, MacVIAState),
VMSTATE_TIMER_PTR(mos6522_via1.one_second_timer, MacVIAState),
VMSTATE_INT64(mos6522_via1.next_second, MacVIAState),
VMSTATE_TIMER_PTR(mos6522_via1.sixty_hz_timer, MacVIAState),
VMSTATE_INT64(mos6522_via1.next_sixty_hz, MacVIAState),
VMSTATE_STRUCT(mos6522_via2.parent_obj, MacVIAState, 0, vmstate_mos6522,
MOS6522State),
/* RTC */
VMSTATE_UINT32(tick_offset, MacVIAState),
VMSTATE_UINT8(data_out, MacVIAState),
VMSTATE_INT32(data_out_cnt, MacVIAState),
VMSTATE_UINT8(data_in, MacVIAState),
VMSTATE_UINT8(data_in_cnt, MacVIAState),
VMSTATE_UINT8(cmd, MacVIAState),
VMSTATE_INT32(wprotect, MacVIAState),
VMSTATE_INT32(alt, MacVIAState),
/* ADB */
VMSTATE_INT32(adb_data_in_size, MacVIAState),
VMSTATE_INT32(adb_data_in_index, MacVIAState),
VMSTATE_INT32(adb_data_out_index, MacVIAState),
VMSTATE_BUFFER(adb_data_in, MacVIAState),
VMSTATE_BUFFER(adb_data_out, MacVIAState),
VMSTATE_UINT8(adb_autopoll_cmd, MacVIAState),
VMSTATE_END_OF_LIST()
}
};
static Property mac_via_properties[] = {
DEFINE_PROP_DRIVE("drive", MacVIAState, blk),
DEFINE_PROP_END_OF_LIST(),
};
static void mac_via_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mac_via_realize;
dc->reset = mac_via_reset;
dc->vmsd = &vmstate_mac_via;
device_class_set_props(dc, mac_via_properties);
}
static TypeInfo mac_via_info = {
.name = TYPE_MAC_VIA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MacVIAState),
.instance_init = mac_via_init,
.class_init = mac_via_class_init,
};
/* VIA 1 */ /* VIA 1 */
static void mos6522_q800_via1_reset(DeviceState *dev) static void mos6522_q800_via1_reset(DeviceState *dev)
{ {
MOS6522State *ms = MOS6522(dev); MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(dev);
MOS6522State *ms = MOS6522(v1s);
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
ADBBusState *adb_bus = &v1s->adb_bus;
mdc->parent_reset(dev); mdc->parent_reset(dev);
@ -1148,19 +979,119 @@ static void mos6522_q800_via1_reset(DeviceState *dev)
ms->timers[1].frequency = VIA_TIMER_FREQ; ms->timers[1].frequency = VIA_TIMER_FREQ;
ms->b = VIA1B_vADB_StateMask | VIA1B_vADBInt | VIA1B_vRTCEnb; ms->b = VIA1B_vADB_StateMask | VIA1B_vADBInt | VIA1B_vRTCEnb;
/* ADB/RTC */
adb_set_autopoll_enabled(adb_bus, true);
v1s->cmd = REG_EMPTY;
v1s->alt = REG_EMPTY;
}
static void mos6522_q800_via1_realize(DeviceState *dev, Error **errp)
{
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(dev);
ADBBusState *adb_bus = &v1s->adb_bus;
struct tm tm;
int ret;
v1s->one_second_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, via1_one_second,
v1s);
via1_one_second_update(v1s);
v1s->sixty_hz_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via1_sixty_hz,
v1s);
via1_sixty_hz_update(v1s);
qemu_get_timedate(&tm, 0);
v1s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
adb_register_autopoll_callback(adb_bus, adb_via_poll, v1s);
v1s->adb_data_ready = qdev_get_gpio_in(dev, VIA1_IRQ_ADB_READY_BIT);
if (v1s->blk) {
int64_t len = blk_getlength(v1s->blk);
if (len < 0) {
error_setg_errno(errp, -len,
"could not get length of backing image");
return;
}
ret = blk_set_perm(v1s->blk,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
len = blk_pread(v1s->blk, 0, v1s->PRAM, sizeof(v1s->PRAM));
if (len != sizeof(v1s->PRAM)) {
error_setg(errp, "can't read PRAM contents");
return;
}
}
} }
static void mos6522_q800_via1_init(Object *obj) static void mos6522_q800_via1_init(Object *obj)
{ {
qdev_init_gpio_in_named(DEVICE(obj), via1_irq_request, "via1-irq", MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(obj);
VIA1_IRQ_NB); SysBusDevice *sbd = SYS_BUS_DEVICE(v1s);
memory_region_init_io(&v1s->via_mem, obj, &mos6522_q800_via1_ops, v1s,
"via1", VIA_SIZE);
sysbus_init_mmio(sbd, &v1s->via_mem);
/* ADB */
qbus_create_inplace((BusState *)&v1s->adb_bus, sizeof(v1s->adb_bus),
TYPE_ADB_BUS, DEVICE(v1s), "adb.0");
qdev_init_gpio_in(DEVICE(obj), via1_irq_request, VIA1_IRQ_NB);
} }
static const VMStateDescription vmstate_q800_via1 = {
.name = "q800-via1",
.version_id = 0,
.minimum_version_id = 0,
.post_load = via1_post_load,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(parent_obj, MOS6522Q800VIA1State, 0, vmstate_mos6522,
MOS6522State),
VMSTATE_UINT8(last_b, MOS6522Q800VIA1State),
/* RTC */
VMSTATE_BUFFER(PRAM, MOS6522Q800VIA1State),
VMSTATE_UINT32(tick_offset, MOS6522Q800VIA1State),
VMSTATE_UINT8(data_out, MOS6522Q800VIA1State),
VMSTATE_INT32(data_out_cnt, MOS6522Q800VIA1State),
VMSTATE_UINT8(data_in, MOS6522Q800VIA1State),
VMSTATE_UINT8(data_in_cnt, MOS6522Q800VIA1State),
VMSTATE_UINT8(cmd, MOS6522Q800VIA1State),
VMSTATE_INT32(wprotect, MOS6522Q800VIA1State),
VMSTATE_INT32(alt, MOS6522Q800VIA1State),
/* ADB */
VMSTATE_INT32(adb_data_in_size, MOS6522Q800VIA1State),
VMSTATE_INT32(adb_data_in_index, MOS6522Q800VIA1State),
VMSTATE_INT32(adb_data_out_index, MOS6522Q800VIA1State),
VMSTATE_BUFFER(adb_data_in, MOS6522Q800VIA1State),
VMSTATE_BUFFER(adb_data_out, MOS6522Q800VIA1State),
VMSTATE_UINT8(adb_autopoll_cmd, MOS6522Q800VIA1State),
/* Timers */
VMSTATE_TIMER_PTR(one_second_timer, MOS6522Q800VIA1State),
VMSTATE_INT64(next_second, MOS6522Q800VIA1State),
VMSTATE_TIMER_PTR(sixty_hz_timer, MOS6522Q800VIA1State),
VMSTATE_INT64(next_sixty_hz, MOS6522Q800VIA1State),
VMSTATE_END_OF_LIST()
}
};
static Property mos6522_q800_via1_properties[] = {
DEFINE_PROP_DRIVE("drive", MOS6522Q800VIA1State, blk),
DEFINE_PROP_END_OF_LIST(),
};
static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data) static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mos6522_q800_via1_realize;
dc->reset = mos6522_q800_via1_reset; dc->reset = mos6522_q800_via1_reset;
dc->vmsd = &vmstate_q800_via1;
device_class_set_props(dc, mos6522_q800_via1_properties);
} }
static const TypeInfo mos6522_q800_via1_type_info = { static const TypeInfo mos6522_q800_via1_type_info = {
@ -1192,20 +1123,61 @@ static void mos6522_q800_via2_reset(DeviceState *dev)
ms->dirb = 0; ms->dirb = 0;
ms->b = 0; ms->b = 0;
ms->dira = 0;
ms->a = 0x7f;
}
static void via2_nubus_irq_request(void *opaque, int irq, int level)
{
MOS6522Q800VIA2State *v2s = opaque;
MOS6522State *s = MOS6522(v2s);
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
if (level) {
/* Port A nubus IRQ inputs are active LOW */
s->a &= ~(1 << irq);
s->ifr |= 1 << VIA2_IRQ_NUBUS_BIT;
} else {
s->a |= (1 << irq);
s->ifr &= ~(1 << VIA2_IRQ_NUBUS_BIT);
}
mdc->update_irq(s);
} }
static void mos6522_q800_via2_init(Object *obj) static void mos6522_q800_via2_init(Object *obj)
{ {
qdev_init_gpio_in_named(DEVICE(obj), via2_irq_request, "via2-irq", MOS6522Q800VIA2State *v2s = MOS6522_Q800_VIA2(obj);
VIA2_IRQ_NB); SysBusDevice *sbd = SYS_BUS_DEVICE(v2s);
memory_region_init_io(&v2s->via_mem, obj, &mos6522_q800_via2_ops, v2s,
"via2", VIA_SIZE);
sysbus_init_mmio(sbd, &v2s->via_mem);
qdev_init_gpio_in(DEVICE(obj), via2_irq_request, VIA2_IRQ_NB);
qdev_init_gpio_in_named(DEVICE(obj), via2_nubus_irq_request, "nubus-irq",
VIA2_NUBUS_IRQ_NB);
} }
static const VMStateDescription vmstate_q800_via2 = {
.name = "q800-via2",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(parent_obj, MOS6522Q800VIA2State, 0, vmstate_mos6522,
MOS6522State),
VMSTATE_END_OF_LIST()
}
};
static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data) static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
dc->reset = mos6522_q800_via2_reset; dc->reset = mos6522_q800_via2_reset;
dc->vmsd = &vmstate_q800_via2;
mdc->portB_write = mos6522_q800_via2_portB_write; mdc->portB_write = mos6522_q800_via2_portB_write;
} }
@ -1221,7 +1193,6 @@ static void mac_via_register_types(void)
{ {
type_register_static(&mos6522_q800_via1_type_info); type_register_static(&mos6522_q800_via1_type_info);
type_register_static(&mos6522_q800_via2_type_info); type_register_static(&mos6522_q800_via2_type_info);
type_register_static(&mac_via_info);
} }
type_init(mac_via_register_types); type_init(mac_via_register_types);

View File

@ -15,6 +15,8 @@
#include "qom/object.h" #include "qom/object.h"
#define VIA_SIZE 0x2000
/* VIA 1 */ /* VIA 1 */
#define VIA1_IRQ_ONE_SECOND_BIT 0 #define VIA1_IRQ_ONE_SECOND_BIT 0
#define VIA1_IRQ_60HZ_BIT 1 #define VIA1_IRQ_60HZ_BIT 1
@ -24,11 +26,11 @@
#define VIA1_IRQ_NB 8 #define VIA1_IRQ_NB 8
#define VIA1_IRQ_ONE_SECOND (1 << VIA1_IRQ_ONE_SECOND_BIT) #define VIA1_IRQ_ONE_SECOND (1 << VIA1_IRQ_ONE_SECOND_BIT)
#define VIA1_IRQ_60HZ (1 << VIA1_IRQ_60HZ_BIT) #define VIA1_IRQ_60HZ (1 << VIA1_IRQ_60HZ_BIT)
#define VIA1_IRQ_ADB_READY (1 << VIA1_IRQ_ADB_READY_BIT) #define VIA1_IRQ_ADB_READY (1 << VIA1_IRQ_ADB_READY_BIT)
#define VIA1_IRQ_ADB_DATA (1 << VIA1_IRQ_ADB_DATA_BIT) #define VIA1_IRQ_ADB_DATA (1 << VIA1_IRQ_ADB_DATA_BIT)
#define VIA1_IRQ_ADB_CLOCK (1 << VIA1_IRQ_ADB_CLOCK_BIT) #define VIA1_IRQ_ADB_CLOCK (1 << VIA1_IRQ_ADB_CLOCK_BIT)
#define TYPE_MOS6522_Q800_VIA1 "mos6522-q800-via1" #define TYPE_MOS6522_Q800_VIA1 "mos6522-q800-via1"
@ -38,9 +40,35 @@ struct MOS6522Q800VIA1State {
/*< private >*/ /*< private >*/
MOS6522State parent_obj; MOS6522State parent_obj;
MemoryRegion via_mem;
qemu_irq irqs[VIA1_IRQ_NB]; qemu_irq irqs[VIA1_IRQ_NB];
uint8_t last_b; uint8_t last_b;
/* RTC */
uint8_t PRAM[256]; uint8_t PRAM[256];
BlockBackend *blk;
VMChangeStateEntry *vmstate;
uint32_t tick_offset;
uint8_t data_out;
int data_out_cnt;
uint8_t data_in;
uint8_t data_in_cnt;
uint8_t cmd;
int wprotect;
int alt;
/* ADB */
ADBBusState adb_bus;
qemu_irq adb_data_ready;
int adb_data_in_size;
int adb_data_in_index;
int adb_data_out_index;
uint8_t adb_data_in[128];
uint8_t adb_data_out[16];
uint8_t adb_autopoll_cmd;
/* external timers */ /* external timers */
QEMUTimer *one_second_timer; QEMUTimer *one_second_timer;
@ -52,18 +80,28 @@ struct MOS6522Q800VIA1State {
/* VIA 2 */ /* VIA 2 */
#define VIA2_IRQ_SCSI_DATA_BIT 0 #define VIA2_IRQ_SCSI_DATA_BIT 0
#define VIA2_IRQ_SLOT_BIT 1 #define VIA2_IRQ_NUBUS_BIT 1
#define VIA2_IRQ_UNUSED_BIT 2 #define VIA2_IRQ_UNUSED_BIT 2
#define VIA2_IRQ_SCSI_BIT 3 #define VIA2_IRQ_SCSI_BIT 3
#define VIA2_IRQ_ASC_BIT 4 #define VIA2_IRQ_ASC_BIT 4
#define VIA2_IRQ_NB 8 #define VIA2_IRQ_NB 8
#define VIA2_IRQ_SCSI_DATA (1 << VIA2_IRQ_SCSI_DATA_BIT) #define VIA2_IRQ_SCSI_DATA (1 << VIA2_IRQ_SCSI_DATA_BIT)
#define VIA2_IRQ_SLOT (1 << VIA2_IRQ_SLOT_BIT) #define VIA2_IRQ_NUBUS (1 << VIA2_IRQ_NUBUS_BIT)
#define VIA2_IRQ_UNUSED (1 << VIA2_IRQ_SCSI_BIT) #define VIA2_IRQ_UNUSED (1 << VIA2_IRQ_SCSI_BIT)
#define VIA2_IRQ_SCSI (1 << VIA2_IRQ_UNUSED_BIT) #define VIA2_IRQ_SCSI (1 << VIA2_IRQ_UNUSED_BIT)
#define VIA2_IRQ_ASC (1 << VIA2_IRQ_ASC_BIT) #define VIA2_IRQ_ASC (1 << VIA2_IRQ_ASC_BIT)
#define VIA2_NUBUS_IRQ_NB 7
#define VIA2_NUBUS_IRQ_9 0
#define VIA2_NUBUS_IRQ_A 1
#define VIA2_NUBUS_IRQ_B 2
#define VIA2_NUBUS_IRQ_C 3
#define VIA2_NUBUS_IRQ_D 4
#define VIA2_NUBUS_IRQ_E 5
#define VIA2_NUBUS_IRQ_INTVIDEO 6
#define TYPE_MOS6522_Q800_VIA2 "mos6522-q800-via2" #define TYPE_MOS6522_Q800_VIA2 "mos6522-q800-via2"
OBJECT_DECLARE_SIMPLE_TYPE(MOS6522Q800VIA2State, MOS6522_Q800_VIA2) OBJECT_DECLARE_SIMPLE_TYPE(MOS6522Q800VIA2State, MOS6522_Q800_VIA2)
@ -71,47 +109,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(MOS6522Q800VIA2State, MOS6522_Q800_VIA2)
struct MOS6522Q800VIA2State { struct MOS6522Q800VIA2State {
/*< private >*/ /*< private >*/
MOS6522State parent_obj; MOS6522State parent_obj;
};
MemoryRegion via_mem;
#define TYPE_MAC_VIA "mac_via"
OBJECT_DECLARE_SIMPLE_TYPE(MacVIAState, MAC_VIA)
struct MacVIAState {
SysBusDevice busdev;
VMChangeStateEntry *vmstate;
/* MMIO */
MemoryRegion mmio;
MemoryRegion via1mem;
MemoryRegion via2mem;
/* VIAs */
MOS6522Q800VIA1State mos6522_via1;
MOS6522Q800VIA2State mos6522_via2;
/* RTC */
uint32_t tick_offset;
uint8_t data_out;
int data_out_cnt;
uint8_t data_in;
uint8_t data_in_cnt;
uint8_t cmd;
int wprotect;
int alt;
BlockBackend *blk;
/* ADB */
ADBBusState adb_bus;
qemu_irq adb_data_ready;
int adb_data_in_size;
int adb_data_in_index;
int adb_data_out_index;
uint8_t adb_data_in[128];
uint8_t adb_data_out[16];
uint8_t adb_autopoll_cmd;
}; };
#endif #endif