mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'q800-for-8.2-pull-request' of https://github.com/vivier/qemu-m68k into staging
Pull request q800 20231008 add support for booting: - MacOS 7.1 - 8.1, with or without virtual memory enabled - A/UX 3.0.1 - NetBSD 9.3 - Linux (via EMILE) # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmUiSrISHGxhdXJlbnRA # dml2aWVyLmV1AAoJEPMMOL0/L748oSUQAKAm3TPYQUDDVFTi2uhzv6IgNSgOVUhK # 3I3xoNb0UR9AT3Wfg1fah5La3p0kL9Y25gvhCl6veUg39WVicv3fbqUevbJ1Nwgl # ovwS3MRRcvYhU+omcXImFfoIPyOxfSf3vZ6SedIkB24hQyXN9eFBZMfgCODU6lfo # rAd/Hm50N2jRI8aKjvN+uHFRz75wqq6rNk/4QLWihRqhtWrjUDPHOTMI9sQxWy9z # LcXxVKbWCY8/WOAandsGL94l2jfu94HM6CfwHaumdxvPBZT6WUyCv3T1rJsVJU29 # b8oTLcwKAmZ7lGLbjl6GdB8q5KAJFCAGLWuEbNIMj0orB37OpUd0Wx2SD9+aA53H # yoKGbk6N1UappTtcnZCfwzWRzNaXrRno+w+/xYjlKsXBdHV9ZXHMGD5ERxoC6MY7 # ISsCa4bafeUDes6SCetgq87ho69E8l+gAlNYPgidHaTP226BjrYWQRJIa0leczfO # aE6dAG7MQFOnOjeOHEJMDB2XpKHiVe1lyVGQH485cLW1J6LHJFWUfUUH2Zjs1v1z # eXZHBTclPO2wbuQzXG6pAz2jdF/9w4ft/aA0PQhQcFxa9RB6AoNFG/juHJN5eUiw # NXJetR2g1juNPqmMFWDNMJ7Zzce5Chjoj69XJBFYSXhgbOtwpUpoEPZUeIMcW1eJ # Va2HvyDQPp1B # =RUHg # -----END PGP SIGNATURE----- # gpg: Signature made Sun 08 Oct 2023 02:22:42 EDT # 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 * tag 'q800-for-8.2-pull-request' of https://github.com/vivier/qemu-m68k: mac_via: extend timer calibration hack to work with A/UX q800: add alias for MacOS toolbox ROM at 0x40000000 q800: add ESCC alias at 0xc000 mac_via: always clear ADB interrupt when switching to A/UX mode mac_via: implement ADB_STATE_IDLE state if shift register in input mode mac_via: workaround NetBSD ADB bus enumeration issue mac_via: work around underflow in TimeDBRA timing loop in SETUPTIMEK swim: update IWM/ISM register block decoding swim: split into separate IWM and ISM register blocks swim: add trace events for IWM and ISM registers q800: add easc bool machine class property to switch between ASC and EASC q800: add Apple Sound Chip (ASC) audio to machine asc: generate silence if FIFO empty but engine still running audio: add Apple Sound Chip (ASC) emulation q800: allow accesses to RAM area even if less memory is available q800: add IOSB subsystem q800: implement additional machine id bits on VIA1 port A q800: add machine id register q800: add djMEMC memory controller q800-glue.c: convert to Resettable interface Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
@@ -1229,6 +1229,9 @@ F: hw/misc/mac_via.c
|
||||
F: hw/nubus/*
|
||||
F: hw/display/macfb.c
|
||||
F: hw/block/swim.c
|
||||
F: hw/misc/djmemc.c
|
||||
F: hw/misc/iosb.c
|
||||
F: hw/audio/asc.c
|
||||
F: hw/m68k/bootinfo.h
|
||||
F: include/standard-headers/asm-m68k/bootinfo.h
|
||||
F: include/standard-headers/asm-m68k/bootinfo-mac.h
|
||||
@@ -1238,6 +1241,9 @@ F: include/hw/display/macfb.h
|
||||
F: include/hw/block/swim.h
|
||||
F: include/hw/m68k/q800.h
|
||||
F: include/hw/m68k/q800-glue.h
|
||||
F: include/hw/misc/djmemc.h
|
||||
F: include/hw/misc/iosb.h
|
||||
F: include/hw/audio/asc.h
|
||||
|
||||
virt
|
||||
M: Laurent Vivier <laurent@vivier.eu>
|
||||
|
||||
@@ -47,3 +47,6 @@ config PL041
|
||||
|
||||
config CS4231
|
||||
bool
|
||||
|
||||
config ASC
|
||||
bool
|
||||
|
||||
+727
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
system_ss.add(files('soundhw.c'))
|
||||
system_ss.add(when: 'CONFIG_AC97', if_true: files('ac97.c'))
|
||||
system_ss.add(when: 'CONFIG_ADLIB', if_true: files('fmopl.c', 'adlib.c'))
|
||||
system_ss.add(when: 'CONFIG_ASC', if_true: files('asc.c'))
|
||||
system_ss.add(when: 'CONFIG_CS4231', if_true: files('cs4231.c'))
|
||||
system_ss.add(when: 'CONFIG_CS4231A', if_true: files('cs4231a.c'))
|
||||
system_ss.add(when: 'CONFIG_ES1370', if_true: files('es1370.c'))
|
||||
|
||||
@@ -17,3 +17,13 @@ via_ac97_codec_write(uint8_t addr, uint16_t val) "0x%x <- 0x%x"
|
||||
via_ac97_sgd_fetch(uint32_t curr, uint32_t addr, char stop, char eol, char flag, uint32_t len) "curr=0x%x addr=0x%x %c%c%c len=%d"
|
||||
via_ac97_sgd_read(uint64_t addr, unsigned size, uint64_t val) "0x%"PRIx64" %d -> 0x%"PRIx64
|
||||
via_ac97_sgd_write(uint64_t addr, unsigned size, uint64_t val) "0x%"PRIx64" %d <- 0x%"PRIx64
|
||||
|
||||
# asc.c
|
||||
asc_read_fifo(const char fifo, int reg, unsigned size, uint64_t value) "fifo %c reg=0x%03x size=%u value=0x%"PRIx64
|
||||
asc_read_reg(int reg, unsigned size, uint64_t value) "reg=0x%03x size=%u value=0x%"PRIx64
|
||||
asc_read_extreg(const char fifo, int reg, unsigned size, uint64_t value) "fifo %c reg=0x%03x size=%u value=0x%"PRIx64
|
||||
asc_fifo_get(const char fifo, int rptr, int cnt, uint64_t value) "fifo %c rptr=0x%x cnt=0x%x value=0x%"PRIx64
|
||||
asc_write_fifo(const char fifo, int reg, unsigned size, int wrptr, int cnt, uint64_t value) "fifo %c reg=0x%03x size=%u wptr=0x%x cnt=0x%x value=0x%"PRIx64
|
||||
asc_write_reg(int reg, unsigned size, uint64_t value) "reg=0x%03x size=%u value=0x%"PRIx64
|
||||
asc_write_extreg(const char fifo, int reg, unsigned size, uint64_t value) "fifo %c reg=0x%03x size=%u value=0x%"PRIx64
|
||||
asc_update_irq(int irq, int a, int b) "set IRQ to %d (A: 0x%x B: 0x%x)"
|
||||
|
||||
+189
-102
@@ -19,25 +19,30 @@
|
||||
#include "hw/block/block.h"
|
||||
#include "hw/block/swim.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
/* IWM latch bits */
|
||||
|
||||
#define IWMLB_PHASE0 0
|
||||
#define IWMLB_PHASE1 1
|
||||
#define IWMLB_PHASE2 2
|
||||
#define IWMLB_PHASE3 3
|
||||
#define IWMLB_MOTORON 4
|
||||
#define IWMLB_DRIVESEL 5
|
||||
#define IWMLB_L6 6
|
||||
#define IWMLB_L7 7
|
||||
|
||||
/* IWM registers */
|
||||
|
||||
#define IWM_PH0L 0
|
||||
#define IWM_PH0H 1
|
||||
#define IWM_PH1L 2
|
||||
#define IWM_PH1H 3
|
||||
#define IWM_PH2L 4
|
||||
#define IWM_PH2H 5
|
||||
#define IWM_PH3L 6
|
||||
#define IWM_PH3H 7
|
||||
#define IWM_MTROFF 8
|
||||
#define IWM_MTRON 9
|
||||
#define IWM_INTDRIVE 10
|
||||
#define IWM_EXTDRIVE 11
|
||||
#define IWM_Q6L 12
|
||||
#define IWM_Q6H 13
|
||||
#define IWM_Q7L 14
|
||||
#define IWM_Q7H 15
|
||||
#define IWM_READALLONES 0
|
||||
#define IWM_READDATA 1
|
||||
#define IWM_READSTATUS0 2
|
||||
#define IWM_READSTATUS1 3
|
||||
#define IWM_READWHANDSHAKE0 4
|
||||
#define IWM_READWHANDSHAKE1 5
|
||||
#define IWM_WRITESETMODE 6
|
||||
#define IWM_WRITEDATA 7
|
||||
|
||||
/* SWIM registers */
|
||||
|
||||
@@ -61,8 +66,9 @@
|
||||
|
||||
#define REG_SHIFT 9
|
||||
|
||||
#define SWIM_MODE_IWM 0
|
||||
#define SWIM_MODE_SWIM 1
|
||||
#define SWIM_MODE_STATUS_BIT 6
|
||||
#define SWIM_MODE_IWM 0
|
||||
#define SWIM_MODE_ISM 1
|
||||
|
||||
/* bits in phase register */
|
||||
|
||||
@@ -125,6 +131,18 @@
|
||||
#define SWIM_HEDSEL 0x20
|
||||
#define SWIM_MOTON 0x80
|
||||
|
||||
static const char *iwm_reg_names[] = {
|
||||
"READALLONES", "READDATA", "READSTATUS0", "READSTATUS1",
|
||||
"READWHANDSHAKE0", "READWHANDSHAKE1", "WRITESETMODE", "WRITEDATA"
|
||||
};
|
||||
|
||||
static const char *ism_reg_names[] = {
|
||||
"WRITE_DATA", "WRITE_MARK", "WRITE_CRC", "WRITE_PARAMETER",
|
||||
"WRITE_PHASE", "WRITE_SETUP", "WRITE_MODE0", "WRITE_MODE1",
|
||||
"READ_DATA", "READ_MARK", "READ_ERROR", "READ_PARAMETER",
|
||||
"READ_PHASE", "READ_SETUP", "READ_STATUS", "READ_HANDSHAKE"
|
||||
};
|
||||
|
||||
static void fd_recalibrate(FDrive *drive)
|
||||
{
|
||||
}
|
||||
@@ -259,73 +277,116 @@ static const TypeInfo swim_bus_info = {
|
||||
.instance_size = sizeof(SWIMBus),
|
||||
};
|
||||
|
||||
static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value,
|
||||
static void iwmctrl_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
SWIMCtrl *swimctrl = opaque;
|
||||
uint8_t latch, reg, ism_bit;
|
||||
|
||||
addr >>= REG_SHIFT;
|
||||
|
||||
/* A3-A1 select a latch, A0 specifies the value */
|
||||
latch = (addr >> 1) & 7;
|
||||
if (addr & 1) {
|
||||
swimctrl->iwm_latches |= (1 << latch);
|
||||
} else {
|
||||
swimctrl->iwm_latches &= ~(1 << latch);
|
||||
}
|
||||
|
||||
reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
|
||||
(swimctrl->iwm_latches & 0x10) >> 4;
|
||||
|
||||
swimctrl->iwmregs[reg] = value;
|
||||
trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value);
|
||||
|
||||
switch (reg) {
|
||||
case IWM_WRITESETMODE:
|
||||
/* detect sequence to switch from IWM mode to SWIM mode */
|
||||
ism_bit = (value & (1 << SWIM_MODE_STATUS_BIT));
|
||||
|
||||
switch (swimctrl->iwm_switch) {
|
||||
case 0:
|
||||
if (ism_bit) { /* 1 */
|
||||
swimctrl->iwm_switch++;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!ism_bit) { /* 0 */
|
||||
swimctrl->iwm_switch++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ism_bit) { /* 1 */
|
||||
swimctrl->iwm_switch++;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (ism_bit) { /* 1 */
|
||||
swimctrl->iwm_switch++;
|
||||
|
||||
swimctrl->mode = SWIM_MODE_ISM;
|
||||
swimctrl->swim_mode |= (1 << SWIM_MODE_STATUS_BIT);
|
||||
swimctrl->iwm_switch = 0;
|
||||
trace_swim_switch_to_ism();
|
||||
|
||||
/* Switch to ISM registers */
|
||||
memory_region_del_subregion(&swimctrl->swim, &swimctrl->iwm);
|
||||
memory_region_add_subregion(&swimctrl->swim, 0x0,
|
||||
&swimctrl->ism);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t iwmctrl_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
SWIMCtrl *swimctrl = opaque;
|
||||
uint8_t latch, reg, value;
|
||||
|
||||
addr >>= REG_SHIFT;
|
||||
|
||||
/* A3-A1 select a latch, A0 specifies the value */
|
||||
latch = (addr >> 1) & 7;
|
||||
if (addr & 1) {
|
||||
swimctrl->iwm_latches |= (1 << latch);
|
||||
} else {
|
||||
swimctrl->iwm_latches &= ~(1 << latch);
|
||||
}
|
||||
|
||||
reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
|
||||
(swimctrl->iwm_latches & 0x10) >> 4;
|
||||
|
||||
switch (reg) {
|
||||
case IWM_READALLONES:
|
||||
value = 0xff;
|
||||
break;
|
||||
default:
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps swimctrl_iwm_ops = {
|
||||
.write = iwmctrl_write,
|
||||
.read = iwmctrl_read,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
SWIMCtrl *swimctrl = opaque;
|
||||
|
||||
reg >>= REG_SHIFT;
|
||||
|
||||
swimctrl->regs[reg >> 1] = reg & 1;
|
||||
|
||||
if (swimctrl->regs[IWM_Q6] &&
|
||||
swimctrl->regs[IWM_Q7]) {
|
||||
if (swimctrl->regs[IWM_MTR]) {
|
||||
/* data register */
|
||||
swimctrl->iwm_data = value;
|
||||
} else {
|
||||
/* mode register */
|
||||
swimctrl->iwm_mode = value;
|
||||
/* detect sequence to switch from IWM mode to SWIM mode */
|
||||
switch (swimctrl->iwm_switch) {
|
||||
case 0:
|
||||
if (value == 0x57) {
|
||||
swimctrl->iwm_switch++;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (value == 0x17) {
|
||||
swimctrl->iwm_switch++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (value == 0x57) {
|
||||
swimctrl->iwm_switch++;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (value == 0x57) {
|
||||
swimctrl->mode = SWIM_MODE_SWIM;
|
||||
swimctrl->iwm_switch = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size)
|
||||
{
|
||||
SWIMCtrl *swimctrl = opaque;
|
||||
|
||||
reg >>= REG_SHIFT;
|
||||
|
||||
swimctrl->regs[reg >> 1] = reg & 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
SWIMCtrl *swimctrl = opaque;
|
||||
|
||||
if (swimctrl->mode == SWIM_MODE_IWM) {
|
||||
iwmctrl_write(opaque, reg, value, size);
|
||||
return;
|
||||
}
|
||||
|
||||
reg >>= REG_SHIFT;
|
||||
trace_swim_ismctrl_write(reg, ism_reg_names[reg], size, value);
|
||||
|
||||
switch (reg) {
|
||||
case SWIM_WRITE_PHASE:
|
||||
@@ -333,28 +394,41 @@ static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value,
|
||||
break;
|
||||
case SWIM_WRITE_MODE0:
|
||||
swimctrl->swim_mode &= ~value;
|
||||
/* Any access to MODE0 register resets PRAM index */
|
||||
swimctrl->pram_idx = 0;
|
||||
|
||||
if (!(swimctrl->swim_mode & (1 << SWIM_MODE_STATUS_BIT))) {
|
||||
/* Clearing the mode bit switches to IWM mode */
|
||||
swimctrl->mode = SWIM_MODE_IWM;
|
||||
swimctrl->iwm_latches = 0;
|
||||
trace_swim_switch_to_iwm();
|
||||
|
||||
/* Switch to IWM registers */
|
||||
memory_region_del_subregion(&swimctrl->swim, &swimctrl->ism);
|
||||
memory_region_add_subregion(&swimctrl->swim, 0x0,
|
||||
&swimctrl->iwm);
|
||||
}
|
||||
break;
|
||||
case SWIM_WRITE_MODE1:
|
||||
swimctrl->swim_mode |= value;
|
||||
break;
|
||||
case SWIM_WRITE_PARAMETER:
|
||||
swimctrl->pram[swimctrl->pram_idx++] = value;
|
||||
swimctrl->pram_idx &= 0xf;
|
||||
break;
|
||||
case SWIM_WRITE_DATA:
|
||||
case SWIM_WRITE_MARK:
|
||||
case SWIM_WRITE_CRC:
|
||||
case SWIM_WRITE_PARAMETER:
|
||||
case SWIM_WRITE_SETUP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size)
|
||||
static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size)
|
||||
{
|
||||
SWIMCtrl *swimctrl = opaque;
|
||||
uint32_t value = 0;
|
||||
|
||||
if (swimctrl->mode == SWIM_MODE_IWM) {
|
||||
return iwmctrl_read(opaque, reg, size);
|
||||
}
|
||||
|
||||
reg >>= REG_SHIFT;
|
||||
|
||||
switch (reg) {
|
||||
@@ -367,22 +441,31 @@ static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size)
|
||||
value = SWIM_SENSE;
|
||||
}
|
||||
break;
|
||||
case SWIM_READ_PARAMETER:
|
||||
value = swimctrl->pram[swimctrl->pram_idx++];
|
||||
swimctrl->pram_idx &= 0xf;
|
||||
break;
|
||||
case SWIM_READ_STATUS:
|
||||
value = swimctrl->swim_status & ~(1 << SWIM_MODE_STATUS_BIT);
|
||||
if (swimctrl->swim_mode == SWIM_MODE_ISM) {
|
||||
value |= (1 << SWIM_MODE_STATUS_BIT);
|
||||
}
|
||||
break;
|
||||
case SWIM_READ_DATA:
|
||||
case SWIM_READ_MARK:
|
||||
case SWIM_READ_ERROR:
|
||||
case SWIM_READ_PARAMETER:
|
||||
case SWIM_READ_SETUP:
|
||||
case SWIM_READ_STATUS:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_swim_ismctrl_read(reg, ism_reg_names[reg], size, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps swimctrl_mem_ops = {
|
||||
.write = swimctrl_write,
|
||||
.read = swimctrl_read,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
static const MemoryRegionOps swimctrl_ism_ops = {
|
||||
.write = ismctrl_write,
|
||||
.read = ismctrl_read,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void sysbus_swim_reset(DeviceState *d)
|
||||
@@ -393,13 +476,11 @@ static void sysbus_swim_reset(DeviceState *d)
|
||||
|
||||
ctrl->mode = 0;
|
||||
ctrl->iwm_switch = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ctrl->regs[i] = 0;
|
||||
}
|
||||
ctrl->iwm_data = 0;
|
||||
ctrl->iwm_mode = 0;
|
||||
memset(ctrl->iwmregs, 0, sizeof(ctrl->iwmregs));
|
||||
|
||||
ctrl->swim_phase = 0;
|
||||
ctrl->swim_mode = 0;
|
||||
memset(ctrl->ismregs, 0, sizeof(ctrl->ismregs));
|
||||
for (i = 0; i < SWIM_MAX_FD; i++) {
|
||||
fd_recalibrate(&ctrl->drives[i]);
|
||||
}
|
||||
@@ -411,9 +492,12 @@ static void sysbus_swim_init(Object *obj)
|
||||
Swim *sbs = SWIM(obj);
|
||||
SWIMCtrl *swimctrl = &sbs->ctrl;
|
||||
|
||||
memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl,
|
||||
"swim", 0x2000);
|
||||
sysbus_init_mmio(sbd, &swimctrl->iomem);
|
||||
memory_region_init(&swimctrl->swim, obj, "swim", 0x2000);
|
||||
memory_region_init_io(&swimctrl->iwm, obj, &swimctrl_iwm_ops, swimctrl,
|
||||
"iwm", 0x2000);
|
||||
memory_region_init_io(&swimctrl->ism, obj, &swimctrl_ism_ops, swimctrl,
|
||||
"ism", 0x2000);
|
||||
sysbus_init_mmio(sbd, &swimctrl->swim);
|
||||
}
|
||||
|
||||
static void sysbus_swim_realize(DeviceState *dev, Error **errp)
|
||||
@@ -423,6 +507,9 @@ static void sysbus_swim_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
|
||||
swimctrl->bus.ctrl = swimctrl;
|
||||
|
||||
/* Default register set is IWM */
|
||||
memory_region_add_subregion(&swimctrl->swim, 0x0, &swimctrl->iwm);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_fdrive = {
|
||||
@@ -442,10 +529,10 @@ static const VMStateDescription vmstate_swim = {
|
||||
VMSTATE_INT32(mode, SWIMCtrl),
|
||||
/* IWM mode */
|
||||
VMSTATE_INT32(iwm_switch, SWIMCtrl),
|
||||
VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8),
|
||||
VMSTATE_UINT8(iwm_data, SWIMCtrl),
|
||||
VMSTATE_UINT8(iwm_mode, SWIMCtrl),
|
||||
VMSTATE_UINT8(iwm_latches, SWIMCtrl),
|
||||
VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 8),
|
||||
/* SWIM mode */
|
||||
VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16),
|
||||
VMSTATE_UINT8(swim_phase, SWIMCtrl),
|
||||
VMSTATE_UINT8(swim_mode, SWIMCtrl),
|
||||
/* Drives */
|
||||
|
||||
@@ -90,3 +90,11 @@ m25p80_read_data(void *s, uint32_t pos, uint8_t v) "[%p] Read data 0x%"PRIx32"=0
|
||||
m25p80_read_sfdp(void *s, uint32_t addr, uint8_t v) "[%p] Read SFDP 0x%"PRIx32"=0x%"PRIx8
|
||||
m25p80_binding(void *s) "[%p] Binding to IF_MTD drive"
|
||||
m25p80_binding_no_bdrv(void *s) "[%p] No BDRV - binding to RAM"
|
||||
|
||||
# swim.c
|
||||
swim_ismctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
|
||||
swim_ismctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
|
||||
swim_iwmctrl_read(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
|
||||
swim_iwmctrl_write(int reg, const char *name, unsigned size, uint64_t value) "reg=%d [%s] size=%u value=0x%"PRIx64
|
||||
swim_switch_to_ism(void) "switch from IWM to ISM mode"
|
||||
swim_switch_to_iwm(void) "switch from ISM to IWM mode"
|
||||
|
||||
@@ -23,6 +23,9 @@ config Q800
|
||||
select ESP
|
||||
select DP8393X
|
||||
select OR_IRQ
|
||||
select DJMEMC
|
||||
select IOSB
|
||||
select ASC
|
||||
|
||||
config M68K_VIRT
|
||||
bool
|
||||
|
||||
+14
-4
@@ -97,6 +97,11 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
|
||||
irq = 6;
|
||||
break;
|
||||
|
||||
case GLUE_IRQ_IN_ASC:
|
||||
/* Route to VIA2 instead, negative edge-triggered */
|
||||
qemu_set_irq(s->irqs[GLUE_IRQ_ASC], !level);
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
@@ -123,6 +128,10 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
|
||||
irq = 6;
|
||||
break;
|
||||
|
||||
case GLUE_IRQ_IN_ASC:
|
||||
irq = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
@@ -166,9 +175,9 @@ static void glue_nmi_release(void *opaque)
|
||||
GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0);
|
||||
}
|
||||
|
||||
static void glue_reset(DeviceState *dev)
|
||||
static void glue_reset_hold(Object *obj)
|
||||
{
|
||||
GLUEState *s = GLUE(dev);
|
||||
GLUEState *s = GLUE(obj);
|
||||
|
||||
s->ipr = 0;
|
||||
s->auxmode = 0;
|
||||
@@ -214,7 +223,7 @@ static void glue_init(Object *obj)
|
||||
qdev_init_gpio_in(dev, GLUE_set_irq, 8);
|
||||
qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1);
|
||||
|
||||
qdev_init_gpio_out(dev, s->irqs, 1);
|
||||
qdev_init_gpio_out(dev, s->irqs, 2);
|
||||
|
||||
/* NMI release timer */
|
||||
s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s);
|
||||
@@ -223,11 +232,12 @@ static void glue_init(Object *obj)
|
||||
static void glue_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
NMIClass *nc = NMI_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_glue;
|
||||
dc->reset = glue_reset;
|
||||
device_class_set_props(dc, glue_properties);
|
||||
rc->phases.hold = glue_reset_hold;
|
||||
nc->nmi_monitor_handler = glue_nmi;
|
||||
}
|
||||
|
||||
|
||||
+137
-1
@@ -40,7 +40,10 @@
|
||||
#include "hw/m68k/q800.h"
|
||||
#include "hw/m68k/q800-glue.h"
|
||||
#include "hw/misc/mac_via.h"
|
||||
#include "hw/misc/djmemc.h"
|
||||
#include "hw/misc/iosb.h"
|
||||
#include "hw/input/adb.h"
|
||||
#include "hw/audio/asc.h"
|
||||
#include "hw/nubus/mac-nubus-bridge.h"
|
||||
#include "hw/display/macfb.h"
|
||||
#include "hw/block/swim.h"
|
||||
@@ -66,9 +69,11 @@
|
||||
#define SONIC_PROM_BASE (IO_BASE + 0x08000)
|
||||
#define SONIC_BASE (IO_BASE + 0x0a000)
|
||||
#define SCC_BASE (IO_BASE + 0x0c020)
|
||||
#define DJMEMC_BASE (IO_BASE + 0x0e000)
|
||||
#define ESP_BASE (IO_BASE + 0x10000)
|
||||
#define ESP_PDMA (IO_BASE + 0x10100)
|
||||
#define ASC_BASE (IO_BASE + 0x14000)
|
||||
#define IOSB_BASE (IO_BASE + 0x18000)
|
||||
#define SWIM_BASE (IO_BASE + 0x1E000)
|
||||
|
||||
#define SONIC_PROM_SIZE 0x1000
|
||||
@@ -82,6 +87,9 @@
|
||||
|
||||
#define MAC_CLOCK 3686418
|
||||
|
||||
/* Size of whole RAM area */
|
||||
#define RAM_SIZE 0x40000000
|
||||
|
||||
/*
|
||||
* Slot 0x9 is reserved for use by the in-built framebuffer whilst only
|
||||
* slots 0xc, 0xd and 0xe physically exist on the Quadra 800
|
||||
@@ -89,6 +97,9 @@
|
||||
#define Q800_NUBUS_SLOTS_AVAILABLE (BIT(0x9) | BIT(0xc) | BIT(0xd) | \
|
||||
BIT(0xe))
|
||||
|
||||
/* Quadra 800 machine ID */
|
||||
#define Q800_MACHINE_ID 0xa55a2bad
|
||||
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
@@ -190,6 +201,48 @@ static const MemoryRegionOps macio_alias_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static uint64_t machine_id_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
return Q800_MACHINE_ID;
|
||||
}
|
||||
|
||||
static void machine_id_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps machine_id_ops = {
|
||||
.read = machine_id_read,
|
||||
.write = machine_id_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static uint64_t ramio_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
static void ramio_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ramio_ops = {
|
||||
.read = ramio_read,
|
||||
.write = ramio_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void q800_machine_init(MachineState *machine)
|
||||
{
|
||||
Q800MachineState *m = Q800_MACHINE(machine);
|
||||
@@ -234,7 +287,11 @@ static void q800_machine_init(MachineState *machine)
|
||||
qemu_register_reset(main_cpu_reset, &m->cpu);
|
||||
|
||||
/* RAM */
|
||||
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
|
||||
memory_region_init_io(&m->ramio, OBJECT(machine), &ramio_ops, &m->ramio,
|
||||
"ram", RAM_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), 0x0, &m->ramio);
|
||||
|
||||
memory_region_add_subregion(&m->ramio, 0, machine->ram);
|
||||
|
||||
/*
|
||||
* Create container for all IO devices
|
||||
@@ -251,12 +308,32 @@ static void q800_machine_init(MachineState *machine)
|
||||
memory_region_add_subregion(get_system_memory(), IO_BASE + IO_SLICE,
|
||||
&m->macio_alias);
|
||||
|
||||
memory_region_init_io(&m->machine_id, NULL, &machine_id_ops, NULL,
|
||||
"Machine ID", 4);
|
||||
memory_region_add_subregion(get_system_memory(), 0x5ffffffc,
|
||||
&m->machine_id);
|
||||
|
||||
/* IRQ Glue */
|
||||
object_initialize_child(OBJECT(machine), "glue", &m->glue, TYPE_GLUE);
|
||||
object_property_set_link(OBJECT(&m->glue), "cpu", OBJECT(&m->cpu),
|
||||
&error_abort);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&m->glue), &error_fatal);
|
||||
|
||||
/* djMEMC memory controller */
|
||||
object_initialize_child(OBJECT(machine), "djmemc", &m->djmemc,
|
||||
TYPE_DJMEMC);
|
||||
sysbus = SYS_BUS_DEVICE(&m->djmemc);
|
||||
sysbus_realize_and_unref(sysbus, &error_fatal);
|
||||
memory_region_add_subregion(&m->macio, DJMEMC_BASE - IO_BASE,
|
||||
sysbus_mmio_get_region(sysbus, 0));
|
||||
|
||||
/* IOSB subsystem */
|
||||
object_initialize_child(OBJECT(machine), "iosb", &m->iosb, TYPE_IOSB);
|
||||
sysbus = SYS_BUS_DEVICE(&m->iosb);
|
||||
sysbus_realize_and_unref(sysbus, &error_fatal);
|
||||
memory_region_add_subregion(&m->macio, IOSB_BASE - IO_BASE,
|
||||
sysbus_mmio_get_region(sysbus, 0));
|
||||
|
||||
/* VIA 1 */
|
||||
object_initialize_child(OBJECT(machine), "via1", &m->via1,
|
||||
TYPE_MOS6522_Q800_VIA1);
|
||||
@@ -374,6 +451,12 @@ static void q800_machine_init(MachineState *machine)
|
||||
memory_region_add_subregion(&m->macio, SCC_BASE - IO_BASE,
|
||||
sysbus_mmio_get_region(sysbus, 0));
|
||||
|
||||
/* Create alias for NetBSD */
|
||||
memory_region_init_alias(&m->escc_alias, OBJECT(machine), "escc-alias",
|
||||
sysbus_mmio_get_region(sysbus, 0), 0, 0x8);
|
||||
memory_region_add_subregion(&m->macio, SCC_BASE - IO_BASE - 0x20,
|
||||
&m->escc_alias);
|
||||
|
||||
/* SCSI */
|
||||
|
||||
object_initialize_child(OBJECT(machine), "esp", &m->esp,
|
||||
@@ -404,6 +487,26 @@ static void q800_machine_init(MachineState *machine)
|
||||
|
||||
scsi_bus_legacy_handle_cmdline(&esp->bus);
|
||||
|
||||
/* Apple Sound Chip */
|
||||
|
||||
object_initialize_child(OBJECT(machine), "asc", &m->asc, TYPE_ASC);
|
||||
qdev_prop_set_uint8(DEVICE(&m->asc), "asctype", m->easc ? ASC_TYPE_EASC
|
||||
: ASC_TYPE_ASC);
|
||||
if (machine->audiodev) {
|
||||
qdev_prop_set_string(DEVICE(&m->asc), "audiodev", machine->audiodev);
|
||||
}
|
||||
sysbus = SYS_BUS_DEVICE(&m->asc);
|
||||
sysbus_realize_and_unref(sysbus, &error_fatal);
|
||||
memory_region_add_subregion(&m->macio, ASC_BASE - IO_BASE,
|
||||
sysbus_mmio_get_region(sysbus, 0));
|
||||
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(DEVICE(&m->glue),
|
||||
GLUE_IRQ_IN_ASC));
|
||||
|
||||
/* Wire ASC IRQ via GLUE for use in classic mode */
|
||||
qdev_connect_gpio_out(DEVICE(&m->glue), GLUE_IRQ_ASC,
|
||||
qdev_get_gpio_in(DEVICE(&m->via2),
|
||||
VIA2_IRQ_ASC_BIT));
|
||||
|
||||
/* SWIM floppy controller */
|
||||
|
||||
object_initialize_child(OBJECT(machine), "swim", &m->swim,
|
||||
@@ -557,6 +660,11 @@ static void q800_machine_init(MachineState *machine)
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
memory_region_add_subregion(get_system_memory(), MACROM_ADDR, &m->rom);
|
||||
|
||||
memory_region_init_alias(&m->rom_alias, NULL, "m68k_mac.rom-alias",
|
||||
&m->rom, 0, MACROM_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), 0x40000000,
|
||||
&m->rom_alias);
|
||||
|
||||
/* Load MacROM binary */
|
||||
if (filename) {
|
||||
bios_size = load_image_targphys(filename, MACROM_ADDR, MACROM_SIZE);
|
||||
@@ -581,6 +689,28 @@ static void q800_machine_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
static bool q800_get_easc(Object *obj, Error **errp)
|
||||
{
|
||||
Q800MachineState *ms = Q800_MACHINE(obj);
|
||||
|
||||
return ms->easc;
|
||||
}
|
||||
|
||||
static void q800_set_easc(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
Q800MachineState *ms = Q800_MACHINE(obj);
|
||||
|
||||
ms->easc = value;
|
||||
}
|
||||
|
||||
static void q800_init(Object *obj)
|
||||
{
|
||||
Q800MachineState *ms = Q800_MACHINE(obj);
|
||||
|
||||
/* Default to EASC */
|
||||
ms->easc = true;
|
||||
}
|
||||
|
||||
static GlobalProperty hw_compat_q800[] = {
|
||||
{ "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on" },
|
||||
{ "scsi-hd", "vendor", " SEAGATE" },
|
||||
@@ -612,12 +742,18 @@ static void q800_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->max_cpus = 1;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->default_ram_id = "m68k_mac.ram";
|
||||
machine_add_audiodev_property(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len);
|
||||
|
||||
object_class_property_add_bool(oc, "easc", q800_get_easc, q800_set_easc);
|
||||
object_class_property_set_description(oc, "easc",
|
||||
"Set to off to use ASC rather than EASC");
|
||||
}
|
||||
|
||||
static const TypeInfo q800_machine_typeinfo = {
|
||||
.name = MACHINE_TYPE_NAME("q800"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_init = q800_init,
|
||||
.instance_size = sizeof(Q800MachineState),
|
||||
.class_init = q800_machine_class_init,
|
||||
};
|
||||
|
||||
@@ -186,4 +186,10 @@ config AXP2XX_PMU
|
||||
bool
|
||||
depends on I2C
|
||||
|
||||
config DJMEMC
|
||||
bool
|
||||
|
||||
config IOSB
|
||||
bool
|
||||
|
||||
source macio/Kconfig
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* djMEMC, macintosh memory and interrupt controller
|
||||
* (Quadra 610/650/800 & Centris 610/650)
|
||||
*
|
||||
* https://mac68k.info/wiki/display/mac68k/djMEMC+Information
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/djmemc.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
#define DJMEMC_INTERLEAVECONF 0x0
|
||||
#define DJMEMC_BANK0CONF 0x4
|
||||
#define DJMEMC_BANK1CONF 0x8
|
||||
#define DJMEMC_BANK2CONF 0xc
|
||||
#define DJMEMC_BANK3CONF 0x10
|
||||
#define DJMEMC_BANK4CONF 0x14
|
||||
#define DJMEMC_BANK5CONF 0x18
|
||||
#define DJMEMC_BANK6CONF 0x1c
|
||||
#define DJMEMC_BANK7CONF 0x20
|
||||
#define DJMEMC_BANK8CONF 0x24
|
||||
#define DJMEMC_BANK9CONF 0x28
|
||||
#define DJMEMC_MEMTOP 0x2c
|
||||
#define DJMEMC_CONFIG 0x30
|
||||
#define DJMEMC_REFRESH 0x34
|
||||
|
||||
|
||||
static uint64_t djmemc_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
DJMEMCState *s = opaque;
|
||||
uint64_t val = 0;
|
||||
|
||||
switch (addr) {
|
||||
case DJMEMC_INTERLEAVECONF:
|
||||
case DJMEMC_BANK0CONF ... DJMEMC_BANK9CONF:
|
||||
case DJMEMC_MEMTOP:
|
||||
case DJMEMC_CONFIG:
|
||||
case DJMEMC_REFRESH:
|
||||
val = s->regs[addr >> 2];
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "djMEMC: unimplemented read addr=0x%"PRIx64
|
||||
" val=0x%"PRIx64 " size=%d\n",
|
||||
addr, val, size);
|
||||
}
|
||||
|
||||
trace_djmemc_read(addr, val, size);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void djmemc_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
DJMEMCState *s = opaque;
|
||||
|
||||
trace_djmemc_write(addr, val, size);
|
||||
|
||||
switch (addr) {
|
||||
case DJMEMC_INTERLEAVECONF:
|
||||
case DJMEMC_BANK0CONF ... DJMEMC_BANK9CONF:
|
||||
case DJMEMC_MEMTOP:
|
||||
case DJMEMC_CONFIG:
|
||||
case DJMEMC_REFRESH:
|
||||
s->regs[addr >> 2] = val;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "djMEMC: unimplemented write addr=0x%"PRIx64
|
||||
" val=0x%"PRIx64 " size=%d\n",
|
||||
addr, val, size);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps djmemc_mmio_ops = {
|
||||
.read = djmemc_read,
|
||||
.write = djmemc_write,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void djmemc_init(Object *obj)
|
||||
{
|
||||
DJMEMCState *s = DJMEMC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->mem_regs, obj, &djmemc_mmio_ops, s, "djMEMC",
|
||||
DJMEMC_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->mem_regs);
|
||||
}
|
||||
|
||||
static void djmemc_reset_hold(Object *obj)
|
||||
{
|
||||
DJMEMCState *s = DJMEMC(obj);
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_djmemc = {
|
||||
.name = "djMEMC",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, DJMEMCState, DJMEMC_NUM_REGS),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void djmemc_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(oc);
|
||||
|
||||
dc->vmsd = &vmstate_djmemc;
|
||||
rc->phases.hold = djmemc_reset_hold;
|
||||
}
|
||||
|
||||
static const TypeInfo djmemc_info_types[] = {
|
||||
{
|
||||
.name = TYPE_DJMEMC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(DJMEMCState),
|
||||
.instance_init = djmemc_init,
|
||||
.class_init = djmemc_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(djmemc_info_types)
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* QEMU IOSB emulation
|
||||
*
|
||||
* Copyright (c) 2019 Laurent Vivier
|
||||
* Copyright (c) 2022 Mark Cave-Ayland
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/iosb.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define IOSB_SIZE 0x2000
|
||||
|
||||
#define IOSB_CONFIG 0x0
|
||||
#define IOSB_CONFIG2 0x100
|
||||
#define IOSB_SONIC_SCSI 0x200
|
||||
#define IOSB_REVISION 0x300
|
||||
#define IOSB_SCSI_RESID 0x400
|
||||
#define IOSB_BRIGHTNESS 0x500
|
||||
#define IOSB_TIMEOUT 0x600
|
||||
|
||||
|
||||
static uint64_t iosb_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
IOSBState *s = IOSB(opaque);
|
||||
uint64_t val = 0;
|
||||
|
||||
switch (addr) {
|
||||
case IOSB_CONFIG:
|
||||
case IOSB_CONFIG2:
|
||||
case IOSB_SONIC_SCSI:
|
||||
case IOSB_REVISION:
|
||||
case IOSB_SCSI_RESID:
|
||||
case IOSB_BRIGHTNESS:
|
||||
case IOSB_TIMEOUT:
|
||||
val = s->regs[addr >> 8];
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "IOSB: unimplemented read addr=0x%"PRIx64
|
||||
" val=0x%"PRIx64 " size=%d\n",
|
||||
addr, val, size);
|
||||
}
|
||||
|
||||
trace_iosb_read(addr, val, size);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void iosb_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
IOSBState *s = IOSB(opaque);
|
||||
|
||||
switch (addr) {
|
||||
case IOSB_CONFIG:
|
||||
case IOSB_CONFIG2:
|
||||
case IOSB_SONIC_SCSI:
|
||||
case IOSB_REVISION:
|
||||
case IOSB_SCSI_RESID:
|
||||
case IOSB_BRIGHTNESS:
|
||||
case IOSB_TIMEOUT:
|
||||
s->regs[addr >> 8] = val;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "IOSB: unimplemented write addr=0x%"PRIx64
|
||||
" val=0x%"PRIx64 " size=%d\n",
|
||||
addr, val, size);
|
||||
}
|
||||
|
||||
trace_iosb_write(addr, val, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps iosb_mmio_ops = {
|
||||
.read = iosb_read,
|
||||
.write = iosb_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void iosb_reset_hold(Object *obj)
|
||||
{
|
||||
IOSBState *s = IOSB(obj);
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
|
||||
/* BCLK 33 MHz */
|
||||
s->regs[IOSB_CONFIG >> 8] = 1;
|
||||
}
|
||||
|
||||
static void iosb_init(Object *obj)
|
||||
{
|
||||
IOSBState *s = IOSB(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->mem_regs, obj, &iosb_mmio_ops, s, "IOSB",
|
||||
IOSB_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->mem_regs);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_iosb = {
|
||||
.name = "IOSB",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, IOSBState, IOSB_REGS),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void iosb_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(oc);
|
||||
|
||||
dc->vmsd = &vmstate_iosb;
|
||||
rc->phases.hold = iosb_reset_hold;
|
||||
}
|
||||
|
||||
static const TypeInfo iosb_info_types[] = {
|
||||
{
|
||||
.name = TYPE_IOSB,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IOSBState),
|
||||
.instance_init = iosb_init,
|
||||
.class_init = iosb_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(iosb_info_types)
|
||||
+233
-1
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
@@ -114,6 +115,9 @@
|
||||
#define VIA1A_CPUID1 0x04 /* CPU id bit 0 on RBV, others */
|
||||
#define VIA1A_CPUID2 0x10 /* CPU id bit 0 on RBV, others */
|
||||
#define VIA1A_CPUID3 0x40 /* CPU id bit 0 on RBV, others */
|
||||
#define VIA1A_CPUID_MASK (VIA1A_CPUID0 | VIA1A_CPUID1 | \
|
||||
VIA1A_CPUID2 | VIA1A_CPUID3)
|
||||
#define VIA1A_CPUID_Q800 (VIA1A_CPUID0 | VIA1A_CPUID2)
|
||||
|
||||
/*
|
||||
* Info on VIA1B is from Macintosh Family Hardware & MkLinux.
|
||||
@@ -698,6 +702,12 @@ static void adb_via_send(MOS6522Q800VIA1State *v1s, int state, uint8_t data)
|
||||
break;
|
||||
|
||||
case ADB_STATE_IDLE:
|
||||
ms->b |= VIA1B_vADBInt;
|
||||
adb_autopoll_unblock(adb_bus);
|
||||
|
||||
trace_via1_adb_send("IDLE", data,
|
||||
(ms->b & VIA1B_vADBInt) ? "+" : "-");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -865,6 +875,159 @@ static void via1_auxmode_update(MOS6522Q800VIA1State *v1s)
|
||||
if (irq != oldirq) {
|
||||
trace_via1_auxmode(irq);
|
||||
qemu_set_irq(v1s->auxmode_irq, irq);
|
||||
|
||||
/*
|
||||
* Clear the ADB interrupt. MacOS can leave VIA1B_vADBInt asserted
|
||||
* (low) if a poll sequence doesn't complete before NetBSD disables
|
||||
* interrupts upon boot. Fortunately NetBSD switches to the so-called
|
||||
* "A/UX" interrupt mode after it initialises, so we can use this as
|
||||
* a convenient place to clear the ADB interrupt for now.
|
||||
*/
|
||||
s->b |= VIA1B_vADBInt;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses and real values for TimeDBRA/TimeSCCB to allow timer calibration
|
||||
* to succeed (NOTE: both values have been multiplied by 3 to cope with the
|
||||
* speed of QEMU execution on a modern host
|
||||
*/
|
||||
#define MACOS_TIMEDBRA 0xd00
|
||||
#define MACOS_TIMESCCB 0xd02
|
||||
|
||||
#define MACOS_TIMEDBRA_VALUE (0x2a00 * 3)
|
||||
#define MACOS_TIMESCCB_VALUE (0x079d * 3)
|
||||
|
||||
static bool via1_is_toolbox_timer_calibrated(void)
|
||||
{
|
||||
/*
|
||||
* Indicate whether the MacOS toolbox has been calibrated by checking
|
||||
* for the value of our magic constants
|
||||
*/
|
||||
uint16_t timedbra = lduw_be_phys(&address_space_memory, MACOS_TIMEDBRA);
|
||||
uint16_t timesccdb = lduw_be_phys(&address_space_memory, MACOS_TIMESCCB);
|
||||
|
||||
return (timedbra == MACOS_TIMEDBRA_VALUE &&
|
||||
timesccdb == MACOS_TIMESCCB_VALUE);
|
||||
}
|
||||
|
||||
static void via1_timer_calibration_hack(MOS6522Q800VIA1State *v1s, int addr,
|
||||
uint64_t val, int size)
|
||||
{
|
||||
/*
|
||||
* Work around timer calibration to ensure we that we have non-zero and
|
||||
* known good values for TIMEDRBA and TIMESCCDB.
|
||||
*
|
||||
* This works by attempting to detect the reset and calibration sequence
|
||||
* of writes to VIA1
|
||||
*/
|
||||
int old_timer_hack_state = v1s->timer_hack_state;
|
||||
|
||||
switch (v1s->timer_hack_state) {
|
||||
case 0:
|
||||
if (addr == VIA_REG_PCR && val == 0x22) {
|
||||
/* VIA_REG_PCR: configure VIA1 edge triggering */
|
||||
v1s->timer_hack_state = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (addr == VIA_REG_T2CL && val == 0xc) {
|
||||
/* VIA_REG_T2CL: low byte of 1ms counter */
|
||||
if (!via1_is_toolbox_timer_calibrated()) {
|
||||
v1s->timer_hack_state = 2;
|
||||
} else {
|
||||
v1s->timer_hack_state = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (addr == VIA_REG_T2CH && val == 0x3) {
|
||||
/*
|
||||
* VIA_REG_T2CH: high byte of 1ms counter (very likely at the
|
||||
* start of SETUPTIMEK)
|
||||
*/
|
||||
if (!via1_is_toolbox_timer_calibrated()) {
|
||||
v1s->timer_hack_state = 3;
|
||||
} else {
|
||||
v1s->timer_hack_state = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (addr == VIA_REG_IER && val == 0x20) {
|
||||
/*
|
||||
* VIA_REG_IER: update at end of SETUPTIMEK
|
||||
*
|
||||
* Timer calibration has finished: unfortunately the values in
|
||||
* TIMEDBRA (0xd00) and TIMESCCDB (0xd02) are so far out they
|
||||
* cause divide by zero errors.
|
||||
*
|
||||
* Update them with values obtained from a real Q800 but with
|
||||
* a x3 scaling factor which seems to work well
|
||||
*/
|
||||
stw_be_phys(&address_space_memory, MACOS_TIMEDBRA,
|
||||
MACOS_TIMEDBRA_VALUE);
|
||||
stw_be_phys(&address_space_memory, MACOS_TIMESCCB,
|
||||
MACOS_TIMESCCB_VALUE);
|
||||
|
||||
v1s->timer_hack_state = 4;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/*
|
||||
* This is the normal post-calibration timer state: we should
|
||||
* generally remain here unless we detect the A/UX calibration
|
||||
* loop, or a write to VIA_REG_PCR suggesting a reset
|
||||
*/
|
||||
if (addr == VIA_REG_PCR && val == 0x22) {
|
||||
/* Looks like there has been a reset? */
|
||||
v1s->timer_hack_state = 1;
|
||||
}
|
||||
|
||||
if (addr == VIA_REG_T2CL && val == 0xf0) {
|
||||
/* VIA_REG_T2CL: low byte of counter (A/UX) */
|
||||
v1s->timer_hack_state = 5;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (addr == VIA_REG_T2CH && val == 0x3c) {
|
||||
/*
|
||||
* VIA_REG_T2CH: high byte of counter (A/UX). We are now extremely
|
||||
* likely to be in the A/UX timer calibration routine, so move to
|
||||
* the next state where we enable the calibration hack.
|
||||
*/
|
||||
v1s->timer_hack_state = 6;
|
||||
} else if ((addr == VIA_REG_IER && val == 0x20) ||
|
||||
addr == VIA_REG_T2CH) {
|
||||
/* We're doing something else with the timer, not calibration */
|
||||
v1s->timer_hack_state = 0;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if ((addr == VIA_REG_IER && val == 0x20) || addr == VIA_REG_T2CH) {
|
||||
/* End of A/UX timer calibration routine, or another write */
|
||||
v1s->timer_hack_state = 7;
|
||||
} else {
|
||||
v1s->timer_hack_state = 0;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/*
|
||||
* This is the normal post-calibration timer state once both the
|
||||
* MacOS toolbox and A/UX have been calibrated, until we see a write
|
||||
* to VIA_REG_PCR to suggest a reset
|
||||
*/
|
||||
if (addr == VIA_REG_PCR && val == 0x22) {
|
||||
/* Looks like there has been a reset? */
|
||||
v1s->timer_hack_state = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (old_timer_hack_state != v1s->timer_hack_state) {
|
||||
trace_via1_timer_hack_state(v1s->timer_hack_state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,9 +1035,36 @@ static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque);
|
||||
MOS6522State *ms = MOS6522(s);
|
||||
uint64_t ret;
|
||||
int64_t now;
|
||||
|
||||
addr = (addr >> 9) & 0xf;
|
||||
return mos6522_read(ms, addr, size);
|
||||
ret = mos6522_read(ms, addr, size);
|
||||
switch (addr) {
|
||||
case VIA_REG_A:
|
||||
case VIA_REG_ANH:
|
||||
/* Quadra 800 Id */
|
||||
ret = (ret & ~VIA1A_CPUID_MASK) | VIA1A_CPUID_Q800;
|
||||
break;
|
||||
case VIA_REG_T2CH:
|
||||
if (s->timer_hack_state == 6) {
|
||||
/*
|
||||
* The A/UX timer calibration loop runs continuously until 2
|
||||
* consecutive iterations differ by at least 0x492 timer ticks.
|
||||
* Modern hosts execute the timer calibration loop so fast that
|
||||
* this situation never occurs causing a hang on boot. Use a
|
||||
* similar method to Shoebill which is to randomly add 0x500 to
|
||||
* the T2 counter value during calibration to enable it to
|
||||
* eventually succeed.
|
||||
*/
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (now & 1) {
|
||||
ret += 0x5;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
@@ -882,8 +1072,13 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
{
|
||||
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque);
|
||||
MOS6522State *ms = MOS6522(v1s);
|
||||
int oldstate, state;
|
||||
int oldsr = ms->sr;
|
||||
|
||||
addr = (addr >> 9) & 0xf;
|
||||
|
||||
via1_timer_calibration_hack(v1s, addr, val, size);
|
||||
|
||||
mos6522_write(ms, addr, val, size);
|
||||
|
||||
switch (addr) {
|
||||
@@ -894,6 +1089,38 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
|
||||
v1s->last_b = ms->b;
|
||||
break;
|
||||
|
||||
case VIA_REG_SR:
|
||||
{
|
||||
/*
|
||||
* NetBSD assumes it can send its first ADB command after sending
|
||||
* the ADB_BUSRESET command in ADB_STATE_NEW without changing the
|
||||
* state back to ADB_STATE_IDLE first as detailed in the ADB
|
||||
* protocol.
|
||||
*
|
||||
* Add a workaround to detect this condition at the start of ADB
|
||||
* enumeration and send the next command written to SR after a
|
||||
* ADB_BUSRESET onto the bus regardless, even if we don't detect a
|
||||
* state transition to ADB_STATE_NEW.
|
||||
*
|
||||
* Note that in my tests the NetBSD state machine takes one ADB
|
||||
* operation to recover which means the probe for an ADB device at
|
||||
* address 1 always fails. However since the first device is at
|
||||
* address 2 then this will work fine, without having to come up
|
||||
* with a more complicated and invasive solution.
|
||||
*/
|
||||
oldstate = (v1s->last_b & VIA1B_vADB_StateMask) >>
|
||||
VIA1B_vADB_StateShift;
|
||||
state = (ms->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift;
|
||||
|
||||
if (oldstate == ADB_STATE_NEW && state == ADB_STATE_NEW &&
|
||||
(ms->acr & VIA1ACR_vShiftOut) &&
|
||||
oldsr == 0 /* ADB_BUSRESET */) {
|
||||
trace_via1_adb_netbsd_enum_hack();
|
||||
adb_via_send(v1s, state, ms->sr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,6 +1223,9 @@ static void mos6522_q800_via1_reset_hold(Object *obj)
|
||||
adb_set_autopoll_enabled(adb_bus, true);
|
||||
v1s->cmd = REG_EMPTY;
|
||||
v1s->alt = REG_EMPTY;
|
||||
|
||||
/* Timer calibration hack */
|
||||
v1s->timer_hack_state = 0;
|
||||
}
|
||||
|
||||
static void mos6522_q800_via1_realize(DeviceState *dev, Error **errp)
|
||||
@@ -1088,6 +1318,8 @@ static const VMStateDescription vmstate_q800_via1 = {
|
||||
VMSTATE_INT64(next_second, MOS6522Q800VIA1State),
|
||||
VMSTATE_TIMER_PTR(sixty_hz_timer, MOS6522Q800VIA1State),
|
||||
VMSTATE_INT64(next_sixty_hz, MOS6522Q800VIA1State),
|
||||
/* Timer hack */
|
||||
VMSTATE_INT32(timer_hack_state, MOS6522Q800VIA1State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,6 +20,8 @@ system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_ras.c'))
|
||||
|
||||
# Mac devices
|
||||
system_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c'))
|
||||
system_ss.add(when: 'CONFIG_DJMEMC', if_true: files('djmemc.c'))
|
||||
system_ss.add(when: 'CONFIG_IOSB', if_true: files('iosb.c'))
|
||||
|
||||
# virt devices
|
||||
system_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c'))
|
||||
|
||||
@@ -271,7 +271,9 @@ via1_rtc_cmd_pram_sect_write(int sector, int offset, int addr, int value) "secto
|
||||
via1_adb_send(const char *state, uint8_t data, const char *vadbint) "state %s data=0x%02x vADBInt=%s"
|
||||
via1_adb_receive(const char *state, uint8_t data, const char *vadbint, int status, int index, int size) "state %s data=0x%02x vADBInt=%s status=0x%x index=%d size=%d"
|
||||
via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size) "data=0x%02x vADBInt=%s status=0x%x index=%d size=%d"
|
||||
via1_adb_netbsd_enum_hack(void) "using NetBSD enum hack"
|
||||
via1_auxmode(int mode) "setting auxmode to %d"
|
||||
via1_timer_hack_state(int state) "setting timer_hack_state to %d"
|
||||
|
||||
# grlib_ahb_apb_pnp.c
|
||||
grlib_ahb_pnp_read(uint64_t addr, unsigned size, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" size:%u data:0x%08x"
|
||||
@@ -301,3 +303,11 @@ virt_ctrl_instance_init(void *dev) "ctrl: %p"
|
||||
lasi_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d"
|
||||
lasi_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x"
|
||||
lasi_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x"
|
||||
|
||||
# djmemc.c
|
||||
djmemc_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
|
||||
djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
|
||||
|
||||
# iosb.c
|
||||
iosb_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
|
||||
iosb_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* QEMU Apple Sound Chip emulation
|
||||
*
|
||||
* Apple Sound Chip (ASC) 344S0063
|
||||
* Enhanced Apple Sound Chip (EASC) 343S1063
|
||||
*
|
||||
* Copyright (c) 2012-2018 Laurent Vivier <laurent@vivier.eu>
|
||||
* Copyright (c) 2022 Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_AUDIO_ASC_H
|
||||
#define HW_AUDIO_ASC_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "audio/audio.h"
|
||||
|
||||
#define ASC_FREQ 22257
|
||||
|
||||
enum {
|
||||
ASC_TYPE_ASC = 0, /* original discrete Apple Sound Chip */
|
||||
ASC_TYPE_EASC = 1 /* discrete Enhanced Apple Sound Chip */
|
||||
};
|
||||
|
||||
#define ASC_FIFO_OFFSET 0x0
|
||||
#define ASC_FIFO_SIZE 0x400
|
||||
|
||||
#define ASC_REG_OFFSET 0x800
|
||||
#define ASC_REG_SIZE 0x60
|
||||
|
||||
#define ASC_EXTREG_OFFSET 0xf00
|
||||
#define ASC_EXTREG_SIZE 0x20
|
||||
|
||||
typedef struct ASCFIFOState {
|
||||
int index;
|
||||
|
||||
MemoryRegion mem_fifo;
|
||||
uint8_t fifo[ASC_FIFO_SIZE];
|
||||
uint8_t int_status;
|
||||
|
||||
int cnt;
|
||||
int wptr;
|
||||
int rptr;
|
||||
|
||||
MemoryRegion mem_extregs;
|
||||
uint8_t extregs[ASC_EXTREG_SIZE];
|
||||
|
||||
int xa_cnt;
|
||||
uint8_t xa_val;
|
||||
uint8_t xa_flags;
|
||||
int16_t xa_last[2];
|
||||
} ASCFIFOState;
|
||||
|
||||
struct ASCState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
uint8_t type;
|
||||
MemoryRegion asc;
|
||||
MemoryRegion mem_fifo;
|
||||
MemoryRegion mem_regs;
|
||||
MemoryRegion mem_extregs;
|
||||
|
||||
QEMUSoundCard card;
|
||||
SWVoiceOut *voice;
|
||||
uint8_t *mixbuf;
|
||||
int samples;
|
||||
int shift;
|
||||
|
||||
uint8_t *silentbuf;
|
||||
|
||||
/* Time when we were last able to generate samples */
|
||||
int64_t fifo_empty_ns;
|
||||
|
||||
qemu_irq irq;
|
||||
|
||||
ASCFIFOState fifos[2];
|
||||
|
||||
uint8_t regs[ASC_REG_SIZE];
|
||||
};
|
||||
|
||||
#define TYPE_ASC "apple-sound-chip"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ASCState, ASC)
|
||||
|
||||
#endif
|
||||
+9
-12
@@ -43,25 +43,22 @@ typedef struct FDrive {
|
||||
} FDrive;
|
||||
|
||||
struct SWIMCtrl {
|
||||
MemoryRegion iomem;
|
||||
MemoryRegion swim;
|
||||
MemoryRegion iwm;
|
||||
MemoryRegion ism;
|
||||
FDrive drives[SWIM_MAX_FD];
|
||||
int mode;
|
||||
/* IWM mode */
|
||||
int iwm_switch;
|
||||
uint16_t regs[8];
|
||||
#define IWM_PH0 0
|
||||
#define IWM_PH1 1
|
||||
#define IWM_PH2 2
|
||||
#define IWM_PH3 3
|
||||
#define IWM_MTR 4
|
||||
#define IWM_DRIVE 5
|
||||
#define IWM_Q6 6
|
||||
#define IWM_Q7 7
|
||||
uint8_t iwm_data;
|
||||
uint8_t iwm_mode;
|
||||
uint8_t iwm_latches;
|
||||
uint8_t iwmregs[8];
|
||||
/* SWIM mode */
|
||||
uint8_t ismregs[16];
|
||||
uint8_t swim_phase;
|
||||
uint8_t swim_mode;
|
||||
uint8_t swim_status;
|
||||
uint8_t pram[16];
|
||||
uint8_t pram_idx;
|
||||
SWIMBus bus;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ struct GLUEState {
|
||||
M68kCPU *cpu;
|
||||
uint8_t ipr;
|
||||
uint8_t auxmode;
|
||||
qemu_irq irqs[1];
|
||||
qemu_irq irqs[2];
|
||||
QEMUTimer *nmi_release;
|
||||
};
|
||||
|
||||
@@ -44,7 +44,9 @@ struct GLUEState {
|
||||
#define GLUE_IRQ_IN_SONIC 2
|
||||
#define GLUE_IRQ_IN_ESCC 3
|
||||
#define GLUE_IRQ_IN_NMI 4
|
||||
#define GLUE_IRQ_IN_ASC 5
|
||||
|
||||
#define GLUE_IRQ_NUBUS_9 0
|
||||
#define GLUE_IRQ_ASC 1
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#include "hw/block/swim.h"
|
||||
#include "hw/nubus/mac-nubus-bridge.h"
|
||||
#include "hw/display/macfb.h"
|
||||
#include "hw/misc/djmemc.h"
|
||||
#include "hw/misc/iosb.h"
|
||||
#include "hw/audio/asc.h"
|
||||
|
||||
/*
|
||||
* The main Q800 machine
|
||||
@@ -44,8 +47,10 @@
|
||||
struct Q800MachineState {
|
||||
MachineState parent_obj;
|
||||
|
||||
bool easc;
|
||||
M68kCPU cpu;
|
||||
MemoryRegion rom;
|
||||
MemoryRegion rom_alias;
|
||||
GLUEState glue;
|
||||
MOS6522Q800VIA1State via1;
|
||||
MOS6522Q800VIA2State via2;
|
||||
@@ -56,8 +61,14 @@ struct Q800MachineState {
|
||||
Swim swim;
|
||||
MacNubusBridge mac_nubus_bridge;
|
||||
MacfbNubusState macfb;
|
||||
DJMEMCState djmemc;
|
||||
IOSBState iosb;
|
||||
ASCState asc;
|
||||
MemoryRegion ramio;
|
||||
MemoryRegion macio;
|
||||
MemoryRegion macio_alias;
|
||||
MemoryRegion machine_id;
|
||||
MemoryRegion escc_alias;
|
||||
};
|
||||
|
||||
#define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user