mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/vivier/tags/q800-branch-pull-request' into staging
Add Macintosh Quadra 800 machine in hw/m68k # gpg: Signature made Mon 28 Oct 2019 18:14:25 GMT # 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-branch-pull-request: BootLinuxConsoleTest: Test the Quadra 800 hw/m68k: define Macintosh Quadra 800 hw/m68k: add a dummy SWIM floppy controller hw/m68k: add Nubus macfb video card hw/m68k: add Nubus support hw/m68k: implement ADB bus support for via hw/m68k: add VIA support dp8393x: manage big endian bus esp: add pseudo-DMA as used by Macintosh esp: move get_cmd() post-DMA code to get_cmd_cb() esp: move handle_ti_cmd() cleanup code to esp_do_dma(). Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+14
@@ -917,6 +917,20 @@ F: hw/m68k/next-*.c
|
||||
F: hw/display/next-fb.c
|
||||
F: include/hw/m68k/next-cube.h
|
||||
|
||||
q800
|
||||
M: Laurent Vivier <laurent@vivier.eu>
|
||||
S: Maintained
|
||||
F: hw/m68k/q800.c
|
||||
F: hw/misc/mac_via.c
|
||||
F: hw/nubus/*
|
||||
F: hw/display/macfb.c
|
||||
F: hw/block/swim.c
|
||||
F: hw/m68k/bootinfo.h
|
||||
F: include/hw/misc/mac_via.h
|
||||
F: include/hw/nubus/*
|
||||
F: include/hw/display/macfb.h
|
||||
F: include/hw/block/swim.h
|
||||
|
||||
MicroBlaze Machines
|
||||
-------------------
|
||||
petalogix_s3adsp1800
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
int graphic_width = 1024;
|
||||
int graphic_height = 768;
|
||||
int graphic_depth = 8;
|
||||
#elif defined(TARGET_M68K)
|
||||
int graphic_width = 800;
|
||||
int graphic_height = 600;
|
||||
int graphic_depth = 8;
|
||||
#else
|
||||
int graphic_width = 800;
|
||||
int graphic_height = 600;
|
||||
|
||||
@@ -7,3 +7,4 @@ CONFIG_SEMIHOSTING=y
|
||||
CONFIG_AN5206=y
|
||||
CONFIG_MCF5208=y
|
||||
CONFIG_NEXTCUBE=y
|
||||
CONFIG_Q800=y
|
||||
|
||||
@@ -21,6 +21,7 @@ source isa/Kconfig
|
||||
source mem/Kconfig
|
||||
source misc/Kconfig
|
||||
source net/Kconfig
|
||||
source nubus/Kconfig
|
||||
source nvram/Kconfig
|
||||
source pci-bridge/Kconfig
|
||||
source pci-host/Kconfig
|
||||
|
||||
@@ -38,6 +38,7 @@ devices-dirs-y += virtio/
|
||||
devices-dirs-y += watchdog/
|
||||
devices-dirs-y += xen/
|
||||
devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
|
||||
devices-dirs-$(CONFIG_NUBUS) += nubus/
|
||||
devices-dirs-y += semihosting/
|
||||
devices-dirs-y += smbios/
|
||||
endif
|
||||
|
||||
@@ -37,3 +37,6 @@ config VHOST_USER_BLK
|
||||
# Only PCI devices are provided for now
|
||||
default y if VIRTIO_PCI
|
||||
depends on VIRTIO && VHOST_USER && LINUX
|
||||
|
||||
config SWIM
|
||||
bool
|
||||
|
||||
@@ -8,6 +8,7 @@ common-obj-$(CONFIG_XEN) += xen-block.o
|
||||
common-obj-$(CONFIG_ECC) += ecc.o
|
||||
common-obj-$(CONFIG_ONENAND) += onenand.o
|
||||
common-obj-$(CONFIG_NVME_PCI) += nvme.o
|
||||
common-obj-$(CONFIG_SWIM) += swim.o
|
||||
|
||||
obj-$(CONFIG_SH4) += tc58128.o
|
||||
|
||||
|
||||
+489
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* QEMU Macintosh floppy disk controller emulator (SWIM)
|
||||
*
|
||||
* Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Only the basic support: it allows to switch from IWM (Integrated WOZ
|
||||
* Machine) mode to the SWIM mode and makes the linux driver happy.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "hw/block/swim.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
||||
/* 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
|
||||
|
||||
/* SWIM registers */
|
||||
|
||||
#define SWIM_WRITE_DATA 0
|
||||
#define SWIM_WRITE_MARK 1
|
||||
#define SWIM_WRITE_CRC 2
|
||||
#define SWIM_WRITE_PARAMETER 3
|
||||
#define SWIM_WRITE_PHASE 4
|
||||
#define SWIM_WRITE_SETUP 5
|
||||
#define SWIM_WRITE_MODE0 6
|
||||
#define SWIM_WRITE_MODE1 7
|
||||
|
||||
#define SWIM_READ_DATA 8
|
||||
#define SWIM_READ_MARK 9
|
||||
#define SWIM_READ_ERROR 10
|
||||
#define SWIM_READ_PARAMETER 11
|
||||
#define SWIM_READ_PHASE 12
|
||||
#define SWIM_READ_SETUP 13
|
||||
#define SWIM_READ_STATUS 14
|
||||
#define SWIM_READ_HANDSHAKE 15
|
||||
|
||||
#define REG_SHIFT 9
|
||||
|
||||
#define SWIM_MODE_IWM 0
|
||||
#define SWIM_MODE_SWIM 1
|
||||
|
||||
/* bits in phase register */
|
||||
|
||||
#define SWIM_SEEK_NEGATIVE 0x074
|
||||
#define SWIM_STEP 0x071
|
||||
#define SWIM_MOTOR_ON 0x072
|
||||
#define SWIM_MOTOR_OFF 0x076
|
||||
#define SWIM_INDEX 0x073
|
||||
#define SWIM_EJECT 0x077
|
||||
#define SWIM_SETMFM 0x171
|
||||
#define SWIM_SETGCR 0x175
|
||||
#define SWIM_RELAX 0x033
|
||||
#define SWIM_LSTRB 0x008
|
||||
#define SWIM_CA_MASK 0x077
|
||||
|
||||
/* Select values for swim_select and swim_readbit */
|
||||
|
||||
#define SWIM_READ_DATA_0 0x074
|
||||
#define SWIM_TWOMEG_DRIVE 0x075
|
||||
#define SWIM_SINGLE_SIDED 0x076
|
||||
#define SWIM_DRIVE_PRESENT 0x077
|
||||
#define SWIM_DISK_IN 0x170
|
||||
#define SWIM_WRITE_PROT 0x171
|
||||
#define SWIM_TRACK_ZERO 0x172
|
||||
#define SWIM_TACHO 0x173
|
||||
#define SWIM_READ_DATA_1 0x174
|
||||
#define SWIM_MFM_MODE 0x175
|
||||
#define SWIM_SEEK_COMPLETE 0x176
|
||||
#define SWIM_ONEMEG_MEDIA 0x177
|
||||
|
||||
/* Bits in handshake register */
|
||||
|
||||
#define SWIM_MARK_BYTE 0x01
|
||||
#define SWIM_CRC_ZERO 0x02
|
||||
#define SWIM_RDDATA 0x04
|
||||
#define SWIM_SENSE 0x08
|
||||
#define SWIM_MOTEN 0x10
|
||||
#define SWIM_ERROR 0x20
|
||||
#define SWIM_DAT2BYTE 0x40
|
||||
#define SWIM_DAT1BYTE 0x80
|
||||
|
||||
/* bits in setup register */
|
||||
|
||||
#define SWIM_S_INV_WDATA 0x01
|
||||
#define SWIM_S_3_5_SELECT 0x02
|
||||
#define SWIM_S_GCR 0x04
|
||||
#define SWIM_S_FCLK_DIV2 0x08
|
||||
#define SWIM_S_ERROR_CORR 0x10
|
||||
#define SWIM_S_IBM_DRIVE 0x20
|
||||
#define SWIM_S_GCR_WRITE 0x40
|
||||
#define SWIM_S_TIMEOUT 0x80
|
||||
|
||||
/* bits in mode register */
|
||||
|
||||
#define SWIM_CLFIFO 0x01
|
||||
#define SWIM_ENBL1 0x02
|
||||
#define SWIM_ENBL2 0x04
|
||||
#define SWIM_ACTION 0x08
|
||||
#define SWIM_WRITE_MODE 0x10
|
||||
#define SWIM_HEDSEL 0x20
|
||||
#define SWIM_MOTON 0x80
|
||||
|
||||
static void fd_recalibrate(FDrive *drive)
|
||||
{
|
||||
}
|
||||
|
||||
static void swim_change_cb(void *opaque, bool load, Error **errp)
|
||||
{
|
||||
FDrive *drive = opaque;
|
||||
|
||||
if (!load) {
|
||||
blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
|
||||
} else {
|
||||
if (!blkconf_apply_backend_options(drive->conf,
|
||||
blk_is_read_only(drive->blk), false,
|
||||
errp)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const BlockDevOps swim_block_ops = {
|
||||
.change_media_cb = swim_change_cb,
|
||||
};
|
||||
|
||||
static Property swim_drive_properties[] = {
|
||||
DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
|
||||
DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void swim_drive_realize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
SWIMDrive *dev = SWIM_DRIVE(qdev);
|
||||
SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
|
||||
FDrive *drive;
|
||||
int ret;
|
||||
|
||||
if (dev->unit == -1) {
|
||||
for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
|
||||
drive = &bus->ctrl->drives[dev->unit];
|
||||
if (!drive->blk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->unit >= SWIM_MAX_FD) {
|
||||
error_setg(errp, "Can't create floppy unit %d, bus supports "
|
||||
"only %d units", dev->unit, SWIM_MAX_FD);
|
||||
return;
|
||||
}
|
||||
|
||||
drive = &bus->ctrl->drives[dev->unit];
|
||||
if (drive->blk) {
|
||||
error_setg(errp, "Floppy unit %d is in use", dev->unit);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->conf.blk) {
|
||||
/* Anonymous BlockBackend for an empty drive */
|
||||
dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
|
||||
ret = blk_attach_dev(dev->conf.blk, qdev);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
blkconf_blocksizes(&dev->conf);
|
||||
if (dev->conf.logical_block_size != 512 ||
|
||||
dev->conf.physical_block_size != 512)
|
||||
{
|
||||
error_setg(errp, "Physical and logical block size must "
|
||||
"be 512 for floppy");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* rerror/werror aren't supported by fdc and therefore not even registered
|
||||
* with qdev. So set the defaults manually before they are used in
|
||||
* blkconf_apply_backend_options().
|
||||
*/
|
||||
dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
|
||||
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
|
||||
|
||||
if (!blkconf_apply_backend_options(&dev->conf,
|
||||
blk_is_read_only(dev->conf.blk),
|
||||
false, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
|
||||
* for empty drives.
|
||||
*/
|
||||
if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
|
||||
blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
|
||||
error_setg(errp, "fdc doesn't support drive option werror");
|
||||
return;
|
||||
}
|
||||
if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
|
||||
error_setg(errp, "fdc doesn't support drive option rerror");
|
||||
return;
|
||||
}
|
||||
|
||||
drive->conf = &dev->conf;
|
||||
drive->blk = dev->conf.blk;
|
||||
drive->swimctrl = bus->ctrl;
|
||||
|
||||
blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
|
||||
}
|
||||
|
||||
static void swim_drive_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *k = DEVICE_CLASS(klass);
|
||||
k->realize = swim_drive_realize;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
|
||||
k->bus_type = TYPE_SWIM_BUS;
|
||||
k->props = swim_drive_properties;
|
||||
k->desc = "virtual SWIM drive";
|
||||
}
|
||||
|
||||
static const TypeInfo swim_drive_info = {
|
||||
.name = TYPE_SWIM_DRIVE,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(SWIMDrive),
|
||||
.class_init = swim_drive_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo swim_bus_info = {
|
||||
.name = TYPE_SWIM_BUS,
|
||||
.parent = TYPE_BUS,
|
||||
.instance_size = sizeof(SWIMBus),
|
||||
};
|
||||
|
||||
static void iwmctrl_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;
|
||||
|
||||
switch (reg) {
|
||||
case SWIM_WRITE_PHASE:
|
||||
swimctrl->swim_phase = value;
|
||||
break;
|
||||
case SWIM_WRITE_MODE0:
|
||||
swimctrl->swim_mode &= ~value;
|
||||
break;
|
||||
case SWIM_WRITE_MODE1:
|
||||
swimctrl->swim_mode |= value;
|
||||
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)
|
||||
{
|
||||
SWIMCtrl *swimctrl = opaque;
|
||||
uint32_t value = 0;
|
||||
|
||||
if (swimctrl->mode == SWIM_MODE_IWM) {
|
||||
return iwmctrl_read(opaque, reg, size);
|
||||
}
|
||||
|
||||
reg >>= REG_SHIFT;
|
||||
|
||||
switch (reg) {
|
||||
case SWIM_READ_PHASE:
|
||||
value = swimctrl->swim_phase;
|
||||
break;
|
||||
case SWIM_READ_HANDSHAKE:
|
||||
if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
|
||||
/* always answer "no drive present" */
|
||||
value = SWIM_SENSE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps swimctrl_mem_ops = {
|
||||
.write = swimctrl_write,
|
||||
.read = swimctrl_read,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void sysbus_swim_reset(DeviceState *d)
|
||||
{
|
||||
SWIM *sys = SWIM(d);
|
||||
SWIMCtrl *ctrl = &sys->ctrl;
|
||||
int i;
|
||||
|
||||
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;
|
||||
ctrl->swim_phase = 0;
|
||||
ctrl->swim_mode = 0;
|
||||
for (i = 0; i < SWIM_MAX_FD; i++) {
|
||||
fd_recalibrate(&ctrl->drives[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void sysbus_swim_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(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);
|
||||
}
|
||||
|
||||
static void sysbus_swim_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SWIM *sys = SWIM(dev);
|
||||
SWIMCtrl *swimctrl = &sys->ctrl;
|
||||
|
||||
qbus_create_inplace(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev,
|
||||
NULL);
|
||||
swimctrl->bus.ctrl = swimctrl;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_fdrive = {
|
||||
.name = "fdrive",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_swim = {
|
||||
.name = "swim",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
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),
|
||||
/* SWIM mode */
|
||||
VMSTATE_UINT8(swim_phase, SWIMCtrl),
|
||||
VMSTATE_UINT8(swim_mode, SWIMCtrl),
|
||||
/* Drives */
|
||||
VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
|
||||
vmstate_fdrive, FDrive),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_sysbus_swim = {
|
||||
.name = "SWIM",
|
||||
.version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(ctrl, SWIM, 0, vmstate_swim, SWIMCtrl),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void sysbus_swim_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = sysbus_swim_realize;
|
||||
dc->reset = sysbus_swim_reset;
|
||||
dc->vmsd = &vmstate_sysbus_swim;
|
||||
}
|
||||
|
||||
static const TypeInfo sysbus_swim_info = {
|
||||
.name = TYPE_SWIM,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SWIM),
|
||||
.instance_init = sysbus_swim_init,
|
||||
.class_init = sysbus_swim_class_init,
|
||||
};
|
||||
|
||||
static void swim_register_types(void)
|
||||
{
|
||||
type_register_static(&sysbus_swim_info);
|
||||
type_register_static(&swim_bus_info);
|
||||
type_register_static(&swim_drive_info);
|
||||
}
|
||||
|
||||
type_init(swim_register_types)
|
||||
@@ -132,3 +132,8 @@ config ATI_VGA
|
||||
select VGA
|
||||
select BITBANG_I2C
|
||||
select DDC
|
||||
|
||||
config MACFB
|
||||
bool
|
||||
select FRAMEBUFFER
|
||||
depends on NUBUS
|
||||
|
||||
@@ -26,6 +26,7 @@ common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o
|
||||
common-obj-$(CONFIG_FRAMEBUFFER) += framebuffer.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o
|
||||
common-obj-$(CONFIG_ZAURUS) += tc6393xb.o
|
||||
common-obj-$(CONFIG_MACFB) += macfb.o
|
||||
|
||||
obj-$(CONFIG_MILKYMIST_TMU2) += milkymist-tmu2.o
|
||||
milkymist-tmu2.o-cflags := $(X11_CFLAGS) $(OPENGL_CFLAGS)
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* QEMU Motorola 680x0 Macintosh Video Card Emulation
|
||||
* Copyright (c) 2012-2018 Laurent Vivier
|
||||
*
|
||||
* some parts from QEMU G364 framebuffer Emulator.
|
||||
* Copyright (c) 2007-2011 Herve Poussineau
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/pixel_ops.h"
|
||||
#include "hw/nubus/nubus.h"
|
||||
#include "hw/display/macfb.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#define VIDEO_BASE 0x00001000
|
||||
#define DAFB_BASE 0x00800000
|
||||
|
||||
#define MACFB_PAGE_SIZE 4096
|
||||
#define MACFB_VRAM_SIZE (4 * MiB)
|
||||
|
||||
#define DAFB_RESET 0x200
|
||||
#define DAFB_LUT 0x213
|
||||
|
||||
|
||||
typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr,
|
||||
int width);
|
||||
|
||||
static inline uint8_t macfb_read_byte(MacfbState *s, uint32_t addr)
|
||||
{
|
||||
return s->vram[addr & s->vram_bit_mask];
|
||||
}
|
||||
|
||||
/* 1-bit color */
|
||||
static void macfb_draw_line1(MacfbState *s, uint8_t *d, uint32_t addr,
|
||||
int width)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int bit = x & 7;
|
||||
int idx = (macfb_read_byte(s, addr) >> (7 - bit)) & 1;
|
||||
r = g = b = ((1 - idx) << 7);
|
||||
addr += (bit == 7);
|
||||
|
||||
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
|
||||
d += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2-bit color */
|
||||
static void macfb_draw_line2(MacfbState *s, uint8_t *d, uint32_t addr,
|
||||
int width)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int bit = (x & 3);
|
||||
int idx = (macfb_read_byte(s, addr) >> ((3 - bit) << 1)) & 3;
|
||||
r = s->color_palette[idx * 3];
|
||||
g = s->color_palette[idx * 3 + 1];
|
||||
b = s->color_palette[idx * 3 + 2];
|
||||
addr += (bit == 3);
|
||||
|
||||
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
|
||||
d += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4-bit color */
|
||||
static void macfb_draw_line4(MacfbState *s, uint8_t *d, uint32_t addr,
|
||||
int width)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int bit = x & 1;
|
||||
int idx = (macfb_read_byte(s, addr) >> ((1 - bit) << 2)) & 15;
|
||||
r = s->color_palette[idx * 3];
|
||||
g = s->color_palette[idx * 3 + 1];
|
||||
b = s->color_palette[idx * 3 + 2];
|
||||
addr += (bit == 1);
|
||||
|
||||
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
|
||||
d += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* 8-bit color */
|
||||
static void macfb_draw_line8(MacfbState *s, uint8_t *d, uint32_t addr,
|
||||
int width)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
r = s->color_palette[macfb_read_byte(s, addr) * 3];
|
||||
g = s->color_palette[macfb_read_byte(s, addr) * 3 + 1];
|
||||
b = s->color_palette[macfb_read_byte(s, addr) * 3 + 2];
|
||||
addr++;
|
||||
|
||||
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
|
||||
d += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* 16-bit color */
|
||||
static void macfb_draw_line16(MacfbState *s, uint8_t *d, uint32_t addr,
|
||||
int width)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
uint16_t pixel;
|
||||
pixel = (macfb_read_byte(s, addr) << 8) | macfb_read_byte(s, addr + 1);
|
||||
r = ((pixel >> 10) & 0x1f) << 3;
|
||||
g = ((pixel >> 5) & 0x1f) << 3;
|
||||
b = (pixel & 0x1f) << 3;
|
||||
addr += 2;
|
||||
|
||||
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
|
||||
d += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* 24-bit color */
|
||||
static void macfb_draw_line24(MacfbState *s, uint8_t *d, uint32_t addr,
|
||||
int width)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
r = macfb_read_byte(s, addr);
|
||||
g = macfb_read_byte(s, addr + 1);
|
||||
b = macfb_read_byte(s, addr + 2);
|
||||
addr += 3;
|
||||
|
||||
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
|
||||
d += 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
MACFB_DRAW_LINE1,
|
||||
MACFB_DRAW_LINE2,
|
||||
MACFB_DRAW_LINE4,
|
||||
MACFB_DRAW_LINE8,
|
||||
MACFB_DRAW_LINE16,
|
||||
MACFB_DRAW_LINE24,
|
||||
MACFB_DRAW_LINE_NB,
|
||||
};
|
||||
|
||||
static macfb_draw_line_func * const
|
||||
macfb_draw_line_table[MACFB_DRAW_LINE_NB] = {
|
||||
macfb_draw_line1,
|
||||
macfb_draw_line2,
|
||||
macfb_draw_line4,
|
||||
macfb_draw_line8,
|
||||
macfb_draw_line16,
|
||||
macfb_draw_line24,
|
||||
};
|
||||
|
||||
static int macfb_check_dirty(MacfbState *s, DirtyBitmapSnapshot *snap,
|
||||
ram_addr_t addr, int len)
|
||||
{
|
||||
return memory_region_snapshot_get_dirty(&s->mem_vram, snap, addr, len);
|
||||
}
|
||||
|
||||
static void macfb_draw_graphic(MacfbState *s)
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
DirtyBitmapSnapshot *snap = NULL;
|
||||
ram_addr_t page;
|
||||
uint32_t v = 0;
|
||||
int y, ymin;
|
||||
int macfb_stride = (s->depth * s->width + 7) / 8;
|
||||
macfb_draw_line_func *macfb_draw_line;
|
||||
|
||||
switch (s->depth) {
|
||||
case 1:
|
||||
v = MACFB_DRAW_LINE1;
|
||||
break;
|
||||
case 2:
|
||||
v = MACFB_DRAW_LINE2;
|
||||
break;
|
||||
case 4:
|
||||
v = MACFB_DRAW_LINE4;
|
||||
break;
|
||||
case 8:
|
||||
v = MACFB_DRAW_LINE8;
|
||||
break;
|
||||
case 16:
|
||||
v = MACFB_DRAW_LINE16;
|
||||
break;
|
||||
case 24:
|
||||
v = MACFB_DRAW_LINE24;
|
||||
break;
|
||||
}
|
||||
|
||||
macfb_draw_line = macfb_draw_line_table[v];
|
||||
assert(macfb_draw_line != NULL);
|
||||
|
||||
snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0x0,
|
||||
memory_region_size(&s->mem_vram),
|
||||
DIRTY_MEMORY_VGA);
|
||||
|
||||
ymin = -1;
|
||||
page = 0;
|
||||
for (y = 0; y < s->height; y++, page += macfb_stride) {
|
||||
if (macfb_check_dirty(s, snap, page, macfb_stride)) {
|
||||
uint8_t *data_display;
|
||||
|
||||
data_display = surface_data(surface) + y * surface_stride(surface);
|
||||
macfb_draw_line(s, data_display, page, s->width);
|
||||
|
||||
if (ymin < 0) {
|
||||
ymin = y;
|
||||
}
|
||||
} else {
|
||||
if (ymin >= 0) {
|
||||
dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
|
||||
ymin = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ymin >= 0) {
|
||||
dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
|
||||
}
|
||||
|
||||
g_free(snap);
|
||||
}
|
||||
|
||||
static void macfb_invalidate_display(void *opaque)
|
||||
{
|
||||
MacfbState *s = opaque;
|
||||
|
||||
memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE);
|
||||
}
|
||||
|
||||
static void macfb_update_display(void *opaque)
|
||||
{
|
||||
MacfbState *s = opaque;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
|
||||
qemu_flush_coalesced_mmio_buffer();
|
||||
|
||||
if (s->width == 0 || s->height == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->width != surface_width(surface) ||
|
||||
s->height != surface_height(surface)) {
|
||||
qemu_console_resize(s->con, s->width, s->height);
|
||||
}
|
||||
|
||||
macfb_draw_graphic(s);
|
||||
}
|
||||
|
||||
static void macfb_reset(MacfbState *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
s->palette_current = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
s->color_palette[i * 3] = 255 - i;
|
||||
s->color_palette[i * 3 + 1] = 255 - i;
|
||||
s->color_palette[i * 3 + 2] = 255 - i;
|
||||
}
|
||||
memset(s->vram, 0, MACFB_VRAM_SIZE);
|
||||
macfb_invalidate_display(s);
|
||||
}
|
||||
|
||||
static uint64_t macfb_ctrl_read(void *opaque,
|
||||
hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void macfb_ctrl_write(void *opaque,
|
||||
hwaddr addr,
|
||||
uint64_t val,
|
||||
unsigned int size)
|
||||
{
|
||||
MacfbState *s = opaque;
|
||||
switch (addr) {
|
||||
case DAFB_RESET:
|
||||
s->palette_current = 0;
|
||||
break;
|
||||
case DAFB_LUT:
|
||||
s->color_palette[s->palette_current++] = val;
|
||||
if (s->palette_current % 3) {
|
||||
macfb_invalidate_display(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps macfb_ctrl_ops = {
|
||||
.read = macfb_ctrl_read,
|
||||
.write = macfb_ctrl_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 4,
|
||||
};
|
||||
|
||||
static int macfb_post_load(void *opaque, int version_id)
|
||||
{
|
||||
macfb_invalidate_display(opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_macfb = {
|
||||
.name = "macfb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = macfb_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
|
||||
VMSTATE_UINT32(palette_current, MacfbState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const GraphicHwOps macfb_ops = {
|
||||
.invalidate = macfb_invalidate_display,
|
||||
.gfx_update = macfb_update_display,
|
||||
};
|
||||
|
||||
static void macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
|
||||
{
|
||||
DisplaySurface *surface;
|
||||
|
||||
if (s->depth != 1 && s->depth != 2 && s->depth != 4 && s->depth != 8 &&
|
||||
s->depth != 16 && s->depth != 24) {
|
||||
error_setg(errp, "unknown guest depth %d", s->depth);
|
||||
return;
|
||||
}
|
||||
|
||||
s->con = graphic_console_init(dev, 0, &macfb_ops, s);
|
||||
surface = qemu_console_surface(s->con);
|
||||
|
||||
if (surface_bits_per_pixel(surface) != 32) {
|
||||
error_setg(errp, "unknown host depth %d",
|
||||
surface_bits_per_pixel(surface));
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->mem_ctrl, NULL, &macfb_ctrl_ops, s, "macfb-ctrl",
|
||||
0x1000);
|
||||
|
||||
memory_region_init_ram_nomigrate(&s->mem_vram, OBJECT(s), "macfb-vram",
|
||||
MACFB_VRAM_SIZE, errp);
|
||||
s->vram = memory_region_get_ram_ptr(&s->mem_vram);
|
||||
s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
|
||||
vmstate_register_ram(&s->mem_vram, dev);
|
||||
memory_region_set_coalescing(&s->mem_vram);
|
||||
}
|
||||
|
||||
static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MacfbSysBusState *s = MACFB(dev);
|
||||
MacfbState *ms = &s->macfb;
|
||||
|
||||
macfb_common_realize(dev, ms, errp);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
|
||||
}
|
||||
|
||||
const uint8_t macfb_rom[] = {
|
||||
255, 0, 0, 0,
|
||||
};
|
||||
|
||||
static void macfb_nubus_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NubusDevice *nd = NUBUS_DEVICE(dev);
|
||||
MacfbNubusState *s = NUBUS_MACFB(dev);
|
||||
MacfbNubusDeviceClass *ndc = MACFB_NUBUS_GET_CLASS(dev);
|
||||
MacfbState *ms = &s->macfb;
|
||||
|
||||
ndc->parent_realize(dev, errp);
|
||||
|
||||
macfb_common_realize(dev, ms, errp);
|
||||
memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
|
||||
memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
|
||||
|
||||
nubus_register_rom(nd, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
|
||||
}
|
||||
|
||||
static void macfb_sysbus_reset(DeviceState *d)
|
||||
{
|
||||
MacfbSysBusState *s = MACFB(d);
|
||||
macfb_reset(&s->macfb);
|
||||
}
|
||||
|
||||
static void macfb_nubus_reset(DeviceState *d)
|
||||
{
|
||||
MacfbNubusState *s = NUBUS_MACFB(d);
|
||||
macfb_reset(&s->macfb);
|
||||
}
|
||||
|
||||
static Property macfb_sysbus_properties[] = {
|
||||
DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640),
|
||||
DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480),
|
||||
DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static Property macfb_nubus_properties[] = {
|
||||
DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640),
|
||||
DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480),
|
||||
DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = macfb_sysbus_realize;
|
||||
dc->desc = "SysBus Macintosh framebuffer";
|
||||
dc->reset = macfb_sysbus_reset;
|
||||
dc->vmsd = &vmstate_macfb;
|
||||
dc->props = macfb_sysbus_properties;
|
||||
}
|
||||
|
||||
static void macfb_nubus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
MacfbNubusDeviceClass *ndc = MACFB_NUBUS_DEVICE_CLASS(klass);
|
||||
|
||||
device_class_set_parent_realize(dc, macfb_nubus_realize,
|
||||
&ndc->parent_realize);
|
||||
dc->desc = "Nubus Macintosh framebuffer";
|
||||
dc->reset = macfb_nubus_reset;
|
||||
dc->vmsd = &vmstate_macfb;
|
||||
dc->props = macfb_nubus_properties;
|
||||
}
|
||||
|
||||
static TypeInfo macfb_sysbus_info = {
|
||||
.name = TYPE_MACFB,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MacfbSysBusState),
|
||||
.class_init = macfb_sysbus_class_init,
|
||||
};
|
||||
|
||||
static TypeInfo macfb_nubus_info = {
|
||||
.name = TYPE_NUBUS_MACFB,
|
||||
.parent = TYPE_NUBUS_DEVICE,
|
||||
.instance_size = sizeof(MacfbNubusState),
|
||||
.class_init = macfb_nubus_class_init,
|
||||
.class_size = sizeof(MacfbNubusDeviceClass),
|
||||
};
|
||||
|
||||
static void macfb_register_types(void)
|
||||
{
|
||||
type_register_static(&macfb_sysbus_info);
|
||||
type_register_static(&macfb_nubus_info);
|
||||
}
|
||||
|
||||
type_init(macfb_register_types)
|
||||
@@ -12,3 +12,13 @@ config NEXTCUBE
|
||||
bool
|
||||
select FRAMEBUFFER
|
||||
select ESCC
|
||||
|
||||
config Q800
|
||||
bool
|
||||
select MAC_VIA
|
||||
select NUBUS
|
||||
select MACFB
|
||||
select SWIM
|
||||
select ESCC
|
||||
select ESP
|
||||
select DP8393X
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
obj-$(CONFIG_AN5206) += an5206.o mcf5206.o
|
||||
obj-$(CONFIG_MCF5208) += mcf5208.o mcf_intc.o
|
||||
obj-$(CONFIG_NEXTCUBE) += next-kbd.o next-cube.o
|
||||
obj-$(CONFIG_Q800) += q800.o
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
||||
*
|
||||
* Bootinfo tags from linux bootinfo.h and bootinfo-mac.h:
|
||||
* This is an easily parsable and extendable structure containing all
|
||||
* information to be passed from the bootstrap to the kernel
|
||||
*
|
||||
* This structure is copied right after the kernel by the bootstrap
|
||||
* routine.
|
||||
*/
|
||||
|
||||
#ifndef HW_M68K_BOOTINFO_H
|
||||
#define HW_M68K_BOOTINFO_H
|
||||
struct bi_record {
|
||||
uint16_t tag; /* tag ID */
|
||||
uint16_t size; /* size of record */
|
||||
uint32_t data[0]; /* data */
|
||||
};
|
||||
|
||||
/* machine independent tags */
|
||||
|
||||
#define BI_LAST 0x0000 /* last record */
|
||||
#define BI_MACHTYPE 0x0001 /* machine type (u_long) */
|
||||
#define BI_CPUTYPE 0x0002 /* cpu type (u_long) */
|
||||
#define BI_FPUTYPE 0x0003 /* fpu type (u_long) */
|
||||
#define BI_MMUTYPE 0x0004 /* mmu type (u_long) */
|
||||
#define BI_MEMCHUNK 0x0005 /* memory chunk address and size */
|
||||
/* (struct mem_info) */
|
||||
#define BI_RAMDISK 0x0006 /* ramdisk address and size */
|
||||
/* (struct mem_info) */
|
||||
#define BI_COMMAND_LINE 0x0007 /* kernel command line parameters */
|
||||
/* (string) */
|
||||
|
||||
/* Macintosh-specific tags (all u_long) */
|
||||
|
||||
#define BI_MAC_MODEL 0x8000 /* Mac Gestalt ID (model type) */
|
||||
#define BI_MAC_VADDR 0x8001 /* Mac video base address */
|
||||
#define BI_MAC_VDEPTH 0x8002 /* Mac video depth */
|
||||
#define BI_MAC_VROW 0x8003 /* Mac video rowbytes */
|
||||
#define BI_MAC_VDIM 0x8004 /* Mac video dimensions */
|
||||
#define BI_MAC_VLOGICAL 0x8005 /* Mac video logical base */
|
||||
#define BI_MAC_SCCBASE 0x8006 /* Mac SCC base address */
|
||||
#define BI_MAC_BTIME 0x8007 /* Mac boot time */
|
||||
#define BI_MAC_GMTBIAS 0x8008 /* Mac GMT timezone offset */
|
||||
#define BI_MAC_MEMSIZE 0x8009 /* Mac RAM size (sanity check) */
|
||||
#define BI_MAC_CPUID 0x800a /* Mac CPU type (sanity check) */
|
||||
#define BI_MAC_ROMBASE 0x800b /* Mac system ROM base address */
|
||||
|
||||
/* Macintosh hardware profile data */
|
||||
|
||||
#define BI_MAC_VIA1BASE 0x8010 /* Mac VIA1 base address (always present) */
|
||||
#define BI_MAC_VIA2BASE 0x8011 /* Mac VIA2 base address (type varies) */
|
||||
#define BI_MAC_VIA2TYPE 0x8012 /* Mac VIA2 type (VIA, RBV, OSS) */
|
||||
#define BI_MAC_ADBTYPE 0x8013 /* Mac ADB interface type */
|
||||
#define BI_MAC_ASCBASE 0x8014 /* Mac Apple Sound Chip base address */
|
||||
#define BI_MAC_SCSI5380 0x8015 /* Mac NCR 5380 SCSI (base address, multi) */
|
||||
#define BI_MAC_SCSIDMA 0x8016 /* Mac SCSI DMA (base address) */
|
||||
#define BI_MAC_SCSI5396 0x8017 /* Mac NCR 53C96 SCSI (base address, multi) */
|
||||
#define BI_MAC_IDETYPE 0x8018 /* Mac IDE interface type */
|
||||
#define BI_MAC_IDEBASE 0x8019 /* Mac IDE interface base address */
|
||||
#define BI_MAC_NUBUS 0x801a /* Mac Nubus type (none, regular, pseudo) */
|
||||
#define BI_MAC_SLOTMASK 0x801b /* Mac Nubus slots present */
|
||||
#define BI_MAC_SCCTYPE 0x801c /* Mac SCC serial type (normal, IOP) */
|
||||
#define BI_MAC_ETHTYPE 0x801d /* Mac builtin ethernet type (Sonic, MACE */
|
||||
#define BI_MAC_ETHBASE 0x801e /* Mac builtin ethernet base address */
|
||||
#define BI_MAC_PMU 0x801f /* Mac power management / poweroff hardware */
|
||||
#define BI_MAC_IOP_SWIM 0x8020 /* Mac SWIM floppy IOP */
|
||||
#define BI_MAC_IOP_ADB 0x8021 /* Mac ADB IOP */
|
||||
|
||||
#define BOOTINFO0(as, base, id) \
|
||||
do { \
|
||||
stw_phys(as, base, id); \
|
||||
base += 2; \
|
||||
stw_phys(as, base, sizeof(struct bi_record)); \
|
||||
base += 2; \
|
||||
} while (0)
|
||||
|
||||
#define BOOTINFO1(as, base, id, value) \
|
||||
do { \
|
||||
stw_phys(as, base, id); \
|
||||
base += 2; \
|
||||
stw_phys(as, base, sizeof(struct bi_record) + 4); \
|
||||
base += 2; \
|
||||
stl_phys(as, base, value); \
|
||||
base += 4; \
|
||||
} while (0)
|
||||
|
||||
#define BOOTINFO2(as, base, id, value1, value2) \
|
||||
do { \
|
||||
stw_phys(as, base, id); \
|
||||
base += 2; \
|
||||
stw_phys(as, base, sizeof(struct bi_record) + 8); \
|
||||
base += 2; \
|
||||
stl_phys(as, base, value1); \
|
||||
base += 4; \
|
||||
stl_phys(as, base, value2); \
|
||||
base += 4; \
|
||||
} while (0)
|
||||
|
||||
#define BOOTINFOSTR(as, base, id, string) \
|
||||
do { \
|
||||
int i; \
|
||||
stw_phys(as, base, id); \
|
||||
base += 2; \
|
||||
stw_phys(as, base, \
|
||||
(sizeof(struct bi_record) + strlen(string) + 2) & ~1); \
|
||||
base += 2; \
|
||||
for (i = 0; string[i]; i++) { \
|
||||
stb_phys(as, base++, string[i]); \
|
||||
} \
|
||||
stb_phys(as, base++, 0); \
|
||||
base = (parameters_base + 1) & ~1; \
|
||||
} while (0)
|
||||
#endif
|
||||
+401
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* QEMU Motorla 680x0 Macintosh hardware System Emulator
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/irq.h"
|
||||
#include "elf.h"
|
||||
#include "hw/loader.h"
|
||||
#include "ui/console.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/char/escc.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/scsi/esp.h"
|
||||
#include "bootinfo.h"
|
||||
#include "hw/misc/mac_via.h"
|
||||
#include "hw/input/adb.h"
|
||||
#include "hw/nubus/mac-nubus-bridge.h"
|
||||
#include "hw/display/macfb.h"
|
||||
#include "hw/block/swim.h"
|
||||
#include "net/net.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/reset.h"
|
||||
|
||||
#define MACROM_ADDR 0x40000000
|
||||
#define MACROM_SIZE 0x00100000
|
||||
|
||||
#define MACROM_FILENAME "MacROM.bin"
|
||||
|
||||
#define Q800_MACHINE_ID 35
|
||||
#define Q800_CPU_ID (1 << 2)
|
||||
#define Q800_FPU_ID (1 << 2)
|
||||
#define Q800_MMU_ID (1 << 2)
|
||||
|
||||
#define MACH_MAC 3
|
||||
#define Q800_MAC_CPU_ID 2
|
||||
|
||||
#define VIA_BASE 0x50f00000
|
||||
#define SONIC_PROM_BASE 0x50f08000
|
||||
#define SONIC_BASE 0x50f0a000
|
||||
#define SCC_BASE 0x50f0c020
|
||||
#define ESP_BASE 0x50f10000
|
||||
#define ESP_PDMA 0x50f10100
|
||||
#define ASC_BASE 0x50F14000
|
||||
#define SWIM_BASE 0x50F1E000
|
||||
#define NUBUS_SUPER_SLOT_BASE 0x60000000
|
||||
#define NUBUS_SLOT_BASE 0xf0000000
|
||||
|
||||
/*
|
||||
* the video base, whereas it a Nubus address,
|
||||
* is needed by the kernel to have early display and
|
||||
* thus provided by the bootloader
|
||||
*/
|
||||
#define VIDEO_BASE 0xf9001000
|
||||
|
||||
#define MAC_CLOCK 3686418
|
||||
|
||||
/*
|
||||
* The GLUE (General Logic Unit) is an Apple custom integrated circuit chip
|
||||
* that performs a variety of functions (RAM management, clock generation, ...).
|
||||
* The GLUE chip receives interrupt requests from various devices,
|
||||
* assign priority to each, and asserts one or more interrupt line to the
|
||||
* CPU.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
M68kCPU *cpu;
|
||||
uint8_t ipr;
|
||||
} GLUEState;
|
||||
|
||||
static void GLUE_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
GLUEState *s = opaque;
|
||||
int i;
|
||||
|
||||
if (level) {
|
||||
s->ipr |= 1 << irq;
|
||||
} else {
|
||||
s->ipr &= ~(1 << irq);
|
||||
}
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
if ((s->ipr >> i) & 1) {
|
||||
m68k_set_irq_level(s->cpu, i + 1, i + 25);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m68k_set_irq_level(s->cpu, 0, 0);
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
M68kCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
cpu_reset(cs);
|
||||
cpu->env.aregs[7] = ldl_phys(cs->as, 0);
|
||||
cpu->env.pc = ldl_phys(cs->as, 4);
|
||||
}
|
||||
|
||||
static void q800_init(MachineState *machine)
|
||||
{
|
||||
M68kCPU *cpu = NULL;
|
||||
int linux_boot;
|
||||
int32_t kernel_size;
|
||||
uint64_t elf_entry;
|
||||
char *filename;
|
||||
int bios_size;
|
||||
ram_addr_t initrd_base;
|
||||
int32_t initrd_size;
|
||||
MemoryRegion *rom;
|
||||
MemoryRegion *ram;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
hwaddr parameters_base;
|
||||
CPUState *cs;
|
||||
DeviceState *dev;
|
||||
DeviceState *via_dev;
|
||||
SysBusESPState *sysbus_esp;
|
||||
ESPState *esp;
|
||||
SysBusDevice *sysbus;
|
||||
BusState *adb_bus;
|
||||
NubusBus *nubus;
|
||||
GLUEState *irq;
|
||||
qemu_irq *pic;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
if (ram_size > 1 * GiB) {
|
||||
error_report("Too much memory for this machine: %" PRId64 " MiB, "
|
||||
"maximum 1024 MiB", ram_size / MiB);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* init CPUs */
|
||||
cpu = M68K_CPU(cpu_create(machine->cpu_type));
|
||||
qemu_register_reset(main_cpu_reset, cpu);
|
||||
|
||||
ram = g_malloc(sizeof(*ram));
|
||||
memory_region_init_ram(ram, NULL, "m68k_mac.ram", ram_size, &error_abort);
|
||||
memory_region_add_subregion(get_system_memory(), 0, ram);
|
||||
|
||||
/* IRQ Glue */
|
||||
|
||||
irq = g_new0(GLUEState, 1);
|
||||
irq->cpu = cpu;
|
||||
pic = qemu_allocate_irqs(GLUE_set_irq, irq, 8);
|
||||
|
||||
/* VIA */
|
||||
|
||||
via_dev = qdev_create(NULL, TYPE_MAC_VIA);
|
||||
qdev_init_nofail(via_dev);
|
||||
sysbus = SYS_BUS_DEVICE(via_dev);
|
||||
sysbus_mmio_map(sysbus, 0, VIA_BASE);
|
||||
qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, pic[0]);
|
||||
qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1, pic[1]);
|
||||
|
||||
|
||||
adb_bus = qdev_get_child_bus(via_dev, "adb.0");
|
||||
dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD);
|
||||
qdev_init_nofail(dev);
|
||||
dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* MACSONIC */
|
||||
|
||||
if (nb_nics > 1) {
|
||||
error_report("q800 can only have one ethernet interface");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qemu_check_nic_model(&nd_table[0], "dp83932");
|
||||
|
||||
/*
|
||||
* MacSonic driver needs an Apple MAC address
|
||||
* Valid prefix are:
|
||||
* 00:05:02 Apple
|
||||
* 00:80:19 Dayna Communications, Inc.
|
||||
* 00:A0:40 Apple
|
||||
* 08:00:07 Apple
|
||||
* (Q800 use the last one)
|
||||
*/
|
||||
nd_table[0].macaddr.a[0] = 0x08;
|
||||
nd_table[0].macaddr.a[1] = 0x00;
|
||||
nd_table[0].macaddr.a[2] = 0x07;
|
||||
|
||||
dev = qdev_create(NULL, "dp8393x");
|
||||
qdev_set_nic_properties(dev, &nd_table[0]);
|
||||
qdev_prop_set_uint8(dev, "it_shift", 2);
|
||||
qdev_prop_set_bit(dev, "big_endian", true);
|
||||
qdev_prop_set_ptr(dev, "dma_mr", get_system_memory());
|
||||
qdev_init_nofail(dev);
|
||||
sysbus = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(sysbus, 0, SONIC_BASE);
|
||||
sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE);
|
||||
sysbus_connect_irq(sysbus, 0, pic[2]);
|
||||
|
||||
/* SCC */
|
||||
|
||||
dev = qdev_create(NULL, TYPE_ESCC);
|
||||
qdev_prop_set_uint32(dev, "disabled", 0);
|
||||
qdev_prop_set_uint32(dev, "frequency", MAC_CLOCK);
|
||||
qdev_prop_set_uint32(dev, "it_shift", 1);
|
||||
qdev_prop_set_bit(dev, "bit_swap", true);
|
||||
qdev_prop_set_chr(dev, "chrA", serial_hd(0));
|
||||
qdev_prop_set_chr(dev, "chrB", serial_hd(1));
|
||||
qdev_prop_set_uint32(dev, "chnBtype", 0);
|
||||
qdev_prop_set_uint32(dev, "chnAtype", 0);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus = SYS_BUS_DEVICE(dev);
|
||||
sysbus_connect_irq(sysbus, 0, pic[3]);
|
||||
sysbus_connect_irq(sysbus, 1, pic[3]);
|
||||
sysbus_mmio_map(sysbus, 0, SCC_BASE);
|
||||
|
||||
/* SCSI */
|
||||
|
||||
dev = qdev_create(NULL, TYPE_ESP);
|
||||
sysbus_esp = ESP_STATE(dev);
|
||||
esp = &sysbus_esp->esp;
|
||||
esp->dma_memory_read = NULL;
|
||||
esp->dma_memory_write = NULL;
|
||||
esp->dma_opaque = NULL;
|
||||
sysbus_esp->it_shift = 4;
|
||||
esp->dma_enabled = 1;
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
sysbus = SYS_BUS_DEVICE(dev);
|
||||
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in_named(via_dev,
|
||||
"via2-irq",
|
||||
VIA2_IRQ_SCSI_BIT));
|
||||
sysbus_connect_irq(sysbus, 1,
|
||||
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, 1, ESP_PDMA);
|
||||
|
||||
scsi_bus_legacy_handle_cmdline(&esp->bus);
|
||||
|
||||
/* SWIM floppy controller */
|
||||
|
||||
dev = qdev_create(NULL, TYPE_SWIM);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SWIM_BASE);
|
||||
|
||||
/* NuBus */
|
||||
|
||||
dev = qdev_create(NULL, TYPE_MAC_NUBUS_BRIDGE);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, NUBUS_SUPER_SLOT_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE);
|
||||
|
||||
nubus = MAC_NUBUS_BRIDGE(dev)->bus;
|
||||
|
||||
/* framebuffer in nubus slot #9 */
|
||||
|
||||
dev = qdev_create(BUS(nubus), TYPE_NUBUS_MACFB);
|
||||
qdev_prop_set_uint32(dev, "width", graphic_width);
|
||||
qdev_prop_set_uint32(dev, "height", graphic_height);
|
||||
qdev_prop_set_uint8(dev, "depth", graphic_depth);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
cs = CPU(cpu);
|
||||
if (linux_boot) {
|
||||
uint64_t high;
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
|
||||
&elf_entry, NULL, &high, 1,
|
||||
EM_68K, 0, 0);
|
||||
if (kernel_size < 0) {
|
||||
error_report("could not load kernel '%s'", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
stl_phys(cs->as, 4, elf_entry); /* reset initial PC */
|
||||
parameters_base = (high + 1) & ~1;
|
||||
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MACHTYPE, MACH_MAC);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, Q800_FPU_ID);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, Q800_MMU_ID);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, Q800_CPU_ID);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MAC_CPUID, Q800_MAC_CPU_ID);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MAC_MODEL, Q800_MACHINE_ID);
|
||||
BOOTINFO1(cs->as, parameters_base,
|
||||
BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */
|
||||
BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MAC_VADDR, VIDEO_BASE);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MAC_VDEPTH, graphic_depth);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MAC_VDIM,
|
||||
(graphic_height << 16) | graphic_width);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MAC_VROW,
|
||||
(graphic_width * graphic_depth + 7) / 8);
|
||||
BOOTINFO1(cs->as, parameters_base, BI_MAC_SCCBASE, SCC_BASE);
|
||||
|
||||
if (kernel_cmdline) {
|
||||
BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE,
|
||||
kernel_cmdline);
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
initrd_size = get_image_size(initrd_filename);
|
||||
if (initrd_size < 0) {
|
||||
error_report("could not load initial ram disk '%s'",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
|
||||
load_image_targphys(initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
BOOTINFO2(cs->as, parameters_base, BI_RAMDISK, initrd_base,
|
||||
initrd_size);
|
||||
} else {
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
}
|
||||
BOOTINFO0(cs->as, parameters_base, BI_LAST);
|
||||
} else {
|
||||
uint8_t *ptr;
|
||||
/* allocate and load BIOS */
|
||||
rom = g_malloc(sizeof(*rom));
|
||||
memory_region_init_ram(rom, NULL, "m68k_mac.rom", MACROM_SIZE,
|
||||
&error_abort);
|
||||
if (bios_name == NULL) {
|
||||
bios_name = MACROM_FILENAME;
|
||||
}
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
memory_region_set_readonly(rom, true);
|
||||
memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom);
|
||||
|
||||
/* Load MacROM binary */
|
||||
if (filename) {
|
||||
bios_size = load_image_targphys(filename, MACROM_ADDR, MACROM_SIZE);
|
||||
g_free(filename);
|
||||
} else {
|
||||
bios_size = -1;
|
||||
}
|
||||
|
||||
/* Remove qtest_enabled() check once firmware files are in the tree */
|
||||
if (!qtest_enabled()) {
|
||||
if (bios_size < 0 || bios_size > MACROM_SIZE) {
|
||||
error_report("could not load MacROM '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ptr = rom_ptr(MACROM_ADDR, MACROM_SIZE);
|
||||
stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */
|
||||
stl_phys(cs->as, 4,
|
||||
MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void q800_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
mc->desc = "Macintosh Quadra 800";
|
||||
mc->init = q800_init;
|
||||
mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
|
||||
mc->max_cpus = 1;
|
||||
mc->is_default = 0;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
}
|
||||
|
||||
static const TypeInfo q800_machine_typeinfo = {
|
||||
.name = MACHINE_TYPE_NAME("q800"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = q800_machine_class_init,
|
||||
};
|
||||
|
||||
static void q800_machine_register_types(void)
|
||||
{
|
||||
type_register_static(&q800_machine_typeinfo);
|
||||
}
|
||||
|
||||
type_init(q800_machine_register_types)
|
||||
@@ -120,4 +120,9 @@ config AUX
|
||||
config UNIMP
|
||||
bool
|
||||
|
||||
config MAC_VIA
|
||||
bool
|
||||
select MOS6522
|
||||
select ADB
|
||||
|
||||
source macio/Kconfig
|
||||
|
||||
@@ -79,5 +79,6 @@ common-obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
|
||||
common-obj-$(CONFIG_MSF2) += msf2-sysreg.o
|
||||
common-obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
|
||||
obj-$(CONFIG_MAC_VIA) += mac_via.o
|
||||
|
||||
common-obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+57
-31
@@ -153,6 +153,7 @@ typedef struct dp8393xState {
|
||||
|
||||
/* Hardware */
|
||||
uint8_t it_shift;
|
||||
bool big_endian;
|
||||
qemu_irq irq;
|
||||
#ifdef DEBUG_SONIC
|
||||
int irq_level;
|
||||
@@ -223,6 +224,29 @@ static uint32_t dp8393x_wt(dp8393xState *s)
|
||||
return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
|
||||
}
|
||||
|
||||
static uint16_t dp8393x_get(dp8393xState *s, int width, uint16_t *base,
|
||||
int offset)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
if (s->big_endian) {
|
||||
val = be16_to_cpu(base[offset * width + width - 1]);
|
||||
} else {
|
||||
val = le16_to_cpu(base[offset * width]);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset,
|
||||
uint16_t val)
|
||||
{
|
||||
if (s->big_endian) {
|
||||
base[offset * width + width - 1] = cpu_to_be16(val);
|
||||
} else {
|
||||
base[offset * width] = cpu_to_le16(val);
|
||||
}
|
||||
}
|
||||
|
||||
static void dp8393x_update_irq(dp8393xState *s)
|
||||
{
|
||||
int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
|
||||
@@ -254,12 +278,12 @@ static void dp8393x_do_load_cam(dp8393xState *s)
|
||||
/* Fill current entry */
|
||||
address_space_rw(&s->as, dp8393x_cdp(s),
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->cam[index][0] = data[1 * width] & 0xff;
|
||||
s->cam[index][1] = data[1 * width] >> 8;
|
||||
s->cam[index][2] = data[2 * width] & 0xff;
|
||||
s->cam[index][3] = data[2 * width] >> 8;
|
||||
s->cam[index][4] = data[3 * width] & 0xff;
|
||||
s->cam[index][5] = data[3 * width] >> 8;
|
||||
s->cam[index][0] = dp8393x_get(s, width, data, 1) & 0xff;
|
||||
s->cam[index][1] = dp8393x_get(s, width, data, 1) >> 8;
|
||||
s->cam[index][2] = dp8393x_get(s, width, data, 2) & 0xff;
|
||||
s->cam[index][3] = dp8393x_get(s, width, data, 2) >> 8;
|
||||
s->cam[index][4] = dp8393x_get(s, width, data, 3) & 0xff;
|
||||
s->cam[index][5] = dp8393x_get(s, width, data, 3) >> 8;
|
||||
DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
|
||||
s->cam[index][0], s->cam[index][1], s->cam[index][2],
|
||||
s->cam[index][3], s->cam[index][4], s->cam[index][5]);
|
||||
@@ -272,7 +296,7 @@ static void dp8393x_do_load_cam(dp8393xState *s)
|
||||
/* Read CAM enable */
|
||||
address_space_rw(&s->as, dp8393x_cdp(s),
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_CE] = data[0 * width];
|
||||
s->regs[SONIC_CE] = dp8393x_get(s, width, data, 0);
|
||||
DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
|
||||
|
||||
/* Done */
|
||||
@@ -293,10 +317,10 @@ static void dp8393x_do_read_rra(dp8393xState *s)
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
|
||||
/* Update SONIC registers */
|
||||
s->regs[SONIC_CRBA0] = data[0 * width];
|
||||
s->regs[SONIC_CRBA1] = data[1 * width];
|
||||
s->regs[SONIC_RBWC0] = data[2 * width];
|
||||
s->regs[SONIC_RBWC1] = data[3 * width];
|
||||
s->regs[SONIC_CRBA0] = dp8393x_get(s, width, data, 0);
|
||||
s->regs[SONIC_CRBA1] = dp8393x_get(s, width, data, 1);
|
||||
s->regs[SONIC_RBWC0] = dp8393x_get(s, width, data, 2);
|
||||
s->regs[SONIC_RBWC1] = dp8393x_get(s, width, data, 3);
|
||||
DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
|
||||
s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
|
||||
s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
|
||||
@@ -411,12 +435,12 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
||||
tx_len = 0;
|
||||
|
||||
/* Update registers */
|
||||
s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
|
||||
s->regs[SONIC_TPS] = data[1 * width];
|
||||
s->regs[SONIC_TFC] = data[2 * width];
|
||||
s->regs[SONIC_TSA0] = data[3 * width];
|
||||
s->regs[SONIC_TSA1] = data[4 * width];
|
||||
s->regs[SONIC_TFS] = data[5 * width];
|
||||
s->regs[SONIC_TCR] = dp8393x_get(s, width, data, 0) & 0xf000;
|
||||
s->regs[SONIC_TPS] = dp8393x_get(s, width, data, 1);
|
||||
s->regs[SONIC_TFC] = dp8393x_get(s, width, data, 2);
|
||||
s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 3);
|
||||
s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 4);
|
||||
s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 5);
|
||||
|
||||
/* Handle programmable interrupt */
|
||||
if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
|
||||
@@ -442,9 +466,9 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
||||
address_space_rw(&s->as,
|
||||
dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width,
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_TSA0] = data[0 * width];
|
||||
s->regs[SONIC_TSA1] = data[1 * width];
|
||||
s->regs[SONIC_TFS] = data[2 * width];
|
||||
s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 0);
|
||||
s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 1);
|
||||
s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,7 +495,8 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
||||
s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
|
||||
|
||||
/* Write status */
|
||||
data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
|
||||
dp8393x_put(s, width, data, 0,
|
||||
s->regs[SONIC_TCR] & 0x0fff); /* status */
|
||||
size = sizeof(uint16_t) * width;
|
||||
address_space_rw(&s->as,
|
||||
dp8393x_ttda(s),
|
||||
@@ -485,8 +510,8 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
||||
sizeof(uint16_t) *
|
||||
(4 + 3 * s->regs[SONIC_TFC]) * width,
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
|
||||
if (data[0 * width] & 0x1) {
|
||||
s->regs[SONIC_CTDA] = dp8393x_get(s, width, data, 0) & ~0x1;
|
||||
if (dp8393x_get(s, width, data, 0) & 0x1) {
|
||||
/* EOL detected */
|
||||
break;
|
||||
}
|
||||
@@ -749,7 +774,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
||||
address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width;
|
||||
address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
|
||||
(uint8_t *)data, size, 0);
|
||||
if (data[0 * width] & 0x1) {
|
||||
if (dp8393x_get(s, width, data, 0) & 0x1) {
|
||||
/* Still EOL ; stop reception */
|
||||
return -1;
|
||||
} else {
|
||||
@@ -793,11 +818,11 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
||||
|
||||
/* Write status to memory */
|
||||
DPRINTF("Write status at %08x\n", dp8393x_crda(s));
|
||||
data[0 * width] = s->regs[SONIC_RCR]; /* status */
|
||||
data[1 * width] = rx_len; /* byte count */
|
||||
data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
|
||||
data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
|
||||
data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
|
||||
dp8393x_put(s, width, data, 0, s->regs[SONIC_RCR]); /* status */
|
||||
dp8393x_put(s, width, data, 1, rx_len); /* byte count */
|
||||
dp8393x_put(s, width, data, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */
|
||||
dp8393x_put(s, width, data, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */
|
||||
dp8393x_put(s, width, data, 4, s->regs[SONIC_RSC]); /* seq_no */
|
||||
size = sizeof(uint16_t) * 5 * width;
|
||||
address_space_rw(&s->as, dp8393x_crda(s),
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
|
||||
@@ -806,12 +831,12 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
||||
size = sizeof(uint16_t) * width;
|
||||
address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width,
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_LLFA] = data[0 * width];
|
||||
s->regs[SONIC_LLFA] = dp8393x_get(s, width, data, 0);
|
||||
if (s->regs[SONIC_LLFA] & 0x1) {
|
||||
/* EOL detected */
|
||||
s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
|
||||
} else {
|
||||
data[0 * width] = 0; /* in_use */
|
||||
dp8393x_put(s, width, data, 0, 0); /* in_use */
|
||||
address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width,
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
|
||||
s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
|
||||
@@ -924,6 +949,7 @@ static Property dp8393x_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(dp8393xState, conf),
|
||||
DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr),
|
||||
DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0),
|
||||
DEFINE_PROP_BOOL("big_endian", dp8393xState, big_endian, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
config NUBUS
|
||||
bool
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user