qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

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>

+3659 -61
+14
MAINTAINERS
··· 917 917 F: hw/display/next-fb.c 918 918 F: include/hw/m68k/next-cube.h 919 919 920 + q800 921 + M: Laurent Vivier <laurent@vivier.eu> 922 + S: Maintained 923 + F: hw/m68k/q800.c 924 + F: hw/misc/mac_via.c 925 + F: hw/nubus/* 926 + F: hw/display/macfb.c 927 + F: hw/block/swim.c 928 + F: hw/m68k/bootinfo.h 929 + F: include/hw/misc/mac_via.h 930 + F: include/hw/nubus/* 931 + F: include/hw/display/macfb.h 932 + F: include/hw/block/swim.h 933 + 920 934 MicroBlaze Machines 921 935 ------------------- 922 936 petalogix_s3adsp1800
+4
arch_init.c
··· 38 38 int graphic_width = 1024; 39 39 int graphic_height = 768; 40 40 int graphic_depth = 8; 41 + #elif defined(TARGET_M68K) 42 + int graphic_width = 800; 43 + int graphic_height = 600; 44 + int graphic_depth = 8; 41 45 #else 42 46 int graphic_width = 800; 43 47 int graphic_height = 600;
+1
default-configs/m68k-softmmu.mak
··· 7 7 CONFIG_AN5206=y 8 8 CONFIG_MCF5208=y 9 9 CONFIG_NEXTCUBE=y 10 + CONFIG_Q800=y
+1
hw/Kconfig
··· 21 21 source mem/Kconfig 22 22 source misc/Kconfig 23 23 source net/Kconfig 24 + source nubus/Kconfig 24 25 source nvram/Kconfig 25 26 source pci-bridge/Kconfig 26 27 source pci-host/Kconfig
+1
hw/Makefile.objs
··· 38 38 devices-dirs-y += watchdog/ 39 39 devices-dirs-y += xen/ 40 40 devices-dirs-$(CONFIG_MEM_DEVICE) += mem/ 41 + devices-dirs-$(CONFIG_NUBUS) += nubus/ 41 42 devices-dirs-y += semihosting/ 42 43 devices-dirs-y += smbios/ 43 44 endif
+3
hw/block/Kconfig
··· 37 37 # Only PCI devices are provided for now 38 38 default y if VIRTIO_PCI 39 39 depends on VIRTIO && VHOST_USER && LINUX 40 + 41 + config SWIM 42 + bool
+1
hw/block/Makefile.objs
··· 8 8 common-obj-$(CONFIG_ECC) += ecc.o 9 9 common-obj-$(CONFIG_ONENAND) += onenand.o 10 10 common-obj-$(CONFIG_NVME_PCI) += nvme.o 11 + common-obj-$(CONFIG_SWIM) += swim.o 11 12 12 13 obj-$(CONFIG_SH4) += tc58128.o 13 14
+489
hw/block/swim.c
··· 1 + /* 2 + * QEMU Macintosh floppy disk controller emulator (SWIM) 3 + * 4 + * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu> 5 + * 6 + * This work is licensed under the terms of the GNU GPL, version 2. See 7 + * the COPYING file in the top-level directory. 8 + * 9 + * Only the basic support: it allows to switch from IWM (Integrated WOZ 10 + * Machine) mode to the SWIM mode and makes the linux driver happy. 11 + */ 12 + 13 + #include "qemu/osdep.h" 14 + #include "qemu/main-loop.h" 15 + #include "qapi/error.h" 16 + #include "sysemu/block-backend.h" 17 + #include "hw/sysbus.h" 18 + #include "migration/vmstate.h" 19 + #include "hw/block/block.h" 20 + #include "hw/block/swim.h" 21 + #include "hw/qdev-properties.h" 22 + 23 + /* IWM registers */ 24 + 25 + #define IWM_PH0L 0 26 + #define IWM_PH0H 1 27 + #define IWM_PH1L 2 28 + #define IWM_PH1H 3 29 + #define IWM_PH2L 4 30 + #define IWM_PH2H 5 31 + #define IWM_PH3L 6 32 + #define IWM_PH3H 7 33 + #define IWM_MTROFF 8 34 + #define IWM_MTRON 9 35 + #define IWM_INTDRIVE 10 36 + #define IWM_EXTDRIVE 11 37 + #define IWM_Q6L 12 38 + #define IWM_Q6H 13 39 + #define IWM_Q7L 14 40 + #define IWM_Q7H 15 41 + 42 + /* SWIM registers */ 43 + 44 + #define SWIM_WRITE_DATA 0 45 + #define SWIM_WRITE_MARK 1 46 + #define SWIM_WRITE_CRC 2 47 + #define SWIM_WRITE_PARAMETER 3 48 + #define SWIM_WRITE_PHASE 4 49 + #define SWIM_WRITE_SETUP 5 50 + #define SWIM_WRITE_MODE0 6 51 + #define SWIM_WRITE_MODE1 7 52 + 53 + #define SWIM_READ_DATA 8 54 + #define SWIM_READ_MARK 9 55 + #define SWIM_READ_ERROR 10 56 + #define SWIM_READ_PARAMETER 11 57 + #define SWIM_READ_PHASE 12 58 + #define SWIM_READ_SETUP 13 59 + #define SWIM_READ_STATUS 14 60 + #define SWIM_READ_HANDSHAKE 15 61 + 62 + #define REG_SHIFT 9 63 + 64 + #define SWIM_MODE_IWM 0 65 + #define SWIM_MODE_SWIM 1 66 + 67 + /* bits in phase register */ 68 + 69 + #define SWIM_SEEK_NEGATIVE 0x074 70 + #define SWIM_STEP 0x071 71 + #define SWIM_MOTOR_ON 0x072 72 + #define SWIM_MOTOR_OFF 0x076 73 + #define SWIM_INDEX 0x073 74 + #define SWIM_EJECT 0x077 75 + #define SWIM_SETMFM 0x171 76 + #define SWIM_SETGCR 0x175 77 + #define SWIM_RELAX 0x033 78 + #define SWIM_LSTRB 0x008 79 + #define SWIM_CA_MASK 0x077 80 + 81 + /* Select values for swim_select and swim_readbit */ 82 + 83 + #define SWIM_READ_DATA_0 0x074 84 + #define SWIM_TWOMEG_DRIVE 0x075 85 + #define SWIM_SINGLE_SIDED 0x076 86 + #define SWIM_DRIVE_PRESENT 0x077 87 + #define SWIM_DISK_IN 0x170 88 + #define SWIM_WRITE_PROT 0x171 89 + #define SWIM_TRACK_ZERO 0x172 90 + #define SWIM_TACHO 0x173 91 + #define SWIM_READ_DATA_1 0x174 92 + #define SWIM_MFM_MODE 0x175 93 + #define SWIM_SEEK_COMPLETE 0x176 94 + #define SWIM_ONEMEG_MEDIA 0x177 95 + 96 + /* Bits in handshake register */ 97 + 98 + #define SWIM_MARK_BYTE 0x01 99 + #define SWIM_CRC_ZERO 0x02 100 + #define SWIM_RDDATA 0x04 101 + #define SWIM_SENSE 0x08 102 + #define SWIM_MOTEN 0x10 103 + #define SWIM_ERROR 0x20 104 + #define SWIM_DAT2BYTE 0x40 105 + #define SWIM_DAT1BYTE 0x80 106 + 107 + /* bits in setup register */ 108 + 109 + #define SWIM_S_INV_WDATA 0x01 110 + #define SWIM_S_3_5_SELECT 0x02 111 + #define SWIM_S_GCR 0x04 112 + #define SWIM_S_FCLK_DIV2 0x08 113 + #define SWIM_S_ERROR_CORR 0x10 114 + #define SWIM_S_IBM_DRIVE 0x20 115 + #define SWIM_S_GCR_WRITE 0x40 116 + #define SWIM_S_TIMEOUT 0x80 117 + 118 + /* bits in mode register */ 119 + 120 + #define SWIM_CLFIFO 0x01 121 + #define SWIM_ENBL1 0x02 122 + #define SWIM_ENBL2 0x04 123 + #define SWIM_ACTION 0x08 124 + #define SWIM_WRITE_MODE 0x10 125 + #define SWIM_HEDSEL 0x20 126 + #define SWIM_MOTON 0x80 127 + 128 + static void fd_recalibrate(FDrive *drive) 129 + { 130 + } 131 + 132 + static void swim_change_cb(void *opaque, bool load, Error **errp) 133 + { 134 + FDrive *drive = opaque; 135 + 136 + if (!load) { 137 + blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort); 138 + } else { 139 + if (!blkconf_apply_backend_options(drive->conf, 140 + blk_is_read_only(drive->blk), false, 141 + errp)) { 142 + return; 143 + } 144 + } 145 + } 146 + 147 + static const BlockDevOps swim_block_ops = { 148 + .change_media_cb = swim_change_cb, 149 + }; 150 + 151 + static Property swim_drive_properties[] = { 152 + DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1), 153 + DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf), 154 + DEFINE_PROP_END_OF_LIST(), 155 + }; 156 + 157 + static void swim_drive_realize(DeviceState *qdev, Error **errp) 158 + { 159 + SWIMDrive *dev = SWIM_DRIVE(qdev); 160 + SWIMBus *bus = SWIM_BUS(qdev->parent_bus); 161 + FDrive *drive; 162 + int ret; 163 + 164 + if (dev->unit == -1) { 165 + for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) { 166 + drive = &bus->ctrl->drives[dev->unit]; 167 + if (!drive->blk) { 168 + break; 169 + } 170 + } 171 + } 172 + 173 + if (dev->unit >= SWIM_MAX_FD) { 174 + error_setg(errp, "Can't create floppy unit %d, bus supports " 175 + "only %d units", dev->unit, SWIM_MAX_FD); 176 + return; 177 + } 178 + 179 + drive = &bus->ctrl->drives[dev->unit]; 180 + if (drive->blk) { 181 + error_setg(errp, "Floppy unit %d is in use", dev->unit); 182 + return; 183 + } 184 + 185 + if (!dev->conf.blk) { 186 + /* Anonymous BlockBackend for an empty drive */ 187 + dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); 188 + ret = blk_attach_dev(dev->conf.blk, qdev); 189 + assert(ret == 0); 190 + } 191 + 192 + blkconf_blocksizes(&dev->conf); 193 + if (dev->conf.logical_block_size != 512 || 194 + dev->conf.physical_block_size != 512) 195 + { 196 + error_setg(errp, "Physical and logical block size must " 197 + "be 512 for floppy"); 198 + return; 199 + } 200 + 201 + /* 202 + * rerror/werror aren't supported by fdc and therefore not even registered 203 + * with qdev. So set the defaults manually before they are used in 204 + * blkconf_apply_backend_options(). 205 + */ 206 + dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO; 207 + dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO; 208 + 209 + if (!blkconf_apply_backend_options(&dev->conf, 210 + blk_is_read_only(dev->conf.blk), 211 + false, errp)) { 212 + return; 213 + } 214 + 215 + /* 216 + * 'enospc' is the default for -drive, 'report' is what blk_new() gives us 217 + * for empty drives. 218 + */ 219 + if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC && 220 + blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) { 221 + error_setg(errp, "fdc doesn't support drive option werror"); 222 + return; 223 + } 224 + if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { 225 + error_setg(errp, "fdc doesn't support drive option rerror"); 226 + return; 227 + } 228 + 229 + drive->conf = &dev->conf; 230 + drive->blk = dev->conf.blk; 231 + drive->swimctrl = bus->ctrl; 232 + 233 + blk_set_dev_ops(drive->blk, &swim_block_ops, drive); 234 + } 235 + 236 + static void swim_drive_class_init(ObjectClass *klass, void *data) 237 + { 238 + DeviceClass *k = DEVICE_CLASS(klass); 239 + k->realize = swim_drive_realize; 240 + set_bit(DEVICE_CATEGORY_STORAGE, k->categories); 241 + k->bus_type = TYPE_SWIM_BUS; 242 + k->props = swim_drive_properties; 243 + k->desc = "virtual SWIM drive"; 244 + } 245 + 246 + static const TypeInfo swim_drive_info = { 247 + .name = TYPE_SWIM_DRIVE, 248 + .parent = TYPE_DEVICE, 249 + .instance_size = sizeof(SWIMDrive), 250 + .class_init = swim_drive_class_init, 251 + }; 252 + 253 + static const TypeInfo swim_bus_info = { 254 + .name = TYPE_SWIM_BUS, 255 + .parent = TYPE_BUS, 256 + .instance_size = sizeof(SWIMBus), 257 + }; 258 + 259 + static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, 260 + unsigned size) 261 + { 262 + SWIMCtrl *swimctrl = opaque; 263 + 264 + reg >>= REG_SHIFT; 265 + 266 + swimctrl->regs[reg >> 1] = reg & 1; 267 + 268 + if (swimctrl->regs[IWM_Q6] && 269 + swimctrl->regs[IWM_Q7]) { 270 + if (swimctrl->regs[IWM_MTR]) { 271 + /* data register */ 272 + swimctrl->iwm_data = value; 273 + } else { 274 + /* mode register */ 275 + swimctrl->iwm_mode = value; 276 + /* detect sequence to switch from IWM mode to SWIM mode */ 277 + switch (swimctrl->iwm_switch) { 278 + case 0: 279 + if (value == 0x57) { 280 + swimctrl->iwm_switch++; 281 + } 282 + break; 283 + case 1: 284 + if (value == 0x17) { 285 + swimctrl->iwm_switch++; 286 + } 287 + break; 288 + case 2: 289 + if (value == 0x57) { 290 + swimctrl->iwm_switch++; 291 + } 292 + break; 293 + case 3: 294 + if (value == 0x57) { 295 + swimctrl->mode = SWIM_MODE_SWIM; 296 + swimctrl->iwm_switch = 0; 297 + } 298 + break; 299 + } 300 + } 301 + } 302 + } 303 + 304 + static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size) 305 + { 306 + SWIMCtrl *swimctrl = opaque; 307 + 308 + reg >>= REG_SHIFT; 309 + 310 + swimctrl->regs[reg >> 1] = reg & 1; 311 + 312 + return 0; 313 + } 314 + 315 + static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value, 316 + unsigned size) 317 + { 318 + SWIMCtrl *swimctrl = opaque; 319 + 320 + if (swimctrl->mode == SWIM_MODE_IWM) { 321 + iwmctrl_write(opaque, reg, value, size); 322 + return; 323 + } 324 + 325 + reg >>= REG_SHIFT; 326 + 327 + switch (reg) { 328 + case SWIM_WRITE_PHASE: 329 + swimctrl->swim_phase = value; 330 + break; 331 + case SWIM_WRITE_MODE0: 332 + swimctrl->swim_mode &= ~value; 333 + break; 334 + case SWIM_WRITE_MODE1: 335 + swimctrl->swim_mode |= value; 336 + break; 337 + case SWIM_WRITE_DATA: 338 + case SWIM_WRITE_MARK: 339 + case SWIM_WRITE_CRC: 340 + case SWIM_WRITE_PARAMETER: 341 + case SWIM_WRITE_SETUP: 342 + break; 343 + } 344 + } 345 + 346 + static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size) 347 + { 348 + SWIMCtrl *swimctrl = opaque; 349 + uint32_t value = 0; 350 + 351 + if (swimctrl->mode == SWIM_MODE_IWM) { 352 + return iwmctrl_read(opaque, reg, size); 353 + } 354 + 355 + reg >>= REG_SHIFT; 356 + 357 + switch (reg) { 358 + case SWIM_READ_PHASE: 359 + value = swimctrl->swim_phase; 360 + break; 361 + case SWIM_READ_HANDSHAKE: 362 + if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) { 363 + /* always answer "no drive present" */ 364 + value = SWIM_SENSE; 365 + } 366 + break; 367 + case SWIM_READ_DATA: 368 + case SWIM_READ_MARK: 369 + case SWIM_READ_ERROR: 370 + case SWIM_READ_PARAMETER: 371 + case SWIM_READ_SETUP: 372 + case SWIM_READ_STATUS: 373 + break; 374 + } 375 + 376 + return value; 377 + } 378 + 379 + static const MemoryRegionOps swimctrl_mem_ops = { 380 + .write = swimctrl_write, 381 + .read = swimctrl_read, 382 + .endianness = DEVICE_NATIVE_ENDIAN, 383 + }; 384 + 385 + static void sysbus_swim_reset(DeviceState *d) 386 + { 387 + SWIM *sys = SWIM(d); 388 + SWIMCtrl *ctrl = &sys->ctrl; 389 + int i; 390 + 391 + ctrl->mode = 0; 392 + ctrl->iwm_switch = 0; 393 + for (i = 0; i < 8; i++) { 394 + ctrl->regs[i] = 0; 395 + } 396 + ctrl->iwm_data = 0; 397 + ctrl->iwm_mode = 0; 398 + ctrl->swim_phase = 0; 399 + ctrl->swim_mode = 0; 400 + for (i = 0; i < SWIM_MAX_FD; i++) { 401 + fd_recalibrate(&ctrl->drives[i]); 402 + } 403 + } 404 + 405 + static void sysbus_swim_init(Object *obj) 406 + { 407 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 408 + SWIM *sbs = SWIM(obj); 409 + SWIMCtrl *swimctrl = &sbs->ctrl; 410 + 411 + memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl, 412 + "swim", 0x2000); 413 + sysbus_init_mmio(sbd, &swimctrl->iomem); 414 + } 415 + 416 + static void sysbus_swim_realize(DeviceState *dev, Error **errp) 417 + { 418 + SWIM *sys = SWIM(dev); 419 + SWIMCtrl *swimctrl = &sys->ctrl; 420 + 421 + qbus_create_inplace(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, 422 + NULL); 423 + swimctrl->bus.ctrl = swimctrl; 424 + } 425 + 426 + static const VMStateDescription vmstate_fdrive = { 427 + .name = "fdrive", 428 + .version_id = 1, 429 + .minimum_version_id = 1, 430 + .fields = (VMStateField[]) { 431 + VMSTATE_END_OF_LIST() 432 + }, 433 + }; 434 + 435 + static const VMStateDescription vmstate_swim = { 436 + .name = "swim", 437 + .version_id = 1, 438 + .minimum_version_id = 1, 439 + .fields = (VMStateField[]) { 440 + VMSTATE_INT32(mode, SWIMCtrl), 441 + /* IWM mode */ 442 + VMSTATE_INT32(iwm_switch, SWIMCtrl), 443 + VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8), 444 + VMSTATE_UINT8(iwm_data, SWIMCtrl), 445 + VMSTATE_UINT8(iwm_mode, SWIMCtrl), 446 + /* SWIM mode */ 447 + VMSTATE_UINT8(swim_phase, SWIMCtrl), 448 + VMSTATE_UINT8(swim_mode, SWIMCtrl), 449 + /* Drives */ 450 + VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1, 451 + vmstate_fdrive, FDrive), 452 + VMSTATE_END_OF_LIST() 453 + }, 454 + }; 455 + 456 + static const VMStateDescription vmstate_sysbus_swim = { 457 + .name = "SWIM", 458 + .version_id = 1, 459 + .fields = (VMStateField[]) { 460 + VMSTATE_STRUCT(ctrl, SWIM, 0, vmstate_swim, SWIMCtrl), 461 + VMSTATE_END_OF_LIST() 462 + } 463 + }; 464 + 465 + static void sysbus_swim_class_init(ObjectClass *oc, void *data) 466 + { 467 + DeviceClass *dc = DEVICE_CLASS(oc); 468 + 469 + dc->realize = sysbus_swim_realize; 470 + dc->reset = sysbus_swim_reset; 471 + dc->vmsd = &vmstate_sysbus_swim; 472 + } 473 + 474 + static const TypeInfo sysbus_swim_info = { 475 + .name = TYPE_SWIM, 476 + .parent = TYPE_SYS_BUS_DEVICE, 477 + .instance_size = sizeof(SWIM), 478 + .instance_init = sysbus_swim_init, 479 + .class_init = sysbus_swim_class_init, 480 + }; 481 + 482 + static void swim_register_types(void) 483 + { 484 + type_register_static(&sysbus_swim_info); 485 + type_register_static(&swim_bus_info); 486 + type_register_static(&swim_drive_info); 487 + } 488 + 489 + type_init(swim_register_types)
+5
hw/display/Kconfig
··· 132 132 select VGA 133 133 select BITBANG_I2C 134 134 select DDC 135 + 136 + config MACFB 137 + bool 138 + select FRAMEBUFFER 139 + depends on NUBUS
+1
hw/display/Makefile.objs
··· 26 26 common-obj-$(CONFIG_FRAMEBUFFER) += framebuffer.o 27 27 obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o 28 28 common-obj-$(CONFIG_ZAURUS) += tc6393xb.o 29 + common-obj-$(CONFIG_MACFB) += macfb.o 29 30 30 31 obj-$(CONFIG_MILKYMIST_TMU2) += milkymist-tmu2.o 31 32 milkymist-tmu2.o-cflags := $(X11_CFLAGS) $(OPENGL_CFLAGS)
+477
hw/display/macfb.c
··· 1 + /* 2 + * QEMU Motorola 680x0 Macintosh Video Card Emulation 3 + * Copyright (c) 2012-2018 Laurent Vivier 4 + * 5 + * some parts from QEMU G364 framebuffer Emulator. 6 + * Copyright (c) 2007-2011 Herve Poussineau 7 + * 8 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 + * See the COPYING file in the top-level directory. 10 + * 11 + */ 12 + 13 + #include "qemu/osdep.h" 14 + #include "qemu/units.h" 15 + #include "hw/sysbus.h" 16 + #include "ui/console.h" 17 + #include "ui/pixel_ops.h" 18 + #include "hw/nubus/nubus.h" 19 + #include "hw/display/macfb.h" 20 + #include "qapi/error.h" 21 + #include "hw/qdev-properties.h" 22 + #include "migration/vmstate.h" 23 + 24 + #define VIDEO_BASE 0x00001000 25 + #define DAFB_BASE 0x00800000 26 + 27 + #define MACFB_PAGE_SIZE 4096 28 + #define MACFB_VRAM_SIZE (4 * MiB) 29 + 30 + #define DAFB_RESET 0x200 31 + #define DAFB_LUT 0x213 32 + 33 + 34 + typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr, 35 + int width); 36 + 37 + static inline uint8_t macfb_read_byte(MacfbState *s, uint32_t addr) 38 + { 39 + return s->vram[addr & s->vram_bit_mask]; 40 + } 41 + 42 + /* 1-bit color */ 43 + static void macfb_draw_line1(MacfbState *s, uint8_t *d, uint32_t addr, 44 + int width) 45 + { 46 + uint8_t r, g, b; 47 + int x; 48 + 49 + for (x = 0; x < width; x++) { 50 + int bit = x & 7; 51 + int idx = (macfb_read_byte(s, addr) >> (7 - bit)) & 1; 52 + r = g = b = ((1 - idx) << 7); 53 + addr += (bit == 7); 54 + 55 + *(uint32_t *)d = rgb_to_pixel32(r, g, b); 56 + d += 4; 57 + } 58 + } 59 + 60 + /* 2-bit color */ 61 + static void macfb_draw_line2(MacfbState *s, uint8_t *d, uint32_t addr, 62 + int width) 63 + { 64 + uint8_t r, g, b; 65 + int x; 66 + 67 + for (x = 0; x < width; x++) { 68 + int bit = (x & 3); 69 + int idx = (macfb_read_byte(s, addr) >> ((3 - bit) << 1)) & 3; 70 + r = s->color_palette[idx * 3]; 71 + g = s->color_palette[idx * 3 + 1]; 72 + b = s->color_palette[idx * 3 + 2]; 73 + addr += (bit == 3); 74 + 75 + *(uint32_t *)d = rgb_to_pixel32(r, g, b); 76 + d += 4; 77 + } 78 + } 79 + 80 + /* 4-bit color */ 81 + static void macfb_draw_line4(MacfbState *s, uint8_t *d, uint32_t addr, 82 + int width) 83 + { 84 + uint8_t r, g, b; 85 + int x; 86 + 87 + for (x = 0; x < width; x++) { 88 + int bit = x & 1; 89 + int idx = (macfb_read_byte(s, addr) >> ((1 - bit) << 2)) & 15; 90 + r = s->color_palette[idx * 3]; 91 + g = s->color_palette[idx * 3 + 1]; 92 + b = s->color_palette[idx * 3 + 2]; 93 + addr += (bit == 1); 94 + 95 + *(uint32_t *)d = rgb_to_pixel32(r, g, b); 96 + d += 4; 97 + } 98 + } 99 + 100 + /* 8-bit color */ 101 + static void macfb_draw_line8(MacfbState *s, uint8_t *d, uint32_t addr, 102 + int width) 103 + { 104 + uint8_t r, g, b; 105 + int x; 106 + 107 + for (x = 0; x < width; x++) { 108 + r = s->color_palette[macfb_read_byte(s, addr) * 3]; 109 + g = s->color_palette[macfb_read_byte(s, addr) * 3 + 1]; 110 + b = s->color_palette[macfb_read_byte(s, addr) * 3 + 2]; 111 + addr++; 112 + 113 + *(uint32_t *)d = rgb_to_pixel32(r, g, b); 114 + d += 4; 115 + } 116 + } 117 + 118 + /* 16-bit color */ 119 + static void macfb_draw_line16(MacfbState *s, uint8_t *d, uint32_t addr, 120 + int width) 121 + { 122 + uint8_t r, g, b; 123 + int x; 124 + 125 + for (x = 0; x < width; x++) { 126 + uint16_t pixel; 127 + pixel = (macfb_read_byte(s, addr) << 8) | macfb_read_byte(s, addr + 1); 128 + r = ((pixel >> 10) & 0x1f) << 3; 129 + g = ((pixel >> 5) & 0x1f) << 3; 130 + b = (pixel & 0x1f) << 3; 131 + addr += 2; 132 + 133 + *(uint32_t *)d = rgb_to_pixel32(r, g, b); 134 + d += 4; 135 + } 136 + } 137 + 138 + /* 24-bit color */ 139 + static void macfb_draw_line24(MacfbState *s, uint8_t *d, uint32_t addr, 140 + int width) 141 + { 142 + uint8_t r, g, b; 143 + int x; 144 + 145 + for (x = 0; x < width; x++) { 146 + r = macfb_read_byte(s, addr); 147 + g = macfb_read_byte(s, addr + 1); 148 + b = macfb_read_byte(s, addr + 2); 149 + addr += 3; 150 + 151 + *(uint32_t *)d = rgb_to_pixel32(r, g, b); 152 + d += 4; 153 + } 154 + } 155 + 156 + 157 + enum { 158 + MACFB_DRAW_LINE1, 159 + MACFB_DRAW_LINE2, 160 + MACFB_DRAW_LINE4, 161 + MACFB_DRAW_LINE8, 162 + MACFB_DRAW_LINE16, 163 + MACFB_DRAW_LINE24, 164 + MACFB_DRAW_LINE_NB, 165 + }; 166 + 167 + static macfb_draw_line_func * const 168 + macfb_draw_line_table[MACFB_DRAW_LINE_NB] = { 169 + macfb_draw_line1, 170 + macfb_draw_line2, 171 + macfb_draw_line4, 172 + macfb_draw_line8, 173 + macfb_draw_line16, 174 + macfb_draw_line24, 175 + }; 176 + 177 + static int macfb_check_dirty(MacfbState *s, DirtyBitmapSnapshot *snap, 178 + ram_addr_t addr, int len) 179 + { 180 + return memory_region_snapshot_get_dirty(&s->mem_vram, snap, addr, len); 181 + } 182 + 183 + static void macfb_draw_graphic(MacfbState *s) 184 + { 185 + DisplaySurface *surface = qemu_console_surface(s->con); 186 + DirtyBitmapSnapshot *snap = NULL; 187 + ram_addr_t page; 188 + uint32_t v = 0; 189 + int y, ymin; 190 + int macfb_stride = (s->depth * s->width + 7) / 8; 191 + macfb_draw_line_func *macfb_draw_line; 192 + 193 + switch (s->depth) { 194 + case 1: 195 + v = MACFB_DRAW_LINE1; 196 + break; 197 + case 2: 198 + v = MACFB_DRAW_LINE2; 199 + break; 200 + case 4: 201 + v = MACFB_DRAW_LINE4; 202 + break; 203 + case 8: 204 + v = MACFB_DRAW_LINE8; 205 + break; 206 + case 16: 207 + v = MACFB_DRAW_LINE16; 208 + break; 209 + case 24: 210 + v = MACFB_DRAW_LINE24; 211 + break; 212 + } 213 + 214 + macfb_draw_line = macfb_draw_line_table[v]; 215 + assert(macfb_draw_line != NULL); 216 + 217 + snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0x0, 218 + memory_region_size(&s->mem_vram), 219 + DIRTY_MEMORY_VGA); 220 + 221 + ymin = -1; 222 + page = 0; 223 + for (y = 0; y < s->height; y++, page += macfb_stride) { 224 + if (macfb_check_dirty(s, snap, page, macfb_stride)) { 225 + uint8_t *data_display; 226 + 227 + data_display = surface_data(surface) + y * surface_stride(surface); 228 + macfb_draw_line(s, data_display, page, s->width); 229 + 230 + if (ymin < 0) { 231 + ymin = y; 232 + } 233 + } else { 234 + if (ymin >= 0) { 235 + dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin); 236 + ymin = -1; 237 + } 238 + } 239 + } 240 + 241 + if (ymin >= 0) { 242 + dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin); 243 + } 244 + 245 + g_free(snap); 246 + } 247 + 248 + static void macfb_invalidate_display(void *opaque) 249 + { 250 + MacfbState *s = opaque; 251 + 252 + memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE); 253 + } 254 + 255 + static void macfb_update_display(void *opaque) 256 + { 257 + MacfbState *s = opaque; 258 + DisplaySurface *surface = qemu_console_surface(s->con); 259 + 260 + qemu_flush_coalesced_mmio_buffer(); 261 + 262 + if (s->width == 0 || s->height == 0) { 263 + return; 264 + } 265 + 266 + if (s->width != surface_width(surface) || 267 + s->height != surface_height(surface)) { 268 + qemu_console_resize(s->con, s->width, s->height); 269 + } 270 + 271 + macfb_draw_graphic(s); 272 + } 273 + 274 + static void macfb_reset(MacfbState *s) 275 + { 276 + int i; 277 + 278 + s->palette_current = 0; 279 + for (i = 0; i < 256; i++) { 280 + s->color_palette[i * 3] = 255 - i; 281 + s->color_palette[i * 3 + 1] = 255 - i; 282 + s->color_palette[i * 3 + 2] = 255 - i; 283 + } 284 + memset(s->vram, 0, MACFB_VRAM_SIZE); 285 + macfb_invalidate_display(s); 286 + } 287 + 288 + static uint64_t macfb_ctrl_read(void *opaque, 289 + hwaddr addr, 290 + unsigned int size) 291 + { 292 + return 0; 293 + } 294 + 295 + static void macfb_ctrl_write(void *opaque, 296 + hwaddr addr, 297 + uint64_t val, 298 + unsigned int size) 299 + { 300 + MacfbState *s = opaque; 301 + switch (addr) { 302 + case DAFB_RESET: 303 + s->palette_current = 0; 304 + break; 305 + case DAFB_LUT: 306 + s->color_palette[s->palette_current++] = val; 307 + if (s->palette_current % 3) { 308 + macfb_invalidate_display(s); 309 + } 310 + break; 311 + } 312 + } 313 + 314 + static const MemoryRegionOps macfb_ctrl_ops = { 315 + .read = macfb_ctrl_read, 316 + .write = macfb_ctrl_write, 317 + .endianness = DEVICE_BIG_ENDIAN, 318 + .impl.min_access_size = 1, 319 + .impl.max_access_size = 4, 320 + }; 321 + 322 + static int macfb_post_load(void *opaque, int version_id) 323 + { 324 + macfb_invalidate_display(opaque); 325 + return 0; 326 + } 327 + 328 + static const VMStateDescription vmstate_macfb = { 329 + .name = "macfb", 330 + .version_id = 1, 331 + .minimum_version_id = 1, 332 + .minimum_version_id_old = 1, 333 + .post_load = macfb_post_load, 334 + .fields = (VMStateField[]) { 335 + VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3), 336 + VMSTATE_UINT32(palette_current, MacfbState), 337 + VMSTATE_END_OF_LIST() 338 + } 339 + }; 340 + 341 + static const GraphicHwOps macfb_ops = { 342 + .invalidate = macfb_invalidate_display, 343 + .gfx_update = macfb_update_display, 344 + }; 345 + 346 + static void macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp) 347 + { 348 + DisplaySurface *surface; 349 + 350 + if (s->depth != 1 && s->depth != 2 && s->depth != 4 && s->depth != 8 && 351 + s->depth != 16 && s->depth != 24) { 352 + error_setg(errp, "unknown guest depth %d", s->depth); 353 + return; 354 + } 355 + 356 + s->con = graphic_console_init(dev, 0, &macfb_ops, s); 357 + surface = qemu_console_surface(s->con); 358 + 359 + if (surface_bits_per_pixel(surface) != 32) { 360 + error_setg(errp, "unknown host depth %d", 361 + surface_bits_per_pixel(surface)); 362 + return; 363 + } 364 + 365 + memory_region_init_io(&s->mem_ctrl, NULL, &macfb_ctrl_ops, s, "macfb-ctrl", 366 + 0x1000); 367 + 368 + memory_region_init_ram_nomigrate(&s->mem_vram, OBJECT(s), "macfb-vram", 369 + MACFB_VRAM_SIZE, errp); 370 + s->vram = memory_region_get_ram_ptr(&s->mem_vram); 371 + s->vram_bit_mask = MACFB_VRAM_SIZE - 1; 372 + vmstate_register_ram(&s->mem_vram, dev); 373 + memory_region_set_coalescing(&s->mem_vram); 374 + } 375 + 376 + static void macfb_sysbus_realize(DeviceState *dev, Error **errp) 377 + { 378 + MacfbSysBusState *s = MACFB(dev); 379 + MacfbState *ms = &s->macfb; 380 + 381 + macfb_common_realize(dev, ms, errp); 382 + sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl); 383 + sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram); 384 + } 385 + 386 + const uint8_t macfb_rom[] = { 387 + 255, 0, 0, 0, 388 + }; 389 + 390 + static void macfb_nubus_realize(DeviceState *dev, Error **errp) 391 + { 392 + NubusDevice *nd = NUBUS_DEVICE(dev); 393 + MacfbNubusState *s = NUBUS_MACFB(dev); 394 + MacfbNubusDeviceClass *ndc = MACFB_NUBUS_GET_CLASS(dev); 395 + MacfbState *ms = &s->macfb; 396 + 397 + ndc->parent_realize(dev, errp); 398 + 399 + macfb_common_realize(dev, ms, errp); 400 + memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl); 401 + memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram); 402 + 403 + nubus_register_rom(nd, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf); 404 + } 405 + 406 + static void macfb_sysbus_reset(DeviceState *d) 407 + { 408 + MacfbSysBusState *s = MACFB(d); 409 + macfb_reset(&s->macfb); 410 + } 411 + 412 + static void macfb_nubus_reset(DeviceState *d) 413 + { 414 + MacfbNubusState *s = NUBUS_MACFB(d); 415 + macfb_reset(&s->macfb); 416 + } 417 + 418 + static Property macfb_sysbus_properties[] = { 419 + DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640), 420 + DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480), 421 + DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8), 422 + DEFINE_PROP_END_OF_LIST(), 423 + }; 424 + 425 + static Property macfb_nubus_properties[] = { 426 + DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640), 427 + DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480), 428 + DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8), 429 + DEFINE_PROP_END_OF_LIST(), 430 + }; 431 + 432 + static void macfb_sysbus_class_init(ObjectClass *klass, void *data) 433 + { 434 + DeviceClass *dc = DEVICE_CLASS(klass); 435 + 436 + dc->realize = macfb_sysbus_realize; 437 + dc->desc = "SysBus Macintosh framebuffer"; 438 + dc->reset = macfb_sysbus_reset; 439 + dc->vmsd = &vmstate_macfb; 440 + dc->props = macfb_sysbus_properties; 441 + } 442 + 443 + static void macfb_nubus_class_init(ObjectClass *klass, void *data) 444 + { 445 + DeviceClass *dc = DEVICE_CLASS(klass); 446 + MacfbNubusDeviceClass *ndc = MACFB_NUBUS_DEVICE_CLASS(klass); 447 + 448 + device_class_set_parent_realize(dc, macfb_nubus_realize, 449 + &ndc->parent_realize); 450 + dc->desc = "Nubus Macintosh framebuffer"; 451 + dc->reset = macfb_nubus_reset; 452 + dc->vmsd = &vmstate_macfb; 453 + dc->props = macfb_nubus_properties; 454 + } 455 + 456 + static TypeInfo macfb_sysbus_info = { 457 + .name = TYPE_MACFB, 458 + .parent = TYPE_SYS_BUS_DEVICE, 459 + .instance_size = sizeof(MacfbSysBusState), 460 + .class_init = macfb_sysbus_class_init, 461 + }; 462 + 463 + static TypeInfo macfb_nubus_info = { 464 + .name = TYPE_NUBUS_MACFB, 465 + .parent = TYPE_NUBUS_DEVICE, 466 + .instance_size = sizeof(MacfbNubusState), 467 + .class_init = macfb_nubus_class_init, 468 + .class_size = sizeof(MacfbNubusDeviceClass), 469 + }; 470 + 471 + static void macfb_register_types(void) 472 + { 473 + type_register_static(&macfb_sysbus_info); 474 + type_register_static(&macfb_nubus_info); 475 + } 476 + 477 + type_init(macfb_register_types)
+10
hw/m68k/Kconfig
··· 12 12 bool 13 13 select FRAMEBUFFER 14 14 select ESCC 15 + 16 + config Q800 17 + bool 18 + select MAC_VIA 19 + select NUBUS 20 + select MACFB 21 + select SWIM 22 + select ESCC 23 + select ESP 24 + select DP8393X
+1
hw/m68k/Makefile.objs
··· 1 1 obj-$(CONFIG_AN5206) += an5206.o mcf5206.o 2 2 obj-$(CONFIG_MCF5208) += mcf5208.o mcf_intc.o 3 3 obj-$(CONFIG_NEXTCUBE) += next-kbd.o next-cube.o 4 + obj-$(CONFIG_Q800) += q800.o
+114
hw/m68k/bootinfo.h
··· 1 + /* 2 + * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note 3 + * 4 + * Bootinfo tags from linux bootinfo.h and bootinfo-mac.h: 5 + * This is an easily parsable and extendable structure containing all 6 + * information to be passed from the bootstrap to the kernel 7 + * 8 + * This structure is copied right after the kernel by the bootstrap 9 + * routine. 10 + */ 11 + 12 + #ifndef HW_M68K_BOOTINFO_H 13 + #define HW_M68K_BOOTINFO_H 14 + struct bi_record { 15 + uint16_t tag; /* tag ID */ 16 + uint16_t size; /* size of record */ 17 + uint32_t data[0]; /* data */ 18 + }; 19 + 20 + /* machine independent tags */ 21 + 22 + #define BI_LAST 0x0000 /* last record */ 23 + #define BI_MACHTYPE 0x0001 /* machine type (u_long) */ 24 + #define BI_CPUTYPE 0x0002 /* cpu type (u_long) */ 25 + #define BI_FPUTYPE 0x0003 /* fpu type (u_long) */ 26 + #define BI_MMUTYPE 0x0004 /* mmu type (u_long) */ 27 + #define BI_MEMCHUNK 0x0005 /* memory chunk address and size */ 28 + /* (struct mem_info) */ 29 + #define BI_RAMDISK 0x0006 /* ramdisk address and size */ 30 + /* (struct mem_info) */ 31 + #define BI_COMMAND_LINE 0x0007 /* kernel command line parameters */ 32 + /* (string) */ 33 + 34 + /* Macintosh-specific tags (all u_long) */ 35 + 36 + #define BI_MAC_MODEL 0x8000 /* Mac Gestalt ID (model type) */ 37 + #define BI_MAC_VADDR 0x8001 /* Mac video base address */ 38 + #define BI_MAC_VDEPTH 0x8002 /* Mac video depth */ 39 + #define BI_MAC_VROW 0x8003 /* Mac video rowbytes */ 40 + #define BI_MAC_VDIM 0x8004 /* Mac video dimensions */ 41 + #define BI_MAC_VLOGICAL 0x8005 /* Mac video logical base */ 42 + #define BI_MAC_SCCBASE 0x8006 /* Mac SCC base address */ 43 + #define BI_MAC_BTIME 0x8007 /* Mac boot time */ 44 + #define BI_MAC_GMTBIAS 0x8008 /* Mac GMT timezone offset */ 45 + #define BI_MAC_MEMSIZE 0x8009 /* Mac RAM size (sanity check) */ 46 + #define BI_MAC_CPUID 0x800a /* Mac CPU type (sanity check) */ 47 + #define BI_MAC_ROMBASE 0x800b /* Mac system ROM base address */ 48 + 49 + /* Macintosh hardware profile data */ 50 + 51 + #define BI_MAC_VIA1BASE 0x8010 /* Mac VIA1 base address (always present) */ 52 + #define BI_MAC_VIA2BASE 0x8011 /* Mac VIA2 base address (type varies) */ 53 + #define BI_MAC_VIA2TYPE 0x8012 /* Mac VIA2 type (VIA, RBV, OSS) */ 54 + #define BI_MAC_ADBTYPE 0x8013 /* Mac ADB interface type */ 55 + #define BI_MAC_ASCBASE 0x8014 /* Mac Apple Sound Chip base address */ 56 + #define BI_MAC_SCSI5380 0x8015 /* Mac NCR 5380 SCSI (base address, multi) */ 57 + #define BI_MAC_SCSIDMA 0x8016 /* Mac SCSI DMA (base address) */ 58 + #define BI_MAC_SCSI5396 0x8017 /* Mac NCR 53C96 SCSI (base address, multi) */ 59 + #define BI_MAC_IDETYPE 0x8018 /* Mac IDE interface type */ 60 + #define BI_MAC_IDEBASE 0x8019 /* Mac IDE interface base address */ 61 + #define BI_MAC_NUBUS 0x801a /* Mac Nubus type (none, regular, pseudo) */ 62 + #define BI_MAC_SLOTMASK 0x801b /* Mac Nubus slots present */ 63 + #define BI_MAC_SCCTYPE 0x801c /* Mac SCC serial type (normal, IOP) */ 64 + #define BI_MAC_ETHTYPE 0x801d /* Mac builtin ethernet type (Sonic, MACE */ 65 + #define BI_MAC_ETHBASE 0x801e /* Mac builtin ethernet base address */ 66 + #define BI_MAC_PMU 0x801f /* Mac power management / poweroff hardware */ 67 + #define BI_MAC_IOP_SWIM 0x8020 /* Mac SWIM floppy IOP */ 68 + #define BI_MAC_IOP_ADB 0x8021 /* Mac ADB IOP */ 69 + 70 + #define BOOTINFO0(as, base, id) \ 71 + do { \ 72 + stw_phys(as, base, id); \ 73 + base += 2; \ 74 + stw_phys(as, base, sizeof(struct bi_record)); \ 75 + base += 2; \ 76 + } while (0) 77 + 78 + #define BOOTINFO1(as, base, id, value) \ 79 + do { \ 80 + stw_phys(as, base, id); \ 81 + base += 2; \ 82 + stw_phys(as, base, sizeof(struct bi_record) + 4); \ 83 + base += 2; \ 84 + stl_phys(as, base, value); \ 85 + base += 4; \ 86 + } while (0) 87 + 88 + #define BOOTINFO2(as, base, id, value1, value2) \ 89 + do { \ 90 + stw_phys(as, base, id); \ 91 + base += 2; \ 92 + stw_phys(as, base, sizeof(struct bi_record) + 8); \ 93 + base += 2; \ 94 + stl_phys(as, base, value1); \ 95 + base += 4; \ 96 + stl_phys(as, base, value2); \ 97 + base += 4; \ 98 + } while (0) 99 + 100 + #define BOOTINFOSTR(as, base, id, string) \ 101 + do { \ 102 + int i; \ 103 + stw_phys(as, base, id); \ 104 + base += 2; \ 105 + stw_phys(as, base, \ 106 + (sizeof(struct bi_record) + strlen(string) + 2) & ~1); \ 107 + base += 2; \ 108 + for (i = 0; string[i]; i++) { \ 109 + stb_phys(as, base++, string[i]); \ 110 + } \ 111 + stb_phys(as, base++, 0); \ 112 + base = (parameters_base + 1) & ~1; \ 113 + } while (0) 114 + #endif
+401
hw/m68k/q800.c
··· 1 + /* 2 + * QEMU Motorla 680x0 Macintosh hardware System Emulator 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a copy 5 + * of this software and associated documentation files (the "Software"), to deal 6 + * in the Software without restriction, including without limitation the rights 7 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 + * copies of the Software, and to permit persons to whom the Software is 9 + * furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice shall be included in 12 + * all copies or substantial portions of the Software. 13 + * 14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 + * THE SOFTWARE. 21 + */ 22 + 23 + #include "qemu/osdep.h" 24 + #include "qemu/units.h" 25 + #include "qemu-common.h" 26 + #include "sysemu/sysemu.h" 27 + #include "cpu.h" 28 + #include "hw/hw.h" 29 + #include "hw/boards.h" 30 + #include "hw/irq.h" 31 + #include "elf.h" 32 + #include "hw/loader.h" 33 + #include "ui/console.h" 34 + #include "exec/address-spaces.h" 35 + #include "hw/char/escc.h" 36 + #include "hw/sysbus.h" 37 + #include "hw/scsi/esp.h" 38 + #include "bootinfo.h" 39 + #include "hw/misc/mac_via.h" 40 + #include "hw/input/adb.h" 41 + #include "hw/nubus/mac-nubus-bridge.h" 42 + #include "hw/display/macfb.h" 43 + #include "hw/block/swim.h" 44 + #include "net/net.h" 45 + #include "qapi/error.h" 46 + #include "sysemu/qtest.h" 47 + #include "sysemu/runstate.h" 48 + #include "sysemu/reset.h" 49 + 50 + #define MACROM_ADDR 0x40000000 51 + #define MACROM_SIZE 0x00100000 52 + 53 + #define MACROM_FILENAME "MacROM.bin" 54 + 55 + #define Q800_MACHINE_ID 35 56 + #define Q800_CPU_ID (1 << 2) 57 + #define Q800_FPU_ID (1 << 2) 58 + #define Q800_MMU_ID (1 << 2) 59 + 60 + #define MACH_MAC 3 61 + #define Q800_MAC_CPU_ID 2 62 + 63 + #define VIA_BASE 0x50f00000 64 + #define SONIC_PROM_BASE 0x50f08000 65 + #define SONIC_BASE 0x50f0a000 66 + #define SCC_BASE 0x50f0c020 67 + #define ESP_BASE 0x50f10000 68 + #define ESP_PDMA 0x50f10100 69 + #define ASC_BASE 0x50F14000 70 + #define SWIM_BASE 0x50F1E000 71 + #define NUBUS_SUPER_SLOT_BASE 0x60000000 72 + #define NUBUS_SLOT_BASE 0xf0000000 73 + 74 + /* 75 + * the video base, whereas it a Nubus address, 76 + * is needed by the kernel to have early display and 77 + * thus provided by the bootloader 78 + */ 79 + #define VIDEO_BASE 0xf9001000 80 + 81 + #define MAC_CLOCK 3686418 82 + 83 + /* 84 + * The GLUE (General Logic Unit) is an Apple custom integrated circuit chip 85 + * that performs a variety of functions (RAM management, clock generation, ...). 86 + * The GLUE chip receives interrupt requests from various devices, 87 + * assign priority to each, and asserts one or more interrupt line to the 88 + * CPU. 89 + */ 90 + 91 + typedef struct { 92 + M68kCPU *cpu; 93 + uint8_t ipr; 94 + } GLUEState; 95 + 96 + static void GLUE_set_irq(void *opaque, int irq, int level) 97 + { 98 + GLUEState *s = opaque; 99 + int i; 100 + 101 + if (level) { 102 + s->ipr |= 1 << irq; 103 + } else { 104 + s->ipr &= ~(1 << irq); 105 + } 106 + 107 + for (i = 7; i >= 0; i--) { 108 + if ((s->ipr >> i) & 1) { 109 + m68k_set_irq_level(s->cpu, i + 1, i + 25); 110 + return; 111 + } 112 + } 113 + m68k_set_irq_level(s->cpu, 0, 0); 114 + } 115 + 116 + static void main_cpu_reset(void *opaque) 117 + { 118 + M68kCPU *cpu = opaque; 119 + CPUState *cs = CPU(cpu); 120 + 121 + cpu_reset(cs); 122 + cpu->env.aregs[7] = ldl_phys(cs->as, 0); 123 + cpu->env.pc = ldl_phys(cs->as, 4); 124 + } 125 + 126 + static void q800_init(MachineState *machine) 127 + { 128 + M68kCPU *cpu = NULL; 129 + int linux_boot; 130 + int32_t kernel_size; 131 + uint64_t elf_entry; 132 + char *filename; 133 + int bios_size; 134 + ram_addr_t initrd_base; 135 + int32_t initrd_size; 136 + MemoryRegion *rom; 137 + MemoryRegion *ram; 138 + ram_addr_t ram_size = machine->ram_size; 139 + const char *kernel_filename = machine->kernel_filename; 140 + const char *initrd_filename = machine->initrd_filename; 141 + const char *kernel_cmdline = machine->kernel_cmdline; 142 + hwaddr parameters_base; 143 + CPUState *cs; 144 + DeviceState *dev; 145 + DeviceState *via_dev; 146 + SysBusESPState *sysbus_esp; 147 + ESPState *esp; 148 + SysBusDevice *sysbus; 149 + BusState *adb_bus; 150 + NubusBus *nubus; 151 + GLUEState *irq; 152 + qemu_irq *pic; 153 + 154 + linux_boot = (kernel_filename != NULL); 155 + 156 + if (ram_size > 1 * GiB) { 157 + error_report("Too much memory for this machine: %" PRId64 " MiB, " 158 + "maximum 1024 MiB", ram_size / MiB); 159 + exit(1); 160 + } 161 + 162 + /* init CPUs */ 163 + cpu = M68K_CPU(cpu_create(machine->cpu_type)); 164 + qemu_register_reset(main_cpu_reset, cpu); 165 + 166 + ram = g_malloc(sizeof(*ram)); 167 + memory_region_init_ram(ram, NULL, "m68k_mac.ram", ram_size, &error_abort); 168 + memory_region_add_subregion(get_system_memory(), 0, ram); 169 + 170 + /* IRQ Glue */ 171 + 172 + irq = g_new0(GLUEState, 1); 173 + irq->cpu = cpu; 174 + pic = qemu_allocate_irqs(GLUE_set_irq, irq, 8); 175 + 176 + /* VIA */ 177 + 178 + via_dev = qdev_create(NULL, TYPE_MAC_VIA); 179 + qdev_init_nofail(via_dev); 180 + sysbus = SYS_BUS_DEVICE(via_dev); 181 + sysbus_mmio_map(sysbus, 0, VIA_BASE); 182 + qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, pic[0]); 183 + qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1, pic[1]); 184 + 185 + 186 + adb_bus = qdev_get_child_bus(via_dev, "adb.0"); 187 + dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); 188 + qdev_init_nofail(dev); 189 + dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); 190 + qdev_init_nofail(dev); 191 + 192 + /* MACSONIC */ 193 + 194 + if (nb_nics > 1) { 195 + error_report("q800 can only have one ethernet interface"); 196 + exit(1); 197 + } 198 + 199 + qemu_check_nic_model(&nd_table[0], "dp83932"); 200 + 201 + /* 202 + * MacSonic driver needs an Apple MAC address 203 + * Valid prefix are: 204 + * 00:05:02 Apple 205 + * 00:80:19 Dayna Communications, Inc. 206 + * 00:A0:40 Apple 207 + * 08:00:07 Apple 208 + * (Q800 use the last one) 209 + */ 210 + nd_table[0].macaddr.a[0] = 0x08; 211 + nd_table[0].macaddr.a[1] = 0x00; 212 + nd_table[0].macaddr.a[2] = 0x07; 213 + 214 + dev = qdev_create(NULL, "dp8393x"); 215 + qdev_set_nic_properties(dev, &nd_table[0]); 216 + qdev_prop_set_uint8(dev, "it_shift", 2); 217 + qdev_prop_set_bit(dev, "big_endian", true); 218 + qdev_prop_set_ptr(dev, "dma_mr", get_system_memory()); 219 + qdev_init_nofail(dev); 220 + sysbus = SYS_BUS_DEVICE(dev); 221 + sysbus_mmio_map(sysbus, 0, SONIC_BASE); 222 + sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE); 223 + sysbus_connect_irq(sysbus, 0, pic[2]); 224 + 225 + /* SCC */ 226 + 227 + dev = qdev_create(NULL, TYPE_ESCC); 228 + qdev_prop_set_uint32(dev, "disabled", 0); 229 + qdev_prop_set_uint32(dev, "frequency", MAC_CLOCK); 230 + qdev_prop_set_uint32(dev, "it_shift", 1); 231 + qdev_prop_set_bit(dev, "bit_swap", true); 232 + qdev_prop_set_chr(dev, "chrA", serial_hd(0)); 233 + qdev_prop_set_chr(dev, "chrB", serial_hd(1)); 234 + qdev_prop_set_uint32(dev, "chnBtype", 0); 235 + qdev_prop_set_uint32(dev, "chnAtype", 0); 236 + qdev_init_nofail(dev); 237 + sysbus = SYS_BUS_DEVICE(dev); 238 + sysbus_connect_irq(sysbus, 0, pic[3]); 239 + sysbus_connect_irq(sysbus, 1, pic[3]); 240 + sysbus_mmio_map(sysbus, 0, SCC_BASE); 241 + 242 + /* SCSI */ 243 + 244 + dev = qdev_create(NULL, TYPE_ESP); 245 + sysbus_esp = ESP_STATE(dev); 246 + esp = &sysbus_esp->esp; 247 + esp->dma_memory_read = NULL; 248 + esp->dma_memory_write = NULL; 249 + esp->dma_opaque = NULL; 250 + sysbus_esp->it_shift = 4; 251 + esp->dma_enabled = 1; 252 + qdev_init_nofail(dev); 253 + 254 + sysbus = SYS_BUS_DEVICE(dev); 255 + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in_named(via_dev, 256 + "via2-irq", 257 + VIA2_IRQ_SCSI_BIT)); 258 + sysbus_connect_irq(sysbus, 1, 259 + qdev_get_gpio_in_named(via_dev, "via2-irq", 260 + VIA2_IRQ_SCSI_DATA_BIT)); 261 + sysbus_mmio_map(sysbus, 0, ESP_BASE); 262 + sysbus_mmio_map(sysbus, 1, ESP_PDMA); 263 + 264 + scsi_bus_legacy_handle_cmdline(&esp->bus); 265 + 266 + /* SWIM floppy controller */ 267 + 268 + dev = qdev_create(NULL, TYPE_SWIM); 269 + qdev_init_nofail(dev); 270 + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SWIM_BASE); 271 + 272 + /* NuBus */ 273 + 274 + dev = qdev_create(NULL, TYPE_MAC_NUBUS_BRIDGE); 275 + qdev_init_nofail(dev); 276 + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, NUBUS_SUPER_SLOT_BASE); 277 + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE); 278 + 279 + nubus = MAC_NUBUS_BRIDGE(dev)->bus; 280 + 281 + /* framebuffer in nubus slot #9 */ 282 + 283 + dev = qdev_create(BUS(nubus), TYPE_NUBUS_MACFB); 284 + qdev_prop_set_uint32(dev, "width", graphic_width); 285 + qdev_prop_set_uint32(dev, "height", graphic_height); 286 + qdev_prop_set_uint8(dev, "depth", graphic_depth); 287 + qdev_init_nofail(dev); 288 + 289 + cs = CPU(cpu); 290 + if (linux_boot) { 291 + uint64_t high; 292 + kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, 293 + &elf_entry, NULL, &high, 1, 294 + EM_68K, 0, 0); 295 + if (kernel_size < 0) { 296 + error_report("could not load kernel '%s'", kernel_filename); 297 + exit(1); 298 + } 299 + stl_phys(cs->as, 4, elf_entry); /* reset initial PC */ 300 + parameters_base = (high + 1) & ~1; 301 + 302 + BOOTINFO1(cs->as, parameters_base, BI_MACHTYPE, MACH_MAC); 303 + BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, Q800_FPU_ID); 304 + BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, Q800_MMU_ID); 305 + BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, Q800_CPU_ID); 306 + BOOTINFO1(cs->as, parameters_base, BI_MAC_CPUID, Q800_MAC_CPU_ID); 307 + BOOTINFO1(cs->as, parameters_base, BI_MAC_MODEL, Q800_MACHINE_ID); 308 + BOOTINFO1(cs->as, parameters_base, 309 + BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */ 310 + BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size); 311 + BOOTINFO1(cs->as, parameters_base, BI_MAC_VADDR, VIDEO_BASE); 312 + BOOTINFO1(cs->as, parameters_base, BI_MAC_VDEPTH, graphic_depth); 313 + BOOTINFO1(cs->as, parameters_base, BI_MAC_VDIM, 314 + (graphic_height << 16) | graphic_width); 315 + BOOTINFO1(cs->as, parameters_base, BI_MAC_VROW, 316 + (graphic_width * graphic_depth + 7) / 8); 317 + BOOTINFO1(cs->as, parameters_base, BI_MAC_SCCBASE, SCC_BASE); 318 + 319 + if (kernel_cmdline) { 320 + BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE, 321 + kernel_cmdline); 322 + } 323 + 324 + /* load initrd */ 325 + if (initrd_filename) { 326 + initrd_size = get_image_size(initrd_filename); 327 + if (initrd_size < 0) { 328 + error_report("could not load initial ram disk '%s'", 329 + initrd_filename); 330 + exit(1); 331 + } 332 + 333 + initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; 334 + load_image_targphys(initrd_filename, initrd_base, 335 + ram_size - initrd_base); 336 + BOOTINFO2(cs->as, parameters_base, BI_RAMDISK, initrd_base, 337 + initrd_size); 338 + } else { 339 + initrd_base = 0; 340 + initrd_size = 0; 341 + } 342 + BOOTINFO0(cs->as, parameters_base, BI_LAST); 343 + } else { 344 + uint8_t *ptr; 345 + /* allocate and load BIOS */ 346 + rom = g_malloc(sizeof(*rom)); 347 + memory_region_init_ram(rom, NULL, "m68k_mac.rom", MACROM_SIZE, 348 + &error_abort); 349 + if (bios_name == NULL) { 350 + bios_name = MACROM_FILENAME; 351 + } 352 + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 353 + memory_region_set_readonly(rom, true); 354 + memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom); 355 + 356 + /* Load MacROM binary */ 357 + if (filename) { 358 + bios_size = load_image_targphys(filename, MACROM_ADDR, MACROM_SIZE); 359 + g_free(filename); 360 + } else { 361 + bios_size = -1; 362 + } 363 + 364 + /* Remove qtest_enabled() check once firmware files are in the tree */ 365 + if (!qtest_enabled()) { 366 + if (bios_size < 0 || bios_size > MACROM_SIZE) { 367 + error_report("could not load MacROM '%s'", bios_name); 368 + exit(1); 369 + } 370 + 371 + ptr = rom_ptr(MACROM_ADDR, MACROM_SIZE); 372 + stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */ 373 + stl_phys(cs->as, 4, 374 + MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */ 375 + } 376 + } 377 + } 378 + 379 + static void q800_machine_class_init(ObjectClass *oc, void *data) 380 + { 381 + MachineClass *mc = MACHINE_CLASS(oc); 382 + mc->desc = "Macintosh Quadra 800"; 383 + mc->init = q800_init; 384 + mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); 385 + mc->max_cpus = 1; 386 + mc->is_default = 0; 387 + mc->block_default_type = IF_SCSI; 388 + } 389 + 390 + static const TypeInfo q800_machine_typeinfo = { 391 + .name = MACHINE_TYPE_NAME("q800"), 392 + .parent = TYPE_MACHINE, 393 + .class_init = q800_machine_class_init, 394 + }; 395 + 396 + static void q800_machine_register_types(void) 397 + { 398 + type_register_static(&q800_machine_typeinfo); 399 + } 400 + 401 + type_init(q800_machine_register_types)
+5
hw/misc/Kconfig
··· 120 120 config UNIMP 121 121 bool 122 122 123 + config MAC_VIA 124 + bool 125 + select MOS6522 126 + select ADB 127 + 123 128 source macio/Kconfig
+1
hw/misc/Makefile.objs
··· 79 79 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o 80 80 common-obj-$(CONFIG_MSF2) += msf2-sysreg.o 81 81 common-obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o 82 + obj-$(CONFIG_MAC_VIA) += mac_via.o 82 83 83 84 common-obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o
+964
hw/misc/mac_via.c
··· 1 + /* 2 + * QEMU m68k Macintosh VIA device support 3 + * 4 + * Copyright (c) 2011-2018 Laurent Vivier 5 + * Copyright (c) 2018 Mark Cave-Ayland 6 + * 7 + * Some parts from hw/misc/macio/cuda.c 8 + * 9 + * Copyright (c) 2004-2007 Fabrice Bellard 10 + * Copyright (c) 2007 Jocelyn Mayer 11 + * 12 + * some parts from linux-2.6.29, arch/m68k/include/asm/mac_via.h 13 + * 14 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 15 + * See the COPYING file in the top-level directory. 16 + */ 17 + 18 + #include "qemu/osdep.h" 19 + #include "qemu-common.h" 20 + #include "migration/vmstate.h" 21 + #include "hw/sysbus.h" 22 + #include "hw/irq.h" 23 + #include "qemu/timer.h" 24 + #include "hw/misc/mac_via.h" 25 + #include "hw/misc/mos6522.h" 26 + #include "hw/input/adb.h" 27 + #include "sysemu/runstate.h" 28 + #include "qapi/error.h" 29 + #include "qemu/cutils.h" 30 + 31 + 32 + /* 33 + * VIAs: There are two in every machine, 34 + */ 35 + 36 + #define VIA_SIZE (0x2000) 37 + 38 + /* 39 + * Not all of these are true post MacII I think. 40 + * CSA: probably the ones CHRP marks as 'unused' change purposes 41 + * when the IWM becomes the SWIM. 42 + * http://www.rs6000.ibm.com/resource/technology/chrpio/via5.mak.html 43 + * ftp://ftp.austin.ibm.com/pub/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf 44 + * 45 + * also, http://developer.apple.com/technotes/hw/hw_09.html claims the 46 + * following changes for IIfx: 47 + * VIA1A_vSccWrReq not available and that VIA1A_vSync has moved to an IOP. 48 + * Also, "All of the functionality of VIA2 has been moved to other chips". 49 + */ 50 + 51 + #define VIA1A_vSccWrReq 0x80 /* 52 + * SCC write. (input) 53 + * [CHRP] SCC WREQ: Reflects the state of the 54 + * Wait/Request pins from the SCC. 55 + * [Macintosh Family Hardware] 56 + * as CHRP on SE/30,II,IIx,IIcx,IIci. 57 + * on IIfx, "0 means an active request" 58 + */ 59 + #define VIA1A_vRev8 0x40 /* 60 + * Revision 8 board ??? 61 + * [CHRP] En WaitReqB: Lets the WaitReq_L 62 + * signal from port B of the SCC appear on 63 + * the PA7 input pin. Output. 64 + * [Macintosh Family] On the SE/30, this 65 + * is the bit to flip screen buffers. 66 + * 0=alternate, 1=main. 67 + * on II,IIx,IIcx,IIci,IIfx this is a bit 68 + * for Rev ID. 0=II,IIx, 1=IIcx,IIci,IIfx 69 + */ 70 + #define VIA1A_vHeadSel 0x20 /* 71 + * Head select for IWM. 72 + * [CHRP] unused. 73 + * [Macintosh Family] "Floppy disk 74 + * state-control line SEL" on all but IIfx 75 + */ 76 + #define VIA1A_vOverlay 0x10 /* 77 + * [Macintosh Family] On SE/30,II,IIx,IIcx 78 + * this bit enables the "Overlay" address 79 + * map in the address decoders as it is on 80 + * reset for mapping the ROM over the reset 81 + * vector. 1=use overlay map. 82 + * On the IIci,IIfx it is another bit of the 83 + * CPU ID: 0=normal IIci, 1=IIci with parity 84 + * feature or IIfx. 85 + * [CHRP] En WaitReqA: Lets the WaitReq_L 86 + * signal from port A of the SCC appear 87 + * on the PA7 input pin (CHRP). Output. 88 + * [MkLinux] "Drive Select" 89 + * (with 0x20 being 'disk head select') 90 + */ 91 + #define VIA1A_vSync 0x08 /* 92 + * [CHRP] Sync Modem: modem clock select: 93 + * 1: select the external serial clock to 94 + * drive the SCC's /RTxCA pin. 95 + * 0: Select the 3.6864MHz clock to drive 96 + * the SCC cell. 97 + * [Macintosh Family] Correct on all but IIfx 98 + */ 99 + 100 + /* 101 + * Macintosh Family Hardware sez: bits 0-2 of VIA1A are volume control 102 + * on Macs which had the PWM sound hardware. Reserved on newer models. 103 + * On IIci,IIfx, bits 1-2 are the rest of the CPU ID: 104 + * bit 2: 1=IIci, 0=IIfx 105 + * bit 1: 1 on both IIci and IIfx. 106 + * MkLinux sez bit 0 is 'burnin flag' in this case. 107 + * CHRP sez: VIA1A bits 0-2 and 5 are 'unused': if programmed as 108 + * inputs, these bits will read 0. 109 + */ 110 + #define VIA1A_vVolume 0x07 /* Audio volume mask for PWM */ 111 + #define VIA1A_CPUID0 0x02 /* CPU id bit 0 on RBV, others */ 112 + #define VIA1A_CPUID1 0x04 /* CPU id bit 0 on RBV, others */ 113 + #define VIA1A_CPUID2 0x10 /* CPU id bit 0 on RBV, others */ 114 + #define VIA1A_CPUID3 0x40 /* CPU id bit 0 on RBV, others */ 115 + 116 + /* 117 + * Info on VIA1B is from Macintosh Family Hardware & MkLinux. 118 + * CHRP offers no info. 119 + */ 120 + #define VIA1B_vSound 0x80 /* 121 + * Sound enable (for compatibility with 122 + * PWM hardware) 0=enabled. 123 + * Also, on IIci w/parity, shows parity error 124 + * 0=error, 1=OK. 125 + */ 126 + #define VIA1B_vMystery 0x40 /* 127 + * On IIci, parity enable. 0=enabled,1=disabled 128 + * On SE/30, vertical sync interrupt enable. 129 + * 0=enabled. This vSync interrupt shows up 130 + * as a slot $E interrupt. 131 + */ 132 + #define VIA1B_vADBS2 0x20 /* ADB state input bit 1 (unused on IIfx) */ 133 + #define VIA1B_vADBS1 0x10 /* ADB state input bit 0 (unused on IIfx) */ 134 + #define VIA1B_vADBInt 0x08 /* ADB interrupt 0=interrupt (unused on IIfx)*/ 135 + #define VIA1B_vRTCEnb 0x04 /* Enable Real time clock. 0=enabled. */ 136 + #define VIA1B_vRTCClk 0x02 /* Real time clock serial-clock line. */ 137 + #define VIA1B_vRTCData 0x01 /* Real time clock serial-data line. */ 138 + 139 + /* 140 + * VIA2 A register is the interrupt lines raised off the nubus 141 + * slots. 142 + * The below info is from 'Macintosh Family Hardware.' 143 + * MkLinux calls the 'IIci internal video IRQ' below the 'RBV slot 0 irq.' 144 + * It also notes that the slot $9 IRQ is the 'Ethernet IRQ' and 145 + * defines the 'Video IRQ' as 0x40 for the 'EVR' VIA work-alike. 146 + * Perhaps OSS uses vRAM1 and vRAM2 for ADB. 147 + */ 148 + 149 + #define VIA2A_vRAM1 0x80 /* RAM size bit 1 (IIci: reserved) */ 150 + #define VIA2A_vRAM0 0x40 /* RAM size bit 0 (IIci: internal video IRQ) */ 151 + #define VIA2A_vIRQE 0x20 /* IRQ from slot $E */ 152 + #define VIA2A_vIRQD 0x10 /* IRQ from slot $D */ 153 + #define VIA2A_vIRQC 0x08 /* IRQ from slot $C */ 154 + #define VIA2A_vIRQB 0x04 /* IRQ from slot $B */ 155 + #define VIA2A_vIRQA 0x02 /* IRQ from slot $A */ 156 + #define VIA2A_vIRQ9 0x01 /* IRQ from slot $9 */ 157 + 158 + /* 159 + * RAM size bits decoded as follows: 160 + * bit1 bit0 size of ICs in bank A 161 + * 0 0 256 kbit 162 + * 0 1 1 Mbit 163 + * 1 0 4 Mbit 164 + * 1 1 16 Mbit 165 + */ 166 + 167 + /* 168 + * Register B has the fun stuff in it 169 + */ 170 + 171 + #define VIA2B_vVBL 0x80 /* 172 + * VBL output to VIA1 (60.15Hz) driven by 173 + * timer T1. 174 + * on IIci, parity test: 0=test mode. 175 + * [MkLinux] RBV_PARODD: 1=odd,0=even. 176 + */ 177 + #define VIA2B_vSndJck 0x40 /* 178 + * External sound jack status. 179 + * 0=plug is inserted. On SE/30, always 0 180 + */ 181 + #define VIA2B_vTfr0 0x20 /* Transfer mode bit 0 ack from NuBus */ 182 + #define VIA2B_vTfr1 0x10 /* Transfer mode bit 1 ack from NuBus */ 183 + #define VIA2B_vMode32 0x08 /* 184 + * 24/32bit switch - doubles as cache flush 185 + * on II, AMU/PMMU control. 186 + * if AMU, 0=24bit to 32bit translation 187 + * if PMMU, 1=PMMU is accessing page table. 188 + * on SE/30 tied low. 189 + * on IIx,IIcx,IIfx, unused. 190 + * on IIci/RBV, cache control. 0=flush cache. 191 + */ 192 + #define VIA2B_vPower 0x04 /* 193 + * Power off, 0=shut off power. 194 + * on SE/30 this signal sent to PDS card. 195 + */ 196 + #define VIA2B_vBusLk 0x02 /* 197 + * Lock NuBus transactions, 0=locked. 198 + * on SE/30 sent to PDS card. 199 + */ 200 + #define VIA2B_vCDis 0x01 /* 201 + * Cache control. On IIci, 1=disable cache card 202 + * on others, 0=disable processor's instruction 203 + * and data caches. 204 + */ 205 + 206 + /* interrupt flags */ 207 + 208 + #define IRQ_SET 0x80 209 + 210 + /* common */ 211 + 212 + #define VIA_IRQ_TIMER1 0x40 213 + #define VIA_IRQ_TIMER2 0x20 214 + 215 + /* 216 + * Apple sez: http://developer.apple.com/technotes/ov/ov_04.html 217 + * Another example of a valid function that has no ROM support is the use 218 + * of the alternate video page for page-flipping animation. Since there 219 + * is no ROM call to flip pages, it is necessary to go play with the 220 + * right bit in the VIA chip (6522 Versatile Interface Adapter). 221 + * [CSA: don't know which one this is, but it's one of 'em!] 222 + */ 223 + 224 + /* 225 + * 6522 registers - see databook. 226 + * CSA: Assignments for VIA1 confirmed from CHRP spec. 227 + */ 228 + 229 + /* partial address decode. 0xYYXX : XX part for RBV, YY part for VIA */ 230 + /* Note: 15 VIA regs, 8 RBV regs */ 231 + 232 + #define vBufB 0x0000 /* [VIA/RBV] Register B */ 233 + #define vBufAH 0x0200 /* [VIA only] Buffer A, with handshake. DON'T USE! */ 234 + #define vDirB 0x0400 /* [VIA only] Data Direction Register B. */ 235 + #define vDirA 0x0600 /* [VIA only] Data Direction Register A. */ 236 + #define vT1CL 0x0800 /* [VIA only] Timer one counter low. */ 237 + #define vT1CH 0x0a00 /* [VIA only] Timer one counter high. */ 238 + #define vT1LL 0x0c00 /* [VIA only] Timer one latches low. */ 239 + #define vT1LH 0x0e00 /* [VIA only] Timer one latches high. */ 240 + #define vT2CL 0x1000 /* [VIA only] Timer two counter low. */ 241 + #define vT2CH 0x1200 /* [VIA only] Timer two counter high. */ 242 + #define vSR 0x1400 /* [VIA only] Shift register. */ 243 + #define vACR 0x1600 /* [VIA only] Auxilary control register. */ 244 + #define vPCR 0x1800 /* [VIA only] Peripheral control register. */ 245 + /* 246 + * CHRP sez never ever to *write* this. 247 + * Mac family says never to *change* this. 248 + * In fact we need to initialize it once at start. 249 + */ 250 + #define vIFR 0x1a00 /* [VIA/RBV] Interrupt flag register. */ 251 + #define vIER 0x1c00 /* [VIA/RBV] Interrupt enable register. */ 252 + #define vBufA 0x1e00 /* [VIA/RBV] register A (no handshake) */ 253 + 254 + /* from linux 2.6 drivers/macintosh/via-macii.c */ 255 + 256 + /* Bits in ACR */ 257 + 258 + #define VIA1ACR_vShiftCtrl 0x1c /* Shift register control bits */ 259 + #define VIA1ACR_vShiftExtClk 0x0c /* Shift on external clock */ 260 + #define VIA1ACR_vShiftOut 0x10 /* Shift out if 1 */ 261 + 262 + /* 263 + * Apple Macintosh Family Hardware Refenece 264 + * Table 19-10 ADB transaction states 265 + */ 266 + 267 + #define ADB_STATE_NEW 0 268 + #define ADB_STATE_EVEN 1 269 + #define ADB_STATE_ODD 2 270 + #define ADB_STATE_IDLE 3 271 + 272 + #define VIA1B_vADB_StateMask (VIA1B_vADBS1 | VIA1B_vADBS2) 273 + #define VIA1B_vADB_StateShift 4 274 + 275 + #define VIA_TIMER_FREQ (783360) 276 + #define VIA_ADB_POLL_FREQ 50 /* XXX: not real */ 277 + 278 + /* VIA returns time offset from Jan 1, 1904, not 1970 */ 279 + #define RTC_OFFSET 2082844800 280 + 281 + static void via1_VBL_update(MOS6522Q800VIA1State *v1s) 282 + { 283 + MOS6522State *s = MOS6522(v1s); 284 + 285 + /* 60 Hz irq */ 286 + v1s->next_VBL = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16630) / 287 + 16630 * 16630; 288 + 289 + if (s->ier & VIA1_IRQ_VBLANK) { 290 + timer_mod(v1s->VBL_timer, v1s->next_VBL); 291 + } else { 292 + timer_del(v1s->VBL_timer); 293 + } 294 + } 295 + 296 + static void via1_one_second_update(MOS6522Q800VIA1State *v1s) 297 + { 298 + MOS6522State *s = MOS6522(v1s); 299 + 300 + v1s->next_second = (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000) / 301 + 1000 * 1000; 302 + if (s->ier & VIA1_IRQ_ONE_SECOND) { 303 + timer_mod(v1s->one_second_timer, v1s->next_second); 304 + } else { 305 + timer_del(v1s->one_second_timer); 306 + } 307 + } 308 + 309 + static void via1_VBL(void *opaque) 310 + { 311 + MOS6522Q800VIA1State *v1s = opaque; 312 + MOS6522State *s = MOS6522(v1s); 313 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); 314 + 315 + s->ifr |= VIA1_IRQ_VBLANK; 316 + mdc->update_irq(s); 317 + 318 + via1_VBL_update(v1s); 319 + } 320 + 321 + static void via1_one_second(void *opaque) 322 + { 323 + MOS6522Q800VIA1State *v1s = opaque; 324 + MOS6522State *s = MOS6522(v1s); 325 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); 326 + 327 + s->ifr |= VIA1_IRQ_ONE_SECOND; 328 + mdc->update_irq(s); 329 + 330 + via1_one_second_update(v1s); 331 + } 332 + 333 + static void via1_irq_request(void *opaque, int irq, int level) 334 + { 335 + MOS6522Q800VIA1State *v1s = opaque; 336 + MOS6522State *s = MOS6522(v1s); 337 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); 338 + 339 + if (level) { 340 + s->ifr |= 1 << irq; 341 + } else { 342 + s->ifr &= ~(1 << irq); 343 + } 344 + 345 + mdc->update_irq(s); 346 + } 347 + 348 + static void via2_irq_request(void *opaque, int irq, int level) 349 + { 350 + MOS6522Q800VIA2State *v2s = opaque; 351 + MOS6522State *s = MOS6522(v2s); 352 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); 353 + 354 + if (level) { 355 + s->ifr |= 1 << irq; 356 + } else { 357 + s->ifr &= ~(1 << irq); 358 + } 359 + 360 + mdc->update_irq(s); 361 + } 362 + 363 + static void via1_rtc_update(MacVIAState *m) 364 + { 365 + MOS6522Q800VIA1State *v1s = &m->mos6522_via1; 366 + MOS6522State *s = MOS6522(v1s); 367 + 368 + if (s->b & VIA1B_vRTCEnb) { 369 + return; 370 + } 371 + 372 + if (s->dirb & VIA1B_vRTCData) { 373 + /* send bits to the RTC */ 374 + if (!(v1s->last_b & VIA1B_vRTCClk) && (s->b & VIA1B_vRTCClk)) { 375 + m->data_out <<= 1; 376 + m->data_out |= s->b & VIA1B_vRTCData; 377 + m->data_out_cnt++; 378 + } 379 + } else { 380 + /* receive bits from the RTC */ 381 + if ((v1s->last_b & VIA1B_vRTCClk) && 382 + !(s->b & VIA1B_vRTCClk) && 383 + m->data_in_cnt) { 384 + s->b = (s->b & ~VIA1B_vRTCData) | 385 + ((m->data_in >> 7) & VIA1B_vRTCData); 386 + m->data_in <<= 1; 387 + m->data_in_cnt--; 388 + } 389 + } 390 + 391 + if (m->data_out_cnt == 8) { 392 + m->data_out_cnt = 0; 393 + 394 + if (m->cmd == 0) { 395 + if (m->data_out & 0x80) { 396 + /* this is a read command */ 397 + uint32_t time = m->tick_offset + 398 + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 399 + NANOSECONDS_PER_SECOND); 400 + if (m->data_out == 0x81) { /* seconds register 0 */ 401 + m->data_in = time & 0xff; 402 + m->data_in_cnt = 8; 403 + } else if (m->data_out == 0x85) { /* seconds register 1 */ 404 + m->data_in = (time >> 8) & 0xff; 405 + m->data_in_cnt = 8; 406 + } else if (m->data_out == 0x89) { /* seconds register 2 */ 407 + m->data_in = (time >> 16) & 0xff; 408 + m->data_in_cnt = 8; 409 + } else if (m->data_out == 0x8d) { /* seconds register 3 */ 410 + m->data_in = (time >> 24) & 0xff; 411 + m->data_in_cnt = 8; 412 + } else if ((m->data_out & 0xf3) == 0xa1) { 413 + /* PRAM address 0x10 -> 0x13 */ 414 + int addr = (m->data_out >> 2) & 0x03; 415 + m->data_in = v1s->PRAM[addr]; 416 + m->data_in_cnt = 8; 417 + } else if ((m->data_out & 0xf3) == 0xa1) { 418 + /* PRAM address 0x00 -> 0x0f */ 419 + int addr = (m->data_out >> 2) & 0x0f; 420 + m->data_in = v1s->PRAM[addr]; 421 + m->data_in_cnt = 8; 422 + } else if ((m->data_out & 0xf8) == 0xb8) { 423 + /* extended memory designator and sector number */ 424 + m->cmd = m->data_out; 425 + } 426 + } else { 427 + /* this is a write command */ 428 + m->cmd = m->data_out; 429 + } 430 + } else { 431 + if (m->cmd & 0x80) { 432 + if ((m->cmd & 0xf8) == 0xb8) { 433 + /* extended memory designator and sector number */ 434 + int sector = m->cmd & 0x07; 435 + int addr = (m->data_out >> 2) & 0x1f; 436 + 437 + m->data_in = v1s->PRAM[sector * 8 + addr]; 438 + m->data_in_cnt = 8; 439 + } 440 + } else if (!m->wprotect) { 441 + /* this is a write command */ 442 + if (m->alt != 0) { 443 + /* extended memory designator and sector number */ 444 + int sector = m->cmd & 0x07; 445 + int addr = (m->alt >> 2) & 0x1f; 446 + 447 + v1s->PRAM[sector * 8 + addr] = m->data_out; 448 + 449 + m->alt = 0; 450 + } else if (m->cmd == 0x01) { /* seconds register 0 */ 451 + /* FIXME */ 452 + } else if (m->cmd == 0x05) { /* seconds register 1 */ 453 + /* FIXME */ 454 + } else if (m->cmd == 0x09) { /* seconds register 2 */ 455 + /* FIXME */ 456 + } else if (m->cmd == 0x0d) { /* seconds register 3 */ 457 + /* FIXME */ 458 + } else if (m->cmd == 0x31) { 459 + /* Test Register */ 460 + } else if (m->cmd == 0x35) { 461 + /* Write Protect register */ 462 + m->wprotect = m->data_out & 1; 463 + } else if ((m->cmd & 0xf3) == 0xa1) { 464 + /* PRAM address 0x10 -> 0x13 */ 465 + int addr = (m->cmd >> 2) & 0x03; 466 + v1s->PRAM[addr] = m->data_out; 467 + } else if ((m->cmd & 0xf3) == 0xa1) { 468 + /* PRAM address 0x00 -> 0x0f */ 469 + int addr = (m->cmd >> 2) & 0x0f; 470 + v1s->PRAM[addr] = m->data_out; 471 + } else if ((m->cmd & 0xf8) == 0xb8) { 472 + /* extended memory designator and sector number */ 473 + m->alt = m->cmd; 474 + } 475 + } 476 + } 477 + m->data_out = 0; 478 + } 479 + } 480 + 481 + static int adb_via_poll(MacVIAState *s, int state, uint8_t *data) 482 + { 483 + if (state != ADB_STATE_IDLE) { 484 + return 0; 485 + } 486 + 487 + if (s->adb_data_in_size < s->adb_data_in_index) { 488 + return 0; 489 + } 490 + 491 + if (s->adb_data_out_index != 0) { 492 + return 0; 493 + } 494 + 495 + s->adb_data_in_index = 0; 496 + s->adb_data_out_index = 0; 497 + s->adb_data_in_size = adb_poll(&s->adb_bus, s->adb_data_in, 0xffff); 498 + 499 + if (s->adb_data_in_size) { 500 + *data = s->adb_data_in[s->adb_data_in_index++]; 501 + qemu_irq_raise(s->adb_data_ready); 502 + } 503 + 504 + return s->adb_data_in_size; 505 + } 506 + 507 + static int adb_via_send(MacVIAState *s, int state, uint8_t data) 508 + { 509 + switch (state) { 510 + case ADB_STATE_NEW: 511 + s->adb_data_out_index = 0; 512 + break; 513 + case ADB_STATE_EVEN: 514 + if ((s->adb_data_out_index & 1) == 0) { 515 + return 0; 516 + } 517 + break; 518 + case ADB_STATE_ODD: 519 + if (s->adb_data_out_index & 1) { 520 + return 0; 521 + } 522 + break; 523 + case ADB_STATE_IDLE: 524 + return 0; 525 + } 526 + 527 + assert(s->adb_data_out_index < sizeof(s->adb_data_out) - 1); 528 + 529 + s->adb_data_out[s->adb_data_out_index++] = data; 530 + qemu_irq_raise(s->adb_data_ready); 531 + return 1; 532 + } 533 + 534 + static int adb_via_receive(MacVIAState *s, int state, uint8_t *data) 535 + { 536 + switch (state) { 537 + case ADB_STATE_NEW: 538 + return 0; 539 + 540 + case ADB_STATE_EVEN: 541 + if (s->adb_data_in_size <= 0) { 542 + qemu_irq_raise(s->adb_data_ready); 543 + return 0; 544 + } 545 + 546 + if (s->adb_data_in_index >= s->adb_data_in_size) { 547 + *data = 0; 548 + qemu_irq_raise(s->adb_data_ready); 549 + return 1; 550 + } 551 + 552 + if ((s->adb_data_in_index & 1) == 0) { 553 + return 0; 554 + } 555 + 556 + break; 557 + 558 + case ADB_STATE_ODD: 559 + if (s->adb_data_in_size <= 0) { 560 + qemu_irq_raise(s->adb_data_ready); 561 + return 0; 562 + } 563 + 564 + if (s->adb_data_in_index >= s->adb_data_in_size) { 565 + *data = 0; 566 + qemu_irq_raise(s->adb_data_ready); 567 + return 1; 568 + } 569 + 570 + if (s->adb_data_in_index & 1) { 571 + return 0; 572 + } 573 + 574 + break; 575 + 576 + case ADB_STATE_IDLE: 577 + if (s->adb_data_out_index == 0) { 578 + return 0; 579 + } 580 + 581 + s->adb_data_in_size = adb_request(&s->adb_bus, s->adb_data_in, 582 + s->adb_data_out, 583 + s->adb_data_out_index); 584 + s->adb_data_out_index = 0; 585 + s->adb_data_in_index = 0; 586 + if (s->adb_data_in_size < 0) { 587 + *data = 0xff; 588 + qemu_irq_raise(s->adb_data_ready); 589 + return -1; 590 + } 591 + 592 + if (s->adb_data_in_size == 0) { 593 + return 0; 594 + } 595 + 596 + break; 597 + } 598 + 599 + assert(s->adb_data_in_index < sizeof(s->adb_data_in) - 1); 600 + 601 + *data = s->adb_data_in[s->adb_data_in_index++]; 602 + qemu_irq_raise(s->adb_data_ready); 603 + if (*data == 0xff || *data == 0) { 604 + return 0; 605 + } 606 + return 1; 607 + } 608 + 609 + static void via1_adb_update(MacVIAState *m) 610 + { 611 + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); 612 + MOS6522State *s = MOS6522(v1s); 613 + int state; 614 + int ret; 615 + 616 + state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; 617 + 618 + if (s->acr & VIA1ACR_vShiftOut) { 619 + /* output mode */ 620 + ret = adb_via_send(m, state, s->sr); 621 + if (ret > 0) { 622 + s->b &= ~VIA1B_vADBInt; 623 + } else { 624 + s->b |= VIA1B_vADBInt; 625 + } 626 + } else { 627 + /* input mode */ 628 + ret = adb_via_receive(m, state, &s->sr); 629 + if (ret > 0 && s->sr != 0xff) { 630 + s->b &= ~VIA1B_vADBInt; 631 + } else { 632 + s->b |= VIA1B_vADBInt; 633 + } 634 + } 635 + } 636 + 637 + static void via_adb_poll(void *opaque) 638 + { 639 + MacVIAState *m = opaque; 640 + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); 641 + MOS6522State *s = MOS6522(v1s); 642 + int state; 643 + 644 + if (s->b & VIA1B_vADBInt) { 645 + state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; 646 + if (adb_via_poll(m, state, &s->sr)) { 647 + s->b &= ~VIA1B_vADBInt; 648 + } 649 + } 650 + 651 + timer_mod(m->adb_poll_timer, 652 + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 653 + (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); 654 + } 655 + 656 + static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) 657 + { 658 + MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque); 659 + MOS6522State *ms = MOS6522(s); 660 + int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); 661 + 662 + /* 663 + * If IRQs are disabled, timers are disabled, but we need to update 664 + * VIA1_IRQ_VBLANK and VIA1_IRQ_ONE_SECOND bits in the IFR 665 + */ 666 + 667 + if (now >= s->next_VBL) { 668 + ms->ifr |= VIA1_IRQ_VBLANK; 669 + via1_VBL_update(s); 670 + } 671 + if (now >= s->next_second) { 672 + ms->ifr |= VIA1_IRQ_ONE_SECOND; 673 + via1_one_second_update(s); 674 + } 675 + 676 + addr = (addr >> 9) & 0xf; 677 + return mos6522_read(ms, addr, size); 678 + } 679 + 680 + static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val, 681 + unsigned size) 682 + { 683 + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque); 684 + MOS6522State *ms = MOS6522(v1s); 685 + 686 + addr = (addr >> 9) & 0xf; 687 + mos6522_write(ms, addr, val, size); 688 + 689 + via1_one_second_update(v1s); 690 + via1_VBL_update(v1s); 691 + } 692 + 693 + static const MemoryRegionOps mos6522_q800_via1_ops = { 694 + .read = mos6522_q800_via1_read, 695 + .write = mos6522_q800_via1_write, 696 + .endianness = DEVICE_BIG_ENDIAN, 697 + .valid = { 698 + .min_access_size = 1, 699 + .max_access_size = 1, 700 + }, 701 + }; 702 + 703 + static uint64_t mos6522_q800_via2_read(void *opaque, hwaddr addr, unsigned size) 704 + { 705 + MOS6522Q800VIA2State *s = MOS6522_Q800_VIA2(opaque); 706 + MOS6522State *ms = MOS6522(s); 707 + 708 + addr = (addr >> 9) & 0xf; 709 + return mos6522_read(ms, addr, size); 710 + } 711 + 712 + static void mos6522_q800_via2_write(void *opaque, hwaddr addr, uint64_t val, 713 + unsigned size) 714 + { 715 + MOS6522Q800VIA2State *s = MOS6522_Q800_VIA2(opaque); 716 + MOS6522State *ms = MOS6522(s); 717 + 718 + addr = (addr >> 9) & 0xf; 719 + mos6522_write(ms, addr, val, size); 720 + } 721 + 722 + static const MemoryRegionOps mos6522_q800_via2_ops = { 723 + .read = mos6522_q800_via2_read, 724 + .write = mos6522_q800_via2_write, 725 + .endianness = DEVICE_BIG_ENDIAN, 726 + .valid = { 727 + .min_access_size = 1, 728 + .max_access_size = 1, 729 + }, 730 + }; 731 + 732 + static void mac_via_reset(DeviceState *dev) 733 + { 734 + MacVIAState *m = MAC_VIA(dev); 735 + MOS6522Q800VIA1State *v1s = &m->mos6522_via1; 736 + 737 + timer_mod(m->adb_poll_timer, 738 + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 739 + (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); 740 + 741 + timer_del(v1s->VBL_timer); 742 + v1s->next_VBL = 0; 743 + timer_del(v1s->one_second_timer); 744 + v1s->next_second = 0; 745 + } 746 + 747 + static void mac_via_realize(DeviceState *dev, Error **errp) 748 + { 749 + MacVIAState *m = MAC_VIA(dev); 750 + MOS6522State *ms; 751 + struct tm tm; 752 + 753 + /* Init VIAs 1 and 2 */ 754 + sysbus_init_child_obj(OBJECT(dev), "via1", &m->mos6522_via1, 755 + sizeof(m->mos6522_via1), TYPE_MOS6522_Q800_VIA1); 756 + 757 + sysbus_init_child_obj(OBJECT(dev), "via2", &m->mos6522_via2, 758 + sizeof(m->mos6522_via2), TYPE_MOS6522_Q800_VIA2); 759 + 760 + /* Pass through mos6522 output IRQs */ 761 + ms = MOS6522(&m->mos6522_via1); 762 + object_property_add_alias(OBJECT(dev), "irq[0]", OBJECT(ms), 763 + SYSBUS_DEVICE_GPIO_IRQ "[0]", &error_abort); 764 + ms = MOS6522(&m->mos6522_via2); 765 + object_property_add_alias(OBJECT(dev), "irq[1]", OBJECT(ms), 766 + SYSBUS_DEVICE_GPIO_IRQ "[0]", &error_abort); 767 + 768 + /* Pass through mos6522 input IRQs */ 769 + qdev_pass_gpios(DEVICE(&m->mos6522_via1), dev, "via1-irq"); 770 + qdev_pass_gpios(DEVICE(&m->mos6522_via2), dev, "via2-irq"); 771 + 772 + /* VIA 1 */ 773 + m->mos6522_via1.one_second_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, 774 + via1_one_second, 775 + &m->mos6522_via1); 776 + m->mos6522_via1.VBL_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via1_VBL, 777 + &m->mos6522_via1); 778 + 779 + qemu_get_timedate(&tm, 0); 780 + m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; 781 + 782 + m->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via_adb_poll, m); 783 + m->adb_data_ready = qdev_get_gpio_in_named(dev, "via1-irq", 784 + VIA1_IRQ_ADB_READY_BIT); 785 + } 786 + 787 + static void mac_via_init(Object *obj) 788 + { 789 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 790 + MacVIAState *m = MAC_VIA(obj); 791 + 792 + /* MMIO */ 793 + memory_region_init(&m->mmio, obj, "mac-via", 2 * VIA_SIZE); 794 + sysbus_init_mmio(sbd, &m->mmio); 795 + 796 + memory_region_init_io(&m->via1mem, obj, &mos6522_q800_via1_ops, 797 + &m->mos6522_via1, "via1", VIA_SIZE); 798 + memory_region_add_subregion(&m->mmio, 0x0, &m->via1mem); 799 + 800 + memory_region_init_io(&m->via2mem, obj, &mos6522_q800_via2_ops, 801 + &m->mos6522_via2, "via2", VIA_SIZE); 802 + memory_region_add_subregion(&m->mmio, VIA_SIZE, &m->via2mem); 803 + 804 + /* ADB */ 805 + qbus_create_inplace((BusState *)&m->adb_bus, sizeof(m->adb_bus), 806 + TYPE_ADB_BUS, DEVICE(obj), "adb.0"); 807 + } 808 + 809 + static const VMStateDescription vmstate_mac_via = { 810 + .name = "mac-via", 811 + .version_id = 1, 812 + .minimum_version_id = 1, 813 + .fields = (VMStateField[]) { 814 + /* VIAs */ 815 + VMSTATE_STRUCT(mos6522_via1.parent_obj, MacVIAState, 0, vmstate_mos6522, 816 + MOS6522State), 817 + VMSTATE_UINT8(mos6522_via1.last_b, MacVIAState), 818 + VMSTATE_BUFFER(mos6522_via1.PRAM, MacVIAState), 819 + VMSTATE_TIMER_PTR(mos6522_via1.one_second_timer, MacVIAState), 820 + VMSTATE_INT64(mos6522_via1.next_second, MacVIAState), 821 + VMSTATE_TIMER_PTR(mos6522_via1.VBL_timer, MacVIAState), 822 + VMSTATE_INT64(mos6522_via1.next_VBL, MacVIAState), 823 + VMSTATE_STRUCT(mos6522_via2.parent_obj, MacVIAState, 0, vmstate_mos6522, 824 + MOS6522State), 825 + /* RTC */ 826 + VMSTATE_UINT32(tick_offset, MacVIAState), 827 + VMSTATE_UINT8(data_out, MacVIAState), 828 + VMSTATE_INT32(data_out_cnt, MacVIAState), 829 + VMSTATE_UINT8(data_in, MacVIAState), 830 + VMSTATE_UINT8(data_in_cnt, MacVIAState), 831 + VMSTATE_UINT8(cmd, MacVIAState), 832 + VMSTATE_INT32(wprotect, MacVIAState), 833 + VMSTATE_INT32(alt, MacVIAState), 834 + /* ADB */ 835 + VMSTATE_TIMER_PTR(adb_poll_timer, MacVIAState), 836 + VMSTATE_INT32(adb_data_in_size, MacVIAState), 837 + VMSTATE_INT32(adb_data_in_index, MacVIAState), 838 + VMSTATE_INT32(adb_data_out_index, MacVIAState), 839 + VMSTATE_BUFFER(adb_data_in, MacVIAState), 840 + VMSTATE_BUFFER(adb_data_out, MacVIAState), 841 + VMSTATE_END_OF_LIST() 842 + } 843 + }; 844 + 845 + static void mac_via_class_init(ObjectClass *oc, void *data) 846 + { 847 + DeviceClass *dc = DEVICE_CLASS(oc); 848 + 849 + dc->realize = mac_via_realize; 850 + dc->reset = mac_via_reset; 851 + dc->vmsd = &vmstate_mac_via; 852 + } 853 + 854 + static TypeInfo mac_via_info = { 855 + .name = TYPE_MAC_VIA, 856 + .parent = TYPE_SYS_BUS_DEVICE, 857 + .instance_size = sizeof(MacVIAState), 858 + .instance_init = mac_via_init, 859 + .class_init = mac_via_class_init, 860 + }; 861 + 862 + /* VIA 1 */ 863 + static void mos6522_q800_via1_portB_write(MOS6522State *s) 864 + { 865 + MOS6522Q800VIA1State *v1s = container_of(s, MOS6522Q800VIA1State, 866 + parent_obj); 867 + MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1); 868 + 869 + via1_rtc_update(m); 870 + via1_adb_update(m); 871 + 872 + v1s->last_b = s->b; 873 + } 874 + 875 + static void mos6522_q800_via1_reset(DeviceState *dev) 876 + { 877 + MOS6522State *ms = MOS6522(dev); 878 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms); 879 + 880 + mdc->parent_reset(dev); 881 + 882 + ms->timers[0].frequency = VIA_TIMER_FREQ; 883 + ms->timers[1].frequency = VIA_TIMER_FREQ; 884 + 885 + ms->b = VIA1B_vADB_StateMask | VIA1B_vADBInt | VIA1B_vRTCEnb; 886 + } 887 + 888 + static void mos6522_q800_via1_init(Object *obj) 889 + { 890 + qdev_init_gpio_in_named(DEVICE(obj), via1_irq_request, "via1-irq", 891 + VIA1_IRQ_NB); 892 + } 893 + 894 + static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data) 895 + { 896 + DeviceClass *dc = DEVICE_CLASS(oc); 897 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc); 898 + 899 + dc->reset = mos6522_q800_via1_reset; 900 + mdc->portB_write = mos6522_q800_via1_portB_write; 901 + } 902 + 903 + static const TypeInfo mos6522_q800_via1_type_info = { 904 + .name = TYPE_MOS6522_Q800_VIA1, 905 + .parent = TYPE_MOS6522, 906 + .instance_size = sizeof(MOS6522Q800VIA1State), 907 + .instance_init = mos6522_q800_via1_init, 908 + .class_init = mos6522_q800_via1_class_init, 909 + }; 910 + 911 + /* VIA 2 */ 912 + static void mos6522_q800_via2_portB_write(MOS6522State *s) 913 + { 914 + if (s->dirb & VIA2B_vPower && (s->b & VIA2B_vPower) == 0) { 915 + /* shutdown */ 916 + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 917 + } 918 + } 919 + 920 + static void mos6522_q800_via2_reset(DeviceState *dev) 921 + { 922 + MOS6522State *ms = MOS6522(dev); 923 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms); 924 + 925 + mdc->parent_reset(dev); 926 + 927 + ms->timers[0].frequency = VIA_TIMER_FREQ; 928 + ms->timers[1].frequency = VIA_TIMER_FREQ; 929 + 930 + ms->dirb = 0; 931 + ms->b = 0; 932 + } 933 + 934 + static void mos6522_q800_via2_init(Object *obj) 935 + { 936 + qdev_init_gpio_in_named(DEVICE(obj), via2_irq_request, "via2-irq", 937 + VIA2_IRQ_NB); 938 + } 939 + 940 + static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data) 941 + { 942 + DeviceClass *dc = DEVICE_CLASS(oc); 943 + MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc); 944 + 945 + dc->reset = mos6522_q800_via2_reset; 946 + mdc->portB_write = mos6522_q800_via2_portB_write; 947 + } 948 + 949 + static const TypeInfo mos6522_q800_via2_type_info = { 950 + .name = TYPE_MOS6522_Q800_VIA2, 951 + .parent = TYPE_MOS6522, 952 + .instance_size = sizeof(MOS6522Q800VIA2State), 953 + .instance_init = mos6522_q800_via2_init, 954 + .class_init = mos6522_q800_via2_class_init, 955 + }; 956 + 957 + static void mac_via_register_types(void) 958 + { 959 + type_register_static(&mos6522_q800_via1_type_info); 960 + type_register_static(&mos6522_q800_via2_type_info); 961 + type_register_static(&mac_via_info); 962 + } 963 + 964 + type_init(mac_via_register_types);
+57 -31
hw/net/dp8393x.c
··· 153 153 154 154 /* Hardware */ 155 155 uint8_t it_shift; 156 + bool big_endian; 156 157 qemu_irq irq; 157 158 #ifdef DEBUG_SONIC 158 159 int irq_level; ··· 223 224 return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; 224 225 } 225 226 227 + static uint16_t dp8393x_get(dp8393xState *s, int width, uint16_t *base, 228 + int offset) 229 + { 230 + uint16_t val; 231 + 232 + if (s->big_endian) { 233 + val = be16_to_cpu(base[offset * width + width - 1]); 234 + } else { 235 + val = le16_to_cpu(base[offset * width]); 236 + } 237 + return val; 238 + } 239 + 240 + static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset, 241 + uint16_t val) 242 + { 243 + if (s->big_endian) { 244 + base[offset * width + width - 1] = cpu_to_be16(val); 245 + } else { 246 + base[offset * width] = cpu_to_le16(val); 247 + } 248 + } 249 + 226 250 static void dp8393x_update_irq(dp8393xState *s) 227 251 { 228 252 int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0; ··· 254 278 /* Fill current entry */ 255 279 address_space_rw(&s->as, dp8393x_cdp(s), 256 280 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); 257 - s->cam[index][0] = data[1 * width] & 0xff; 258 - s->cam[index][1] = data[1 * width] >> 8; 259 - s->cam[index][2] = data[2 * width] & 0xff; 260 - s->cam[index][3] = data[2 * width] >> 8; 261 - s->cam[index][4] = data[3 * width] & 0xff; 262 - s->cam[index][5] = data[3 * width] >> 8; 281 + s->cam[index][0] = dp8393x_get(s, width, data, 1) & 0xff; 282 + s->cam[index][1] = dp8393x_get(s, width, data, 1) >> 8; 283 + s->cam[index][2] = dp8393x_get(s, width, data, 2) & 0xff; 284 + s->cam[index][3] = dp8393x_get(s, width, data, 2) >> 8; 285 + s->cam[index][4] = dp8393x_get(s, width, data, 3) & 0xff; 286 + s->cam[index][5] = dp8393x_get(s, width, data, 3) >> 8; 263 287 DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index, 264 288 s->cam[index][0], s->cam[index][1], s->cam[index][2], 265 289 s->cam[index][3], s->cam[index][4], s->cam[index][5]); ··· 272 296 /* Read CAM enable */ 273 297 address_space_rw(&s->as, dp8393x_cdp(s), 274 298 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); 275 - s->regs[SONIC_CE] = data[0 * width]; 299 + s->regs[SONIC_CE] = dp8393x_get(s, width, data, 0); 276 300 DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); 277 301 278 302 /* Done */ ··· 293 317 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); 294 318 295 319 /* Update SONIC registers */ 296 - s->regs[SONIC_CRBA0] = data[0 * width]; 297 - s->regs[SONIC_CRBA1] = data[1 * width]; 298 - s->regs[SONIC_RBWC0] = data[2 * width]; 299 - s->regs[SONIC_RBWC1] = data[3 * width]; 320 + s->regs[SONIC_CRBA0] = dp8393x_get(s, width, data, 0); 321 + s->regs[SONIC_CRBA1] = dp8393x_get(s, width, data, 1); 322 + s->regs[SONIC_RBWC0] = dp8393x_get(s, width, data, 2); 323 + s->regs[SONIC_RBWC1] = dp8393x_get(s, width, data, 3); 300 324 DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n", 301 325 s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1], 302 326 s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]); ··· 411 435 tx_len = 0; 412 436 413 437 /* Update registers */ 414 - s->regs[SONIC_TCR] = data[0 * width] & 0xf000; 415 - s->regs[SONIC_TPS] = data[1 * width]; 416 - s->regs[SONIC_TFC] = data[2 * width]; 417 - s->regs[SONIC_TSA0] = data[3 * width]; 418 - s->regs[SONIC_TSA1] = data[4 * width]; 419 - s->regs[SONIC_TFS] = data[5 * width]; 438 + s->regs[SONIC_TCR] = dp8393x_get(s, width, data, 0) & 0xf000; 439 + s->regs[SONIC_TPS] = dp8393x_get(s, width, data, 1); 440 + s->regs[SONIC_TFC] = dp8393x_get(s, width, data, 2); 441 + s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 3); 442 + s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 4); 443 + s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 5); 420 444 421 445 /* Handle programmable interrupt */ 422 446 if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) { ··· 442 466 address_space_rw(&s->as, 443 467 dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width, 444 468 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); 445 - s->regs[SONIC_TSA0] = data[0 * width]; 446 - s->regs[SONIC_TSA1] = data[1 * width]; 447 - s->regs[SONIC_TFS] = data[2 * width]; 469 + s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 0); 470 + s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 1); 471 + s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 2); 448 472 } 449 473 } 450 474 ··· 471 495 s->regs[SONIC_TCR] |= SONIC_TCR_PTX; 472 496 473 497 /* Write status */ 474 - data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ 498 + dp8393x_put(s, width, data, 0, 499 + s->regs[SONIC_TCR] & 0x0fff); /* status */ 475 500 size = sizeof(uint16_t) * width; 476 501 address_space_rw(&s->as, 477 502 dp8393x_ttda(s), ··· 485 510 sizeof(uint16_t) * 486 511 (4 + 3 * s->regs[SONIC_TFC]) * width, 487 512 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); 488 - s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; 489 - if (data[0 * width] & 0x1) { 513 + s->regs[SONIC_CTDA] = dp8393x_get(s, width, data, 0) & ~0x1; 514 + if (dp8393x_get(s, width, data, 0) & 0x1) { 490 515 /* EOL detected */ 491 516 break; 492 517 } ··· 749 774 address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width; 750 775 address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, 751 776 (uint8_t *)data, size, 0); 752 - if (data[0 * width] & 0x1) { 777 + if (dp8393x_get(s, width, data, 0) & 0x1) { 753 778 /* Still EOL ; stop reception */ 754 779 return -1; 755 780 } else { ··· 793 818 794 819 /* Write status to memory */ 795 820 DPRINTF("Write status at %08x\n", dp8393x_crda(s)); 796 - data[0 * width] = s->regs[SONIC_RCR]; /* status */ 797 - data[1 * width] = rx_len; /* byte count */ 798 - data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */ 799 - data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ 800 - data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ 821 + dp8393x_put(s, width, data, 0, s->regs[SONIC_RCR]); /* status */ 822 + dp8393x_put(s, width, data, 1, rx_len); /* byte count */ 823 + dp8393x_put(s, width, data, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */ 824 + dp8393x_put(s, width, data, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */ 825 + dp8393x_put(s, width, data, 4, s->regs[SONIC_RSC]); /* seq_no */ 801 826 size = sizeof(uint16_t) * 5 * width; 802 827 address_space_rw(&s->as, dp8393x_crda(s), 803 828 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); ··· 806 831 size = sizeof(uint16_t) * width; 807 832 address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width, 808 833 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); 809 - s->regs[SONIC_LLFA] = data[0 * width]; 834 + s->regs[SONIC_LLFA] = dp8393x_get(s, width, data, 0); 810 835 if (s->regs[SONIC_LLFA] & 0x1) { 811 836 /* EOL detected */ 812 837 s->regs[SONIC_ISR] |= SONIC_ISR_RDE; 813 838 } else { 814 - data[0 * width] = 0; /* in_use */ 839 + dp8393x_put(s, width, data, 0, 0); /* in_use */ 815 840 address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width, 816 841 MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); 817 842 s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; ··· 924 949 DEFINE_NIC_PROPERTIES(dp8393xState, conf), 925 950 DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr), 926 951 DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0), 952 + DEFINE_PROP_BOOL("big_endian", dp8393xState, big_endian, false), 927 953 DEFINE_PROP_END_OF_LIST(), 928 954 }; 929 955
+2
hw/nubus/Kconfig
··· 1 + config NUBUS 2 + bool
+4
hw/nubus/Makefile.objs
··· 1 + common-obj-y += nubus-device.o 2 + common-obj-y += nubus-bus.o 3 + common-obj-y += nubus-bridge.o 4 + common-obj-$(CONFIG_Q800) += mac-nubus-bridge.o
+45
hw/nubus/mac-nubus-bridge.c
··· 1 + /* 2 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 3 + * 4 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 + * See the COPYING file in the top-level directory. 6 + * 7 + */ 8 + 9 + #include "qemu/osdep.h" 10 + #include "hw/sysbus.h" 11 + #include "hw/nubus/mac-nubus-bridge.h" 12 + 13 + 14 + static void mac_nubus_bridge_init(Object *obj) 15 + { 16 + MacNubusState *s = MAC_NUBUS_BRIDGE(obj); 17 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 18 + 19 + s->bus = NUBUS_BUS(qbus_create(TYPE_NUBUS_BUS, DEVICE(s), NULL)); 20 + 21 + sysbus_init_mmio(sbd, &s->bus->super_slot_io); 22 + sysbus_init_mmio(sbd, &s->bus->slot_io); 23 + } 24 + 25 + static void mac_nubus_bridge_class_init(ObjectClass *klass, void *data) 26 + { 27 + DeviceClass *dc = DEVICE_CLASS(klass); 28 + 29 + dc->desc = "Nubus bridge"; 30 + } 31 + 32 + static const TypeInfo mac_nubus_bridge_info = { 33 + .name = TYPE_MAC_NUBUS_BRIDGE, 34 + .parent = TYPE_NUBUS_BRIDGE, 35 + .instance_init = mac_nubus_bridge_init, 36 + .instance_size = sizeof(MacNubusState), 37 + .class_init = mac_nubus_bridge_class_init, 38 + }; 39 + 40 + static void mac_nubus_bridge_register_types(void) 41 + { 42 + type_register_static(&mac_nubus_bridge_info); 43 + } 44 + 45 + type_init(mac_nubus_bridge_register_types)
+34
hw/nubus/nubus-bridge.c
··· 1 + /* 2 + * QEMU Macintosh Nubus 3 + * 4 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 5 + * 6 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 + * See the COPYING file in the top-level directory. 8 + * 9 + */ 10 + 11 + #include "qemu/osdep.h" 12 + #include "hw/sysbus.h" 13 + #include "hw/nubus/nubus.h" 14 + 15 + static void nubus_bridge_class_init(ObjectClass *klass, void *data) 16 + { 17 + DeviceClass *dc = DEVICE_CLASS(klass); 18 + 19 + dc->fw_name = "nubus"; 20 + } 21 + 22 + static const TypeInfo nubus_bridge_info = { 23 + .name = TYPE_NUBUS_BRIDGE, 24 + .parent = TYPE_SYS_BUS_DEVICE, 25 + .instance_size = sizeof(SysBusDevice), 26 + .class_init = nubus_bridge_class_init, 27 + }; 28 + 29 + static void nubus_register_types(void) 30 + { 31 + type_register_static(&nubus_bridge_info); 32 + } 33 + 34 + type_init(nubus_register_types)
+111
hw/nubus/nubus-bus.c
··· 1 + /* 2 + * QEMU Macintosh Nubus 3 + * 4 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 5 + * 6 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 + * See the COPYING file in the top-level directory. 8 + * 9 + */ 10 + 11 + #include "qemu/osdep.h" 12 + #include "hw/nubus/nubus.h" 13 + #include "hw/sysbus.h" 14 + #include "qapi/error.h" 15 + 16 + 17 + static NubusBus *nubus_find(void) 18 + { 19 + /* Returns NULL unless there is exactly one nubus device */ 20 + return NUBUS_BUS(object_resolve_path_type("", TYPE_NUBUS_BUS, NULL)); 21 + } 22 + 23 + static void nubus_slot_write(void *opaque, hwaddr addr, uint64_t val, 24 + unsigned int size) 25 + { 26 + /* read only */ 27 + } 28 + 29 + 30 + static uint64_t nubus_slot_read(void *opaque, hwaddr addr, 31 + unsigned int size) 32 + { 33 + return 0; 34 + } 35 + 36 + static const MemoryRegionOps nubus_slot_ops = { 37 + .read = nubus_slot_read, 38 + .write = nubus_slot_write, 39 + .endianness = DEVICE_BIG_ENDIAN, 40 + .valid = { 41 + .min_access_size = 1, 42 + .max_access_size = 1, 43 + }, 44 + }; 45 + 46 + static void nubus_super_slot_write(void *opaque, hwaddr addr, uint64_t val, 47 + unsigned int size) 48 + { 49 + /* read only */ 50 + } 51 + 52 + static uint64_t nubus_super_slot_read(void *opaque, hwaddr addr, 53 + unsigned int size) 54 + { 55 + return 0; 56 + } 57 + 58 + static const MemoryRegionOps nubus_super_slot_ops = { 59 + .read = nubus_super_slot_read, 60 + .write = nubus_super_slot_write, 61 + .endianness = DEVICE_BIG_ENDIAN, 62 + .valid = { 63 + .min_access_size = 1, 64 + .max_access_size = 1, 65 + }, 66 + }; 67 + 68 + static void nubus_realize(BusState *bus, Error **errp) 69 + { 70 + if (!nubus_find()) { 71 + error_setg(errp, "at most one %s device is permitted", TYPE_NUBUS_BUS); 72 + return; 73 + } 74 + } 75 + 76 + static void nubus_init(Object *obj) 77 + { 78 + NubusBus *nubus = NUBUS_BUS(obj); 79 + 80 + memory_region_init_io(&nubus->super_slot_io, obj, &nubus_super_slot_ops, 81 + nubus, "nubus-super-slots", 82 + NUBUS_SUPER_SLOT_NB * NUBUS_SUPER_SLOT_SIZE); 83 + 84 + memory_region_init_io(&nubus->slot_io, obj, &nubus_slot_ops, 85 + nubus, "nubus-slots", 86 + NUBUS_SLOT_NB * NUBUS_SLOT_SIZE); 87 + 88 + nubus->current_slot = NUBUS_FIRST_SLOT; 89 + } 90 + 91 + static void nubus_class_init(ObjectClass *oc, void *data) 92 + { 93 + BusClass *bc = BUS_CLASS(oc); 94 + 95 + bc->realize = nubus_realize; 96 + } 97 + 98 + static const TypeInfo nubus_bus_info = { 99 + .name = TYPE_NUBUS_BUS, 100 + .parent = TYPE_BUS, 101 + .instance_size = sizeof(NubusBus), 102 + .instance_init = nubus_init, 103 + .class_init = nubus_class_init, 104 + }; 105 + 106 + static void nubus_register_types(void) 107 + { 108 + type_register_static(&nubus_bus_info); 109 + } 110 + 111 + type_init(nubus_register_types)
+215
hw/nubus/nubus-device.c
··· 1 + /* 2 + * QEMU Macintosh Nubus 3 + * 4 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 5 + * 6 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 + * See the COPYING file in the top-level directory. 8 + * 9 + */ 10 + 11 + #include "qemu/osdep.h" 12 + #include "hw/nubus/nubus.h" 13 + #include "qapi/error.h" 14 + 15 + 16 + /* The Format Block Structure */ 17 + 18 + #define FBLOCK_DIRECTORY_OFFSET 0 19 + #define FBLOCK_LENGTH 4 20 + #define FBLOCK_CRC 8 21 + #define FBLOCK_REVISION_LEVEL 12 22 + #define FBLOCK_FORMAT 13 23 + #define FBLOCK_TEST_PATTERN 14 24 + #define FBLOCK_RESERVED 18 25 + #define FBLOCK_BYTE_LANES 19 26 + 27 + #define FBLOCK_SIZE 20 28 + #define FBLOCK_PATTERN_VAL 0x5a932bc7 29 + 30 + static uint64_t nubus_fblock_read(void *opaque, hwaddr addr, unsigned int size) 31 + { 32 + NubusDevice *dev = opaque; 33 + uint64_t val; 34 + 35 + #define BYTE(v, b) (((v) >> (24 - 8 * (b))) & 0xff) 36 + switch (addr) { 37 + case FBLOCK_BYTE_LANES: 38 + val = dev->byte_lanes; 39 + val |= (val ^ 0xf) << 4; 40 + break; 41 + case FBLOCK_RESERVED: 42 + val = 0x00; 43 + break; 44 + case FBLOCK_TEST_PATTERN...FBLOCK_TEST_PATTERN + 3: 45 + val = BYTE(FBLOCK_PATTERN_VAL, addr - FBLOCK_TEST_PATTERN); 46 + break; 47 + case FBLOCK_FORMAT: 48 + val = dev->rom_format; 49 + break; 50 + case FBLOCK_REVISION_LEVEL: 51 + val = dev->rom_rev; 52 + break; 53 + case FBLOCK_CRC...FBLOCK_CRC + 3: 54 + val = BYTE(dev->rom_crc, addr - FBLOCK_CRC); 55 + break; 56 + case FBLOCK_LENGTH...FBLOCK_LENGTH + 3: 57 + val = BYTE(dev->rom_length, addr - FBLOCK_LENGTH); 58 + break; 59 + case FBLOCK_DIRECTORY_OFFSET...FBLOCK_DIRECTORY_OFFSET + 3: 60 + val = BYTE(dev->directory_offset, addr - FBLOCK_DIRECTORY_OFFSET); 61 + break; 62 + default: 63 + val = 0; 64 + break; 65 + } 66 + return val; 67 + } 68 + 69 + static void nubus_fblock_write(void *opaque, hwaddr addr, uint64_t val, 70 + unsigned int size) 71 + { 72 + /* read only */ 73 + } 74 + 75 + static const MemoryRegionOps nubus_format_block_ops = { 76 + .read = nubus_fblock_read, 77 + .write = nubus_fblock_write, 78 + .endianness = DEVICE_BIG_ENDIAN, 79 + .valid = { 80 + .min_access_size = 1, 81 + .max_access_size = 1, 82 + } 83 + }; 84 + 85 + static void nubus_register_format_block(NubusDevice *dev) 86 + { 87 + char *fblock_name; 88 + 89 + fblock_name = g_strdup_printf("nubus-slot-%d-format-block", 90 + dev->slot_nb); 91 + 92 + hwaddr fblock_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE; 93 + memory_region_init_io(&dev->fblock_io, NULL, &nubus_format_block_ops, 94 + dev, fblock_name, FBLOCK_SIZE); 95 + memory_region_add_subregion(&dev->slot_mem, fblock_offset, 96 + &dev->fblock_io); 97 + 98 + g_free(fblock_name); 99 + } 100 + 101 + static void mac_nubus_rom_write(void *opaque, hwaddr addr, uint64_t val, 102 + unsigned int size) 103 + { 104 + /* read only */ 105 + } 106 + 107 + static uint64_t mac_nubus_rom_read(void *opaque, hwaddr addr, 108 + unsigned int size) 109 + { 110 + NubusDevice *dev = opaque; 111 + 112 + return dev->rom[addr]; 113 + } 114 + 115 + static const MemoryRegionOps mac_nubus_rom_ops = { 116 + .read = mac_nubus_rom_read, 117 + .write = mac_nubus_rom_write, 118 + .endianness = DEVICE_BIG_ENDIAN, 119 + .valid = { 120 + .min_access_size = 1, 121 + .max_access_size = 1, 122 + }, 123 + }; 124 + 125 + 126 + void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, 127 + int revision, int format, uint8_t byte_lanes) 128 + { 129 + hwaddr rom_offset; 130 + char *rom_name; 131 + 132 + /* FIXME : really compute CRC */ 133 + dev->rom_length = 0; 134 + dev->rom_crc = 0; 135 + 136 + dev->rom_rev = revision; 137 + dev->rom_format = format; 138 + 139 + dev->byte_lanes = byte_lanes; 140 + dev->directory_offset = -size; 141 + 142 + /* ROM */ 143 + 144 + dev->rom = rom; 145 + rom_name = g_strdup_printf("nubus-slot-%d-rom", dev->slot_nb); 146 + memory_region_init_io(&dev->rom_io, NULL, &mac_nubus_rom_ops, 147 + dev, rom_name, size); 148 + memory_region_set_readonly(&dev->rom_io, true); 149 + 150 + rom_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE + 151 + dev->directory_offset; 152 + memory_region_add_subregion(&dev->slot_mem, rom_offset, &dev->rom_io); 153 + 154 + g_free(rom_name); 155 + } 156 + 157 + static void nubus_device_realize(DeviceState *dev, Error **errp) 158 + { 159 + NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(DEVICE(dev))); 160 + NubusDevice *nd = NUBUS_DEVICE(dev); 161 + char *name; 162 + hwaddr slot_offset; 163 + 164 + if (nubus->current_slot < NUBUS_FIRST_SLOT || 165 + nubus->current_slot > NUBUS_LAST_SLOT) { 166 + error_setg(errp, "Cannot register nubus card, not enough slots"); 167 + return; 168 + } 169 + 170 + nd->slot_nb = nubus->current_slot++; 171 + name = g_strdup_printf("nubus-slot-%d", nd->slot_nb); 172 + 173 + if (nd->slot_nb < NUBUS_FIRST_SLOT) { 174 + /* Super */ 175 + slot_offset = (nd->slot_nb - 6) * NUBUS_SUPER_SLOT_SIZE; 176 + 177 + memory_region_init(&nd->slot_mem, OBJECT(dev), name, 178 + NUBUS_SUPER_SLOT_SIZE); 179 + memory_region_add_subregion(&nubus->super_slot_io, slot_offset, 180 + &nd->slot_mem); 181 + } else { 182 + /* Normal */ 183 + slot_offset = nd->slot_nb * NUBUS_SLOT_SIZE; 184 + 185 + memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE); 186 + memory_region_add_subregion(&nubus->slot_io, slot_offset, 187 + &nd->slot_mem); 188 + } 189 + 190 + g_free(name); 191 + nubus_register_format_block(nd); 192 + } 193 + 194 + static void nubus_device_class_init(ObjectClass *oc, void *data) 195 + { 196 + DeviceClass *dc = DEVICE_CLASS(oc); 197 + 198 + dc->realize = nubus_device_realize; 199 + dc->bus_type = TYPE_NUBUS_BUS; 200 + } 201 + 202 + static const TypeInfo nubus_device_type_info = { 203 + .name = TYPE_NUBUS_DEVICE, 204 + .parent = TYPE_DEVICE, 205 + .abstract = true, 206 + .instance_size = sizeof(NubusDevice), 207 + .class_init = nubus_device_class_init, 208 + }; 209 + 210 + static void nubus_register_types(void) 211 + { 212 + type_register_static(&nubus_device_type_info); 213 + } 214 + 215 + type_init(nubus_register_types)
+308 -28
hw/scsi/esp.c
··· 38 38 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt 39 39 * and 40 40 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt 41 + * 42 + * On Macintosh Quadra it is a NCR53C96. 41 43 */ 42 44 43 45 static void esp_raise_irq(ESPState *s) ··· 58 60 } 59 61 } 60 62 63 + static void esp_raise_drq(ESPState *s) 64 + { 65 + qemu_irq_raise(s->irq_data); 66 + } 67 + 68 + static void esp_lower_drq(ESPState *s) 69 + { 70 + qemu_irq_lower(s->irq_data); 71 + } 72 + 61 73 void esp_dma_enable(ESPState *s, int irq, int level) 62 74 { 63 75 if (level) { ··· 84 96 } 85 97 } 86 98 99 + static void set_pdma(ESPState *s, enum pdma_origin_id origin, 100 + uint32_t index, uint32_t len) 101 + { 102 + s->pdma_origin = origin; 103 + s->pdma_start = index; 104 + s->pdma_cur = index; 105 + s->pdma_len = len; 106 + } 107 + 108 + static uint8_t *get_pdma_buf(ESPState *s) 109 + { 110 + switch (s->pdma_origin) { 111 + case PDMA: 112 + return s->pdma_buf; 113 + case TI: 114 + return s->ti_buf; 115 + case CMD: 116 + return s->cmdbuf; 117 + case ASYNC: 118 + return s->async_buf; 119 + } 120 + return NULL; 121 + } 122 + 123 + static int get_cmd_cb(ESPState *s) 124 + { 125 + int target; 126 + 127 + target = s->wregs[ESP_WBUSID] & BUSID_DID; 128 + 129 + s->ti_size = 0; 130 + s->ti_rptr = 0; 131 + s->ti_wptr = 0; 132 + 133 + if (s->current_req) { 134 + /* Started a new command before the old one finished. Cancel it. */ 135 + scsi_req_cancel(s->current_req); 136 + s->async_len = 0; 137 + } 138 + 139 + s->current_dev = scsi_device_find(&s->bus, 0, target, 0); 140 + if (!s->current_dev) { 141 + /* No such drive */ 142 + s->rregs[ESP_RSTAT] = 0; 143 + s->rregs[ESP_RINTR] = INTR_DC; 144 + s->rregs[ESP_RSEQ] = SEQ_0; 145 + esp_raise_irq(s); 146 + return -1; 147 + } 148 + return 0; 149 + } 150 + 87 151 static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) 88 152 { 89 153 uint32_t dmalen; ··· 97 161 if (dmalen > buflen) { 98 162 return 0; 99 163 } 100 - s->dma_memory_read(s->dma_opaque, buf, dmalen); 164 + if (s->dma_memory_read) { 165 + s->dma_memory_read(s->dma_opaque, buf, dmalen); 166 + } else { 167 + memcpy(s->pdma_buf, buf, dmalen); 168 + set_pdma(s, PDMA, 0, dmalen); 169 + esp_raise_drq(s); 170 + return 0; 171 + } 101 172 } else { 102 173 dmalen = s->ti_size; 103 174 if (dmalen > TI_BUFSZ) { ··· 108 179 } 109 180 trace_esp_get_cmd(dmalen, target); 110 181 111 - s->ti_size = 0; 112 - s->ti_rptr = 0; 113 - s->ti_wptr = 0; 114 - 115 - if (s->current_req) { 116 - /* Started a new command before the old one finished. Cancel it. */ 117 - scsi_req_cancel(s->current_req); 118 - s->async_len = 0; 119 - } 120 - 121 - s->current_dev = scsi_device_find(&s->bus, 0, target, 0); 122 - if (!s->current_dev) { 123 - // No such drive 124 - s->rregs[ESP_RSTAT] = 0; 125 - s->rregs[ESP_RINTR] = INTR_DC; 126 - s->rregs[ESP_RSEQ] = SEQ_0; 127 - esp_raise_irq(s); 182 + if (get_cmd_cb(s) < 0) { 128 183 return 0; 129 184 } 130 185 return dmalen; ··· 165 220 do_busid_cmd(s, &buf[1], busid); 166 221 } 167 222 223 + static void satn_pdma_cb(ESPState *s) 224 + { 225 + if (get_cmd_cb(s) < 0) { 226 + return; 227 + } 228 + if (s->pdma_cur != s->pdma_start) { 229 + do_cmd(s, get_pdma_buf(s) + s->pdma_start); 230 + } 231 + } 232 + 168 233 static void handle_satn(ESPState *s) 169 234 { 170 235 uint8_t buf[32]; ··· 174 239 s->dma_cb = handle_satn; 175 240 return; 176 241 } 242 + s->pdma_cb = satn_pdma_cb; 177 243 len = get_cmd(s, buf, sizeof(buf)); 178 244 if (len) 179 245 do_cmd(s, buf); 180 246 } 181 247 248 + static void s_without_satn_pdma_cb(ESPState *s) 249 + { 250 + if (get_cmd_cb(s) < 0) { 251 + return; 252 + } 253 + if (s->pdma_cur != s->pdma_start) { 254 + do_busid_cmd(s, get_pdma_buf(s) + s->pdma_start, 0); 255 + } 256 + } 257 + 182 258 static void handle_s_without_atn(ESPState *s) 183 259 { 184 260 uint8_t buf[32]; ··· 188 264 s->dma_cb = handle_s_without_atn; 189 265 return; 190 266 } 267 + s->pdma_cb = s_without_satn_pdma_cb; 191 268 len = get_cmd(s, buf, sizeof(buf)); 192 269 if (len) { 193 270 do_busid_cmd(s, buf, 0); 194 271 } 195 272 } 196 273 274 + static void satn_stop_pdma_cb(ESPState *s) 275 + { 276 + if (get_cmd_cb(s) < 0) { 277 + return; 278 + } 279 + s->cmdlen = s->pdma_cur - s->pdma_start; 280 + if (s->cmdlen) { 281 + trace_esp_handle_satn_stop(s->cmdlen); 282 + s->do_cmd = 1; 283 + s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; 284 + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 285 + s->rregs[ESP_RSEQ] = SEQ_CD; 286 + esp_raise_irq(s); 287 + } 288 + } 289 + 197 290 static void handle_satn_stop(ESPState *s) 198 291 { 199 292 if (s->dma && !s->dma_enabled) { 200 293 s->dma_cb = handle_satn_stop; 201 294 return; 202 295 } 296 + s->pdma_cb = satn_stop_pdma_cb;; 203 297 s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf)); 204 298 if (s->cmdlen) { 205 299 trace_esp_handle_satn_stop(s->cmdlen); ··· 211 305 } 212 306 } 213 307 308 + static void write_response_pdma_cb(ESPState *s) 309 + { 310 + s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 311 + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 312 + s->rregs[ESP_RSEQ] = SEQ_CD; 313 + esp_raise_irq(s); 314 + } 315 + 214 316 static void write_response(ESPState *s) 215 317 { 216 318 trace_esp_write_response(s->status); 217 319 s->ti_buf[0] = s->status; 218 320 s->ti_buf[1] = 0; 219 321 if (s->dma) { 220 - s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); 221 - s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 222 - s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 223 - s->rregs[ESP_RSEQ] = SEQ_CD; 322 + if (s->dma_memory_write) { 323 + s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); 324 + s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 325 + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 326 + s->rregs[ESP_RSEQ] = SEQ_CD; 327 + } else { 328 + set_pdma(s, TI, 0, 2); 329 + s->pdma_cb = write_response_pdma_cb; 330 + esp_raise_drq(s); 331 + return; 332 + } 224 333 } else { 225 334 s->ti_size = 2; 226 335 s->ti_rptr = 0; ··· 242 351 esp_raise_irq(s); 243 352 } 244 353 354 + static void do_dma_pdma_cb(ESPState *s) 355 + { 356 + int to_device = (s->ti_size < 0); 357 + int len = s->pdma_cur - s->pdma_start; 358 + if (s->do_cmd) { 359 + s->ti_size = 0; 360 + s->cmdlen = 0; 361 + s->do_cmd = 0; 362 + do_cmd(s, s->cmdbuf); 363 + return; 364 + } 365 + s->dma_left -= len; 366 + s->async_buf += len; 367 + s->async_len -= len; 368 + if (to_device) { 369 + s->ti_size += len; 370 + } else { 371 + s->ti_size -= len; 372 + } 373 + if (s->async_len == 0) { 374 + scsi_req_continue(s->current_req); 375 + /* 376 + * If there is still data to be read from the device then 377 + * complete the DMA operation immediately. Otherwise defer 378 + * until the scsi layer has completed. 379 + */ 380 + if (to_device || s->dma_left != 0 || s->ti_size == 0) { 381 + return; 382 + } 383 + } 384 + 385 + /* Partially filled a scsi buffer. Complete immediately. */ 386 + esp_dma_done(s); 387 + } 388 + 245 389 static void esp_do_dma(ESPState *s) 246 390 { 247 391 uint32_t len; ··· 249 393 250 394 len = s->dma_left; 251 395 if (s->do_cmd) { 396 + /* 397 + * handle_ti_cmd() case: esp_do_dma() is called only from 398 + * handle_ti_cmd() with do_cmd != NULL (see the assert()) 399 + */ 252 400 trace_esp_do_dma(s->cmdlen, len); 253 401 assert (s->cmdlen <= sizeof(s->cmdbuf) && 254 402 len <= sizeof(s->cmdbuf) - s->cmdlen); 255 - s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); 403 + if (s->dma_memory_read) { 404 + s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); 405 + } else { 406 + set_pdma(s, CMD, s->cmdlen, len); 407 + s->pdma_cb = do_dma_pdma_cb; 408 + esp_raise_drq(s); 409 + return; 410 + } 411 + trace_esp_handle_ti_cmd(s->cmdlen); 412 + s->ti_size = 0; 413 + s->cmdlen = 0; 414 + s->do_cmd = 0; 415 + do_cmd(s, s->cmdbuf); 256 416 return; 257 417 } 258 418 if (s->async_len == 0) { ··· 264 424 } 265 425 to_device = (s->ti_size < 0); 266 426 if (to_device) { 267 - s->dma_memory_read(s->dma_opaque, s->async_buf, len); 427 + if (s->dma_memory_read) { 428 + s->dma_memory_read(s->dma_opaque, s->async_buf, len); 429 + } else { 430 + set_pdma(s, ASYNC, 0, len); 431 + s->pdma_cb = do_dma_pdma_cb; 432 + esp_raise_drq(s); 433 + return; 434 + } 268 435 } else { 269 - s->dma_memory_write(s->dma_opaque, s->async_buf, len); 436 + if (s->dma_memory_write) { 437 + s->dma_memory_write(s->dma_opaque, s->async_buf, len); 438 + } else { 439 + set_pdma(s, ASYNC, 0, len); 440 + s->pdma_cb = do_dma_pdma_cb; 441 + esp_raise_drq(s); 442 + return; 443 + } 270 444 } 271 445 s->dma_left -= len; 272 446 s->async_buf += len; ··· 373 547 s->dma_left = minlen; 374 548 s->rregs[ESP_RSTAT] &= ~STAT_TC; 375 549 esp_do_dma(s); 376 - } 377 - if (s->do_cmd) { 550 + } else if (s->do_cmd) { 378 551 trace_esp_handle_ti_cmd(s->cmdlen); 379 552 s->ti_size = 0; 380 553 s->cmdlen = 0; ··· 401 574 static void esp_soft_reset(ESPState *s) 402 575 { 403 576 qemu_irq_lower(s->irq); 577 + qemu_irq_lower(s->irq_data); 404 578 esp_hard_reset(s); 405 579 } 406 580 ··· 590 764 return (size == 1) || (is_write && size == 4); 591 765 } 592 766 767 + static bool esp_pdma_needed(void *opaque) 768 + { 769 + ESPState *s = opaque; 770 + return s->dma_memory_read == NULL && s->dma_memory_write == NULL && 771 + s->dma_enabled; 772 + } 773 + 774 + static const VMStateDescription vmstate_esp_pdma = { 775 + .name = "esp/pdma", 776 + .version_id = 1, 777 + .minimum_version_id = 1, 778 + .needed = esp_pdma_needed, 779 + .fields = (VMStateField[]) { 780 + VMSTATE_BUFFER(pdma_buf, ESPState), 781 + VMSTATE_INT32(pdma_origin, ESPState), 782 + VMSTATE_UINT32(pdma_len, ESPState), 783 + VMSTATE_UINT32(pdma_start, ESPState), 784 + VMSTATE_UINT32(pdma_cur, ESPState), 785 + VMSTATE_END_OF_LIST() 786 + } 787 + }; 788 + 593 789 const VMStateDescription vmstate_esp = { 594 790 .name ="esp", 595 791 .version_id = 4, ··· 611 807 VMSTATE_UINT32(do_cmd, ESPState), 612 808 VMSTATE_UINT32(dma_left, ESPState), 613 809 VMSTATE_END_OF_LIST() 810 + }, 811 + .subsections = (const VMStateDescription * []) { 812 + &vmstate_esp_pdma, 813 + NULL 614 814 } 615 815 }; 616 816 ··· 641 841 .valid.accepts = esp_mem_accepts, 642 842 }; 643 843 844 + static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, 845 + uint64_t val, unsigned int size) 846 + { 847 + SysBusESPState *sysbus = opaque; 848 + ESPState *s = &sysbus->esp; 849 + uint32_t dmalen; 850 + uint8_t *buf = get_pdma_buf(s); 851 + 852 + dmalen = s->rregs[ESP_TCLO]; 853 + dmalen |= s->rregs[ESP_TCMID] << 8; 854 + dmalen |= s->rregs[ESP_TCHI] << 16; 855 + if (dmalen == 0 || s->pdma_len == 0) { 856 + return; 857 + } 858 + switch (size) { 859 + case 1: 860 + buf[s->pdma_cur++] = val; 861 + s->pdma_len--; 862 + dmalen--; 863 + break; 864 + case 2: 865 + buf[s->pdma_cur++] = val >> 8; 866 + buf[s->pdma_cur++] = val; 867 + s->pdma_len -= 2; 868 + dmalen -= 2; 869 + break; 870 + } 871 + s->rregs[ESP_TCLO] = dmalen & 0xff; 872 + s->rregs[ESP_TCMID] = dmalen >> 8; 873 + s->rregs[ESP_TCHI] = dmalen >> 16; 874 + if (s->pdma_len == 0 && s->pdma_cb) { 875 + esp_lower_drq(s); 876 + s->pdma_cb(s); 877 + s->pdma_cb = NULL; 878 + } 879 + } 880 + 881 + static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, 882 + unsigned int size) 883 + { 884 + SysBusESPState *sysbus = opaque; 885 + ESPState *s = &sysbus->esp; 886 + uint8_t *buf = get_pdma_buf(s); 887 + uint64_t val = 0; 888 + 889 + if (s->pdma_len == 0) { 890 + return 0; 891 + } 892 + switch (size) { 893 + case 1: 894 + val = buf[s->pdma_cur++]; 895 + s->pdma_len--; 896 + break; 897 + case 2: 898 + val = buf[s->pdma_cur++]; 899 + val = (val << 8) | buf[s->pdma_cur++]; 900 + s->pdma_len -= 2; 901 + break; 902 + } 903 + 904 + if (s->pdma_len == 0 && s->pdma_cb) { 905 + esp_lower_drq(s); 906 + s->pdma_cb(s); 907 + s->pdma_cb = NULL; 908 + } 909 + return val; 910 + } 911 + 912 + static const MemoryRegionOps sysbus_esp_pdma_ops = { 913 + .read = sysbus_esp_pdma_read, 914 + .write = sysbus_esp_pdma_write, 915 + .endianness = DEVICE_NATIVE_ENDIAN, 916 + .valid.min_access_size = 1, 917 + .valid.max_access_size = 2, 918 + }; 919 + 644 920 static const struct SCSIBusInfo esp_scsi_info = { 645 921 .tcq = false, 646 922 .max_target = ESP_MAX_DEVS, ··· 673 949 ESPState *s = &sysbus->esp; 674 950 675 951 sysbus_init_irq(sbd, &s->irq); 952 + sysbus_init_irq(sbd, &s->irq_data); 676 953 assert(sysbus->it_shift != -1); 677 954 678 955 s->chip_id = TCHI_FAS100A; 679 956 memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops, 680 - sysbus, "esp", ESP_REGS << sysbus->it_shift); 957 + sysbus, "esp-regs", ESP_REGS << sysbus->it_shift); 681 958 sysbus_init_mmio(sbd, &sysbus->iomem); 959 + memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops, 960 + sysbus, "esp-pdma", 2); 961 + sysbus_init_mmio(sbd, &sysbus->pdma); 682 962 683 963 qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); 684 964
+76
include/hw/block/swim.h
··· 1 + /* 2 + * QEMU Macintosh floppy disk controller emulator (SWIM) 3 + * 4 + * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu> 5 + * 6 + * This work is licensed under the terms of the GNU GPL, version 2. See 7 + * the COPYING file in the top-level directory. 8 + * 9 + */ 10 + 11 + #ifndef SWIM_H 12 + #define SWIM_H 13 + 14 + #include "qemu/osdep.h" 15 + #include "hw/sysbus.h" 16 + 17 + #define SWIM_MAX_FD 2 18 + 19 + typedef struct SWIMDrive SWIMDrive; 20 + typedef struct SWIMBus SWIMBus; 21 + typedef struct SWIMCtrl SWIMCtrl; 22 + 23 + #define TYPE_SWIM_DRIVE "swim-drive" 24 + #define SWIM_DRIVE(obj) OBJECT_CHECK(SWIMDrive, (obj), TYPE_SWIM_DRIVE) 25 + 26 + struct SWIMDrive { 27 + DeviceState qdev; 28 + int32_t unit; 29 + BlockConf conf; 30 + }; 31 + 32 + #define TYPE_SWIM_BUS "swim-bus" 33 + #define SWIM_BUS(obj) OBJECT_CHECK(SWIMBus, (obj), TYPE_SWIM_BUS) 34 + 35 + struct SWIMBus { 36 + BusState bus; 37 + struct SWIMCtrl *ctrl; 38 + }; 39 + 40 + typedef struct FDrive { 41 + SWIMCtrl *swimctrl; 42 + BlockBackend *blk; 43 + BlockConf *conf; 44 + } FDrive; 45 + 46 + struct SWIMCtrl { 47 + MemoryRegion iomem; 48 + FDrive drives[SWIM_MAX_FD]; 49 + int mode; 50 + /* IWM mode */ 51 + int iwm_switch; 52 + uint16_t regs[8]; 53 + #define IWM_PH0 0 54 + #define IWM_PH1 1 55 + #define IWM_PH2 2 56 + #define IWM_PH3 3 57 + #define IWM_MTR 4 58 + #define IWM_DRIVE 5 59 + #define IWM_Q6 6 60 + #define IWM_Q7 7 61 + uint8_t iwm_data; 62 + uint8_t iwm_mode; 63 + /* SWIM mode */ 64 + uint8_t swim_phase; 65 + uint8_t swim_mode; 66 + SWIMBus bus; 67 + }; 68 + 69 + #define TYPE_SWIM "swim" 70 + #define SWIM(obj) OBJECT_CHECK(SWIM, (obj), TYPE_SWIM) 71 + 72 + typedef struct SWIM { 73 + SysBusDevice parent_obj; 74 + SWIMCtrl ctrl; 75 + } SWIM; 76 + #endif
+64
include/hw/display/macfb.h
··· 1 + /* 2 + * QEMU Motorola 680x0 Macintosh Video Card Emulation 3 + * Copyright (c) 2012-2018 Laurent Vivier 4 + * 5 + * some parts from QEMU G364 framebuffer Emulator. 6 + * Copyright (c) 2007-2011 Herve Poussineau 7 + * 8 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 + * See the COPYING file in the top-level directory. 10 + * 11 + */ 12 + 13 + #ifndef MACFB_H 14 + #define MACFB_H 15 + 16 + #include "qemu/osdep.h" 17 + #include "exec/memory.h" 18 + #include "ui/console.h" 19 + 20 + typedef struct MacfbState { 21 + MemoryRegion mem_vram; 22 + MemoryRegion mem_ctrl; 23 + QemuConsole *con; 24 + 25 + uint8_t *vram; 26 + uint32_t vram_bit_mask; 27 + uint32_t palette_current; 28 + uint8_t color_palette[256 * 3]; 29 + uint32_t width, height; /* in pixels */ 30 + uint8_t depth; 31 + } MacfbState; 32 + 33 + #define TYPE_MACFB "sysbus-macfb" 34 + #define MACFB(obj) \ 35 + OBJECT_CHECK(MacfbSysBusState, (obj), TYPE_MACFB) 36 + 37 + typedef struct { 38 + SysBusDevice busdev; 39 + 40 + MacfbState macfb; 41 + } MacfbSysBusState; 42 + 43 + #define MACFB_NUBUS_DEVICE_CLASS(class) \ 44 + OBJECT_CLASS_CHECK(MacfbNubusDeviceClass, (class), TYPE_NUBUS_MACFB) 45 + #define MACFB_NUBUS_GET_CLASS(obj) \ 46 + OBJECT_GET_CLASS(MacfbNubusDeviceClass, (obj), TYPE_NUBUS_MACFB) 47 + 48 + typedef struct MacfbNubusDeviceClass { 49 + DeviceClass parent_class; 50 + 51 + DeviceRealize parent_realize; 52 + } MacfbNubusDeviceClass; 53 + 54 + #define TYPE_NUBUS_MACFB "nubus-macfb" 55 + #define NUBUS_MACFB(obj) \ 56 + OBJECT_CHECK(MacfbNubusState, (obj), TYPE_NUBUS_MACFB) 57 + 58 + typedef struct { 59 + NubusDevice busdev; 60 + 61 + MacfbState macfb; 62 + } MacfbNubusState; 63 + 64 + #endif
+115
include/hw/misc/mac_via.h
··· 1 + /* 2 + * 3 + * Copyright (c) 2011-2018 Laurent Vivier 4 + * 5 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 6 + * See the COPYING file in the top-level directory. 7 + */ 8 + 9 + #ifndef HW_MISC_MAC_VIA_H 10 + #define HW_MISC_MAC_VIA_H 11 + 12 + #include "exec/memory.h" 13 + #include "hw/sysbus.h" 14 + #include "hw/misc/mos6522.h" 15 + 16 + 17 + /* VIA 1 */ 18 + #define VIA1_IRQ_ONE_SECOND_BIT 0 19 + #define VIA1_IRQ_VBLANK_BIT 1 20 + #define VIA1_IRQ_ADB_READY_BIT 2 21 + #define VIA1_IRQ_ADB_DATA_BIT 3 22 + #define VIA1_IRQ_ADB_CLOCK_BIT 4 23 + 24 + #define VIA1_IRQ_NB 8 25 + 26 + #define VIA1_IRQ_ONE_SECOND (1 << VIA1_IRQ_ONE_SECOND_BIT) 27 + #define VIA1_IRQ_VBLANK (1 << VIA1_IRQ_VBLANK_BIT) 28 + #define VIA1_IRQ_ADB_READY (1 << VIA1_IRQ_ADB_READY_BIT) 29 + #define VIA1_IRQ_ADB_DATA (1 << VIA1_IRQ_ADB_DATA_BIT) 30 + #define VIA1_IRQ_ADB_CLOCK (1 << VIA1_IRQ_ADB_CLOCK_BIT) 31 + 32 + 33 + #define TYPE_MOS6522_Q800_VIA1 "mos6522-q800-via1" 34 + #define MOS6522_Q800_VIA1(obj) OBJECT_CHECK(MOS6522Q800VIA1State, (obj), \ 35 + TYPE_MOS6522_Q800_VIA1) 36 + 37 + typedef struct MOS6522Q800VIA1State { 38 + /*< private >*/ 39 + MOS6522State parent_obj; 40 + 41 + qemu_irq irqs[VIA1_IRQ_NB]; 42 + uint8_t last_b; 43 + uint8_t PRAM[256]; 44 + 45 + /* external timers */ 46 + QEMUTimer *one_second_timer; 47 + int64_t next_second; 48 + QEMUTimer *VBL_timer; 49 + int64_t next_VBL; 50 + } MOS6522Q800VIA1State; 51 + 52 + 53 + /* VIA 2 */ 54 + #define VIA2_IRQ_SCSI_DATA_BIT 0 55 + #define VIA2_IRQ_SLOT_BIT 1 56 + #define VIA2_IRQ_UNUSED_BIT 2 57 + #define VIA2_IRQ_SCSI_BIT 3 58 + #define VIA2_IRQ_ASC_BIT 4 59 + 60 + #define VIA2_IRQ_NB 8 61 + 62 + #define VIA2_IRQ_SCSI_DATA (1 << VIA2_IRQ_SCSI_DATA_BIT) 63 + #define VIA2_IRQ_SLOT (1 << VIA2_IRQ_SLOT_BIT) 64 + #define VIA2_IRQ_UNUSED (1 << VIA2_IRQ_SCSI_BIT) 65 + #define VIA2_IRQ_SCSI (1 << VIA2_IRQ_UNUSED_BIT) 66 + #define VIA2_IRQ_ASC (1 << VIA2_IRQ_ASC_BIT) 67 + 68 + #define TYPE_MOS6522_Q800_VIA2 "mos6522-q800-via2" 69 + #define MOS6522_Q800_VIA2(obj) OBJECT_CHECK(MOS6522Q800VIA2State, (obj), \ 70 + TYPE_MOS6522_Q800_VIA2) 71 + 72 + typedef struct MOS6522Q800VIA2State { 73 + /*< private >*/ 74 + MOS6522State parent_obj; 75 + } MOS6522Q800VIA2State; 76 + 77 + 78 + #define TYPE_MAC_VIA "mac_via" 79 + #define MAC_VIA(obj) OBJECT_CHECK(MacVIAState, (obj), TYPE_MAC_VIA) 80 + 81 + typedef struct MacVIAState { 82 + SysBusDevice busdev; 83 + 84 + /* MMIO */ 85 + MemoryRegion mmio; 86 + MemoryRegion via1mem; 87 + MemoryRegion via2mem; 88 + 89 + /* VIAs */ 90 + MOS6522Q800VIA1State mos6522_via1; 91 + MOS6522Q800VIA2State mos6522_via2; 92 + 93 + /* RTC */ 94 + uint32_t tick_offset; 95 + 96 + uint8_t data_out; 97 + int data_out_cnt; 98 + uint8_t data_in; 99 + uint8_t data_in_cnt; 100 + uint8_t cmd; 101 + int wprotect; 102 + int alt; 103 + 104 + /* ADB */ 105 + ADBBusState adb_bus; 106 + QEMUTimer *adb_poll_timer; 107 + qemu_irq adb_data_ready; 108 + int adb_data_in_size; 109 + int adb_data_in_index; 110 + int adb_data_out_index; 111 + uint8_t adb_data_in[128]; 112 + uint8_t adb_data_out[16]; 113 + } MacVIAState; 114 + 115 + #endif
+24
include/hw/nubus/mac-nubus-bridge.h
··· 1 + /* 2 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 3 + * 4 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 + * See the COPYING file in the top-level directory. 6 + * 7 + */ 8 + 9 + #ifndef HW_NUBUS_MAC_H 10 + #define HW_NUBUS_MAC_H 11 + 12 + #include "hw/nubus/nubus.h" 13 + 14 + #define TYPE_MAC_NUBUS_BRIDGE "mac-nubus-bridge" 15 + #define MAC_NUBUS_BRIDGE(obj) OBJECT_CHECK(MacNubusState, (obj), \ 16 + TYPE_MAC_NUBUS_BRIDGE) 17 + 18 + typedef struct MacNubusState { 19 + SysBusDevice sysbus_dev; 20 + 21 + NubusBus *bus; 22 + } MacNubusState; 23 + 24 + #endif
+69
include/hw/nubus/nubus.h
··· 1 + /* 2 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 3 + * 4 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 + * See the COPYING file in the top-level directory. 6 + * 7 + */ 8 + 9 + #ifndef HW_NUBUS_NUBUS_H 10 + #define HW_NUBUS_NUBUS_H 11 + 12 + #include "hw/qdev-properties.h" 13 + #include "exec/address-spaces.h" 14 + 15 + #define NUBUS_SUPER_SLOT_SIZE 0x10000000U 16 + #define NUBUS_SUPER_SLOT_NB 0x9 17 + 18 + #define NUBUS_SLOT_SIZE 0x01000000 19 + #define NUBUS_SLOT_NB 0xF 20 + 21 + #define NUBUS_FIRST_SLOT 0x9 22 + #define NUBUS_LAST_SLOT 0xF 23 + 24 + #define TYPE_NUBUS_DEVICE "nubus-device" 25 + #define NUBUS_DEVICE(obj) \ 26 + OBJECT_CHECK(NubusDevice, (obj), TYPE_NUBUS_DEVICE) 27 + 28 + #define TYPE_NUBUS_BUS "nubus-bus" 29 + #define NUBUS_BUS(obj) OBJECT_CHECK(NubusBus, (obj), TYPE_NUBUS_BUS) 30 + 31 + #define TYPE_NUBUS_BRIDGE "nubus-bridge" 32 + #define NUBUS_BRIDGE(obj) OBJECT_CHECK(NubusBridge, (obj), TYPE_NUBUS_BRIDGE) 33 + 34 + typedef struct NubusBus { 35 + BusState qbus; 36 + 37 + MemoryRegion super_slot_io; 38 + MemoryRegion slot_io; 39 + 40 + int current_slot; 41 + } NubusBus; 42 + 43 + typedef struct NubusDevice { 44 + DeviceState qdev; 45 + 46 + int slot_nb; 47 + MemoryRegion slot_mem; 48 + 49 + /* Format Block */ 50 + 51 + MemoryRegion fblock_io; 52 + 53 + uint32_t rom_length; 54 + uint32_t rom_crc; 55 + uint8_t rom_rev; 56 + uint8_t rom_format; 57 + uint8_t byte_lanes; 58 + int32_t directory_offset; 59 + 60 + /* ROM */ 61 + 62 + MemoryRegion rom_io; 63 + const uint8_t *rom; 64 + } NubusDevice; 65 + 66 + void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, 67 + int revision, int format, uint8_t byte_lanes); 68 + 69 + #endif
+15
include/hw/scsi/esp.h
··· 14 14 15 15 typedef struct ESPState ESPState; 16 16 17 + enum pdma_origin_id { 18 + PDMA, 19 + TI, 20 + CMD, 21 + ASYNC, 22 + }; 23 + 17 24 struct ESPState { 18 25 uint8_t rregs[ESP_REGS]; 19 26 uint8_t wregs[ESP_REGS]; 20 27 qemu_irq irq; 28 + qemu_irq irq_data; 21 29 uint8_t chip_id; 22 30 bool tchi_written; 23 31 int32_t ti_size; ··· 48 56 ESPDMAMemoryReadWriteFunc dma_memory_write; 49 57 void *dma_opaque; 50 58 void (*dma_cb)(ESPState *s); 59 + uint8_t pdma_buf[32]; 60 + int pdma_origin; 61 + uint32_t pdma_len; 62 + uint32_t pdma_start; 63 + uint32_t pdma_cur; 64 + void (*pdma_cb)(ESPState *s); 51 65 }; 52 66 53 67 #define TYPE_ESP "esp" ··· 59 73 /*< public >*/ 60 74 61 75 MemoryRegion iomem; 76 + MemoryRegion pdma; 62 77 uint32_t it_shift; 63 78 ESPState esp; 64 79 } SysBusESPState;
+1 -1
qemu-options.hx
··· 1859 1859 1860 1860 DEF("g", 1, QEMU_OPTION_g , 1861 1861 "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n", 1862 - QEMU_ARCH_PPC | QEMU_ARCH_SPARC) 1862 + QEMU_ARCH_PPC | QEMU_ARCH_SPARC | QEMU_ARCH_M68K) 1863 1863 STEXI 1864 1864 @item -g @var{width}x@var{height}[x@var{depth}] 1865 1865 @findex -g
+24
tests/acceptance/boot_linux_console.py
··· 378 378 self.vm.launch() 379 379 console_pattern = 'Kernel command line: %s' % kernel_command_line 380 380 self.wait_for_console_pattern(console_pattern) 381 + 382 + def test_m68k_q800(self): 383 + """ 384 + :avocado: tags=arch:m68k 385 + :avocado: tags=machine:q800 386 + """ 387 + deb_url = ('http://ftp.ports.debian.org/debian-ports/pool-m68k/main' 388 + '/l/linux/kernel-image-5.2.0-2-m68k-di_5.2.9-2_m68k.udeb') 389 + deb_hash = '0797e05129595f22f3c0142db5e199769a723bf9' 390 + deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash) 391 + kernel_path = self.extract_from_deb(deb_path, 392 + '/boot/vmlinux-5.2.0-2-m68k') 393 + 394 + self.vm.set_machine('q800') 395 + self.vm.set_console() 396 + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 397 + 'console=ttyS0 vga=off') 398 + self.vm.add_args('-kernel', kernel_path, 399 + '-append', kernel_command_line) 400 + self.vm.launch() 401 + console_pattern = 'Kernel command line: %s' % kernel_command_line 402 + self.wait_for_console_pattern(console_pattern) 403 + console_pattern = 'No filesystem could mount root' 404 + self.wait_for_console_pattern(console_pattern)
+2 -1
vl.c
··· 3229 3229 if (*p == 'x') { 3230 3230 p++; 3231 3231 depth = strtol(p, (char **)&p, 10); 3232 - if (depth != 8 && depth != 15 && depth != 16 && 3232 + if (depth != 1 && depth != 2 && depth != 4 && 3233 + depth != 8 && depth != 15 && depth != 16 && 3233 3234 depth != 24 && depth != 32) 3234 3235 goto graphic_error; 3235 3236 } else if (*p == '\0') {