1956a7811SThomas Huth /* 2956a7811SThomas Huth * NeXT Cube System Driver 3956a7811SThomas Huth * 4956a7811SThomas Huth * Copyright (c) 2011 Bryce Lanham 5956a7811SThomas Huth * 6956a7811SThomas Huth * This code is free software; you can redistribute it and/or modify 7956a7811SThomas Huth * it under the terms of the GNU General Public License as published 8956a7811SThomas Huth * by the Free Software Foundation; either version 2 of the License, 9956a7811SThomas Huth * or (at your option) any later version. 10956a7811SThomas Huth */ 11956a7811SThomas Huth 12956a7811SThomas Huth #include "qemu/osdep.h" 13956a7811SThomas Huth #include "exec/hwaddr.h" 14956a7811SThomas Huth #include "sysemu/sysemu.h" 15956a7811SThomas Huth #include "sysemu/qtest.h" 16b17bed5bSThomas Huth #include "hw/irq.h" 17956a7811SThomas Huth #include "hw/m68k/next-cube.h" 18956a7811SThomas Huth #include "hw/boards.h" 19956a7811SThomas Huth #include "hw/loader.h" 20956a7811SThomas Huth #include "hw/scsi/esp.h" 21956a7811SThomas Huth #include "hw/sysbus.h" 22db1015e9SEduardo Habkost #include "qom/object.h" 23956a7811SThomas Huth #include "hw/char/escc.h" /* ZILOG 8530 Serial Emulation */ 24956a7811SThomas Huth #include "hw/block/fdc.h" 25b17bed5bSThomas Huth #include "hw/qdev-properties.h" 26956a7811SThomas Huth #include "qapi/error.h" 27cc37d98bSRichard Henderson #include "qemu/error-report.h" 28956a7811SThomas Huth #include "ui/console.h" 29956a7811SThomas Huth #include "target/m68k/cpu.h" 3075ca77ecSPeter Maydell #include "migration/vmstate.h" 31956a7811SThomas Huth 32956a7811SThomas Huth /* #define DEBUG_NEXT */ 33956a7811SThomas Huth #ifdef DEBUG_NEXT 34956a7811SThomas Huth #define DPRINTF(fmt, ...) \ 35956a7811SThomas Huth do { printf("NeXT: " fmt , ## __VA_ARGS__); } while (0) 36956a7811SThomas Huth #else 37956a7811SThomas Huth #define DPRINTF(fmt, ...) do { } while (0) 38956a7811SThomas Huth #endif 39956a7811SThomas Huth 40956a7811SThomas Huth #define TYPE_NEXT_MACHINE MACHINE_TYPE_NAME("next-cube") 418063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(NeXTState, NEXT_MACHINE) 42956a7811SThomas Huth 43956a7811SThomas Huth #define ENTRY 0x0100001e 44956a7811SThomas Huth #define RAM_SIZE 0x4000000 45956a7811SThomas Huth #define ROM_FILE "Rev_2.5_v66.bin" 46956a7811SThomas Huth 47956a7811SThomas Huth typedef struct next_dma { 48956a7811SThomas Huth uint32_t csr; 49956a7811SThomas Huth 50956a7811SThomas Huth uint32_t saved_next; 51956a7811SThomas Huth uint32_t saved_limit; 52956a7811SThomas Huth uint32_t saved_start; 53956a7811SThomas Huth uint32_t saved_stop; 54956a7811SThomas Huth 55956a7811SThomas Huth uint32_t next; 56956a7811SThomas Huth uint32_t limit; 57956a7811SThomas Huth uint32_t start; 58956a7811SThomas Huth uint32_t stop; 59956a7811SThomas Huth 60956a7811SThomas Huth uint32_t next_initbuf; 61956a7811SThomas Huth uint32_t size; 62956a7811SThomas Huth } next_dma; 63956a7811SThomas Huth 64cd4fc142SThomas Huth typedef struct NextRtc { 6588d0c5b0SMark Cave-Ayland int8_t phase; 66cd4fc142SThomas Huth uint8_t ram[32]; 67cd4fc142SThomas Huth uint8_t command; 68cd4fc142SThomas Huth uint8_t value; 69cd4fc142SThomas Huth uint8_t status; 70cd4fc142SThomas Huth uint8_t control; 71cd4fc142SThomas Huth uint8_t retval; 72cd4fc142SThomas Huth } NextRtc; 73cd4fc142SThomas Huth 74db1015e9SEduardo Habkost struct NeXTState { 75956a7811SThomas Huth MachineState parent; 76956a7811SThomas Huth 77956a7811SThomas Huth next_dma dma[10]; 78db1015e9SEduardo Habkost }; 79956a7811SThomas Huth 80660bef33SPeter Maydell #define TYPE_NEXT_PC "next-pc" 81660bef33SPeter Maydell OBJECT_DECLARE_SIMPLE_TYPE(NeXTPC, NEXT_PC) 82660bef33SPeter Maydell 83660bef33SPeter Maydell /* NeXT Peripheral Controller */ 84660bef33SPeter Maydell struct NeXTPC { 85660bef33SPeter Maydell SysBusDevice parent_obj; 86660bef33SPeter Maydell 87b497f4a1SPeter Maydell M68kCPU *cpu; 88b497f4a1SPeter Maydell 8940831636SPeter Maydell MemoryRegion mmiomem; 901dc7aeaeSPeter Maydell MemoryRegion scrmem; 9140831636SPeter Maydell 9240831636SPeter Maydell uint32_t scr1; 9340831636SPeter Maydell uint32_t scr2; 9422cf5ee3SMark Cave-Ayland uint32_t old_scr2; 95ac99317bSPeter Maydell uint32_t int_mask; 96ac99317bSPeter Maydell uint32_t int_status; 978220baa0SMark Cave-Ayland uint32_t led; 98f2a80c6eSThomas Huth uint8_t scsi_csr_1; 99f2a80c6eSThomas Huth uint8_t scsi_csr_2; 100f2a80c6eSThomas Huth 101f2a80c6eSThomas Huth qemu_irq scsi_reset; 102f2a80c6eSThomas Huth qemu_irq scsi_dma; 1036f0face7SPeter Maydell 1046f0face7SPeter Maydell NextRtc rtc; 105660bef33SPeter Maydell }; 106660bef33SPeter Maydell 107956a7811SThomas Huth /* Thanks to NeXT forums for this */ 108956a7811SThomas Huth /* 109956a7811SThomas Huth static const uint8_t rtc_ram3[32] = { 110956a7811SThomas Huth 0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 111956a7811SThomas Huth 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00, 112956a7811SThomas Huth 0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 113956a7811SThomas Huth 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13 114956a7811SThomas Huth }; 115956a7811SThomas Huth */ 116956a7811SThomas Huth static const uint8_t rtc_ram2[32] = { 117956a7811SThomas Huth 0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 118956a7811SThomas Huth 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00, 119956a7811SThomas Huth 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 120956a7811SThomas Huth 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e, 121956a7811SThomas Huth }; 122956a7811SThomas Huth 123956a7811SThomas Huth #define SCR2_RTCLK 0x2 124956a7811SThomas Huth #define SCR2_RTDATA 0x4 125956a7811SThomas Huth #define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10)) 126956a7811SThomas Huth 1273deafd18SMark Cave-Ayland static void next_scr2_led_update(NeXTPC *s) 1283deafd18SMark Cave-Ayland { 1293deafd18SMark Cave-Ayland if (s->scr2 & 0x1) { 1303deafd18SMark Cave-Ayland DPRINTF("fault!\n"); 1313deafd18SMark Cave-Ayland s->led++; 1323deafd18SMark Cave-Ayland if (s->led == 10) { 1333deafd18SMark Cave-Ayland DPRINTF("LED flashing, possible fault!\n"); 1343deafd18SMark Cave-Ayland s->led = 0; 1353deafd18SMark Cave-Ayland } 1363deafd18SMark Cave-Ayland } 1373deafd18SMark Cave-Ayland } 1383deafd18SMark Cave-Ayland 139*039b10acSMark Cave-Ayland static void next_scr2_rtc_update(NeXTPC *s) 140956a7811SThomas Huth { 14122cf5ee3SMark Cave-Ayland uint8_t old_scr2, scr2_2; 1426f0face7SPeter Maydell NextRtc *rtc = &s->rtc; 143956a7811SThomas Huth 144*039b10acSMark Cave-Ayland old_scr2 = extract32(s->old_scr2, 8, 8); 145*039b10acSMark Cave-Ayland scr2_2 = extract32(s->scr2, 8, 8); 14622cf5ee3SMark Cave-Ayland 147956a7811SThomas Huth if (scr2_2 & 0x1) { 14888d0c5b0SMark Cave-Ayland /* DPRINTF("RTC %x phase %i\n", scr2_2, rtc->phase); */ 14988d0c5b0SMark Cave-Ayland if (rtc->phase == -1) { 15088d0c5b0SMark Cave-Ayland rtc->phase = 0; 151956a7811SThomas Huth } 152956a7811SThomas Huth /* If we are in going down clock... do something */ 153956a7811SThomas Huth if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) && 154956a7811SThomas Huth ((scr2_2 & SCR2_RTCLK) == 0)) { 15588d0c5b0SMark Cave-Ayland if (rtc->phase < 8) { 156cd4fc142SThomas Huth rtc->command = (rtc->command << 1) | 157956a7811SThomas Huth ((scr2_2 & SCR2_RTDATA) ? 1 : 0); 158956a7811SThomas Huth } 15988d0c5b0SMark Cave-Ayland if (rtc->phase >= 8 && rtc->phase < 16) { 160cd4fc142SThomas Huth rtc->value = (rtc->value << 1) | 161cd4fc142SThomas Huth ((scr2_2 & SCR2_RTDATA) ? 1 : 0); 162956a7811SThomas Huth 163956a7811SThomas Huth /* if we read RAM register, output RT_DATA bit */ 164cd4fc142SThomas Huth if (rtc->command <= 0x1F) { 165956a7811SThomas Huth scr2_2 = scr2_2 & (~SCR2_RTDATA); 16688d0c5b0SMark Cave-Ayland if (rtc->ram[rtc->command] & (0x80 >> (rtc->phase - 8))) { 167956a7811SThomas Huth scr2_2 |= SCR2_RTDATA; 168956a7811SThomas Huth } 169956a7811SThomas Huth 170cd4fc142SThomas Huth rtc->retval = (rtc->retval << 1) | 171956a7811SThomas Huth ((scr2_2 & SCR2_RTDATA) ? 1 : 0); 172956a7811SThomas Huth } 173956a7811SThomas Huth /* read the status 0x30 */ 174cd4fc142SThomas Huth if (rtc->command == 0x30) { 175956a7811SThomas Huth scr2_2 = scr2_2 & (~SCR2_RTDATA); 176956a7811SThomas Huth /* for now status = 0x98 (new rtc + FTU) */ 17788d0c5b0SMark Cave-Ayland if (rtc->status & (0x80 >> (rtc->phase - 8))) { 178956a7811SThomas Huth scr2_2 |= SCR2_RTDATA; 179956a7811SThomas Huth } 180956a7811SThomas Huth 181cd4fc142SThomas Huth rtc->retval = (rtc->retval << 1) | 182956a7811SThomas Huth ((scr2_2 & SCR2_RTDATA) ? 1 : 0); 183956a7811SThomas Huth } 184956a7811SThomas Huth /* read the status 0x31 */ 185cd4fc142SThomas Huth if (rtc->command == 0x31) { 186956a7811SThomas Huth scr2_2 = scr2_2 & (~SCR2_RTDATA); 18788d0c5b0SMark Cave-Ayland if (rtc->control & (0x80 >> (rtc->phase - 8))) { 188956a7811SThomas Huth scr2_2 |= SCR2_RTDATA; 189956a7811SThomas Huth } 190cd4fc142SThomas Huth rtc->retval = (rtc->retval << 1) | 191956a7811SThomas Huth ((scr2_2 & SCR2_RTDATA) ? 1 : 0); 192956a7811SThomas Huth } 193956a7811SThomas Huth 194cd4fc142SThomas Huth if ((rtc->command >= 0x20) && (rtc->command <= 0x2F)) { 195956a7811SThomas Huth scr2_2 = scr2_2 & (~SCR2_RTDATA); 196956a7811SThomas Huth /* for now 0x00 */ 197956a7811SThomas Huth time_t time_h = time(NULL); 198956a7811SThomas Huth struct tm *info = localtime(&time_h); 199956a7811SThomas Huth int ret = 0; 200956a7811SThomas Huth 201cd4fc142SThomas Huth switch (rtc->command) { 202956a7811SThomas Huth case 0x20: 203956a7811SThomas Huth ret = SCR2_TOBCD(info->tm_sec); 204956a7811SThomas Huth break; 205956a7811SThomas Huth case 0x21: 206956a7811SThomas Huth ret = SCR2_TOBCD(info->tm_min); 207956a7811SThomas Huth break; 208956a7811SThomas Huth case 0x22: 209956a7811SThomas Huth ret = SCR2_TOBCD(info->tm_hour); 210956a7811SThomas Huth break; 211956a7811SThomas Huth case 0x24: 212956a7811SThomas Huth ret = SCR2_TOBCD(info->tm_mday); 213956a7811SThomas Huth break; 214956a7811SThomas Huth case 0x25: 215956a7811SThomas Huth ret = SCR2_TOBCD((info->tm_mon + 1)); 216956a7811SThomas Huth break; 217956a7811SThomas Huth case 0x26: 218956a7811SThomas Huth ret = SCR2_TOBCD((info->tm_year - 100)); 219956a7811SThomas Huth break; 220956a7811SThomas Huth 221956a7811SThomas Huth } 222956a7811SThomas Huth 22388d0c5b0SMark Cave-Ayland if (ret & (0x80 >> (rtc->phase - 8))) { 224956a7811SThomas Huth scr2_2 |= SCR2_RTDATA; 225956a7811SThomas Huth } 226cd4fc142SThomas Huth rtc->retval = (rtc->retval << 1) | 227956a7811SThomas Huth ((scr2_2 & SCR2_RTDATA) ? 1 : 0); 228956a7811SThomas Huth } 229956a7811SThomas Huth 230956a7811SThomas Huth } 231956a7811SThomas Huth 23288d0c5b0SMark Cave-Ayland rtc->phase++; 23388d0c5b0SMark Cave-Ayland if (rtc->phase == 16) { 234cd4fc142SThomas Huth if (rtc->command >= 0x80 && rtc->command <= 0x9F) { 235cd4fc142SThomas Huth rtc->ram[rtc->command - 0x80] = rtc->value; 236956a7811SThomas Huth } 237956a7811SThomas Huth /* write to x30 register */ 238cd4fc142SThomas Huth if (rtc->command == 0xB1) { 239956a7811SThomas Huth /* clear FTU */ 240cd4fc142SThomas Huth if (rtc->value & 0x04) { 241cd4fc142SThomas Huth rtc->status = rtc->status & (~0x18); 242ac99317bSPeter Maydell s->int_status = s->int_status & (~0x04); 243956a7811SThomas Huth } 244956a7811SThomas Huth } 245956a7811SThomas Huth } 246956a7811SThomas Huth } 247956a7811SThomas Huth } else { 248956a7811SThomas Huth /* else end or abort */ 24988d0c5b0SMark Cave-Ayland rtc->phase = -1; 250cd4fc142SThomas Huth rtc->command = 0; 251cd4fc142SThomas Huth rtc->value = 0; 252956a7811SThomas Huth } 253*039b10acSMark Cave-Ayland 254*039b10acSMark Cave-Ayland s->scr2 = deposit32(s->scr2, 8, 8, scr2_2); 255956a7811SThomas Huth } 256956a7811SThomas Huth 2577e993d93SMark Cave-Ayland static uint64_t next_mmio_read(void *opaque, hwaddr addr, unsigned size) 258956a7811SThomas Huth { 2597e993d93SMark Cave-Ayland NeXTPC *s = NEXT_PC(opaque); 2607e993d93SMark Cave-Ayland uint64_t val; 261956a7811SThomas Huth 262956a7811SThomas Huth switch (addr) { 263956a7811SThomas Huth case 0x7000: 264ac99317bSPeter Maydell /* DPRINTF("Read INT status: %x\n", s->int_status); */ 2657e993d93SMark Cave-Ayland val = s->int_status; 2667e993d93SMark Cave-Ayland break; 267956a7811SThomas Huth 268956a7811SThomas Huth case 0x7800: 269ac99317bSPeter Maydell DPRINTF("MMIO Read INT mask: %x\n", s->int_mask); 2707e993d93SMark Cave-Ayland val = s->int_mask; 271956a7811SThomas Huth break; 272956a7811SThomas Huth 2737e993d93SMark Cave-Ayland case 0xc000 ... 0xc003: 2747e993d93SMark Cave-Ayland val = extract32(s->scr1, (4 - (addr - 0xc000) - size) << 3, 2757e993d93SMark Cave-Ayland size << 3); 2767e993d93SMark Cave-Ayland break; 277956a7811SThomas Huth 2787e993d93SMark Cave-Ayland case 0xd000 ... 0xd003: 2797e993d93SMark Cave-Ayland val = extract32(s->scr2, (4 - (addr - 0xd000) - size) << 3, 2807e993d93SMark Cave-Ayland size << 3); 2817e993d93SMark Cave-Ayland break; 282956a7811SThomas Huth 2837e993d93SMark Cave-Ayland case 0x14020: 2847e993d93SMark Cave-Ayland val = 0x7f; 285956a7811SThomas Huth break; 286956a7811SThomas Huth 287956a7811SThomas Huth default: 2887e993d93SMark Cave-Ayland val = 0; 2897e993d93SMark Cave-Ayland DPRINTF("MMIO Read @ 0x%"HWADDR_PRIx" size %d\n", addr, size); 2907e993d93SMark Cave-Ayland break; 291956a7811SThomas Huth } 292956a7811SThomas Huth 2937e993d93SMark Cave-Ayland return val; 294956a7811SThomas Huth } 295956a7811SThomas Huth 2967e993d93SMark Cave-Ayland static void next_mmio_write(void *opaque, hwaddr addr, uint64_t val, 297956a7811SThomas Huth unsigned size) 298956a7811SThomas Huth { 29940831636SPeter Maydell NeXTPC *s = NEXT_PC(opaque); 300956a7811SThomas Huth 3017e993d93SMark Cave-Ayland switch (addr) { 3027e993d93SMark Cave-Ayland case 0x7000: 3037e993d93SMark Cave-Ayland DPRINTF("INT Status old: %x new: %x\n", s->int_status, 3047e993d93SMark Cave-Ayland (unsigned int)val); 3057e993d93SMark Cave-Ayland s->int_status = val; 306956a7811SThomas Huth break; 3077e993d93SMark Cave-Ayland 3087e993d93SMark Cave-Ayland case 0x7800: 3097e993d93SMark Cave-Ayland DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, (unsigned int)val); 3107e993d93SMark Cave-Ayland s->int_mask = val; 311956a7811SThomas Huth break; 3127e993d93SMark Cave-Ayland 3137e993d93SMark Cave-Ayland case 0xc000 ... 0xc003: 3147e993d93SMark Cave-Ayland DPRINTF("SCR1 Write: %x\n", (unsigned int)val); 3157e993d93SMark Cave-Ayland s->scr1 = deposit32(s->scr1, (4 - (addr - 0xc000) - size) << 3, 3167e993d93SMark Cave-Ayland size << 3, val); 317956a7811SThomas Huth break; 3187e993d93SMark Cave-Ayland 3197e993d93SMark Cave-Ayland case 0xd000 ... 0xd003: 32022cf5ee3SMark Cave-Ayland s->scr2 = deposit32(s->scr2, (4 - (addr - 0xd000) - size) << 3, 32122cf5ee3SMark Cave-Ayland size << 3, val); 3223deafd18SMark Cave-Ayland next_scr2_led_update(s); 323*039b10acSMark Cave-Ayland next_scr2_rtc_update(s); 32422cf5ee3SMark Cave-Ayland s->old_scr2 = s->scr2; 3257e993d93SMark Cave-Ayland break; 3267e993d93SMark Cave-Ayland 327956a7811SThomas Huth default: 3287e993d93SMark Cave-Ayland DPRINTF("MMIO Write @ 0x%"HWADDR_PRIx " with 0x%x size %u\n", addr, 3297e993d93SMark Cave-Ayland (unsigned int)val, size); 330956a7811SThomas Huth } 331956a7811SThomas Huth } 332956a7811SThomas Huth 3337e993d93SMark Cave-Ayland static const MemoryRegionOps next_mmio_ops = { 3347e993d93SMark Cave-Ayland .read = next_mmio_read, 3357e993d93SMark Cave-Ayland .write = next_mmio_write, 336956a7811SThomas Huth .valid.min_access_size = 1, 337956a7811SThomas Huth .valid.max_access_size = 4, 3387e993d93SMark Cave-Ayland .endianness = DEVICE_BIG_ENDIAN, 339956a7811SThomas Huth }; 340956a7811SThomas Huth 341956a7811SThomas Huth #define SCSICSR_ENABLE 0x01 342956a7811SThomas Huth #define SCSICSR_RESET 0x02 /* reset scsi dma */ 343956a7811SThomas Huth #define SCSICSR_FIFOFL 0x04 344956a7811SThomas Huth #define SCSICSR_DMADIR 0x08 /* if set, scsi to mem */ 345956a7811SThomas Huth #define SCSICSR_CPUDMA 0x10 /* if set, dma enabled */ 346956a7811SThomas Huth #define SCSICSR_INTMASK 0x20 /* if set, interrupt enabled */ 347956a7811SThomas Huth 3480d60da39SMark Cave-Ayland static uint64_t next_scr_readfn(void *opaque, hwaddr addr, unsigned size) 349956a7811SThomas Huth { 3500d60da39SMark Cave-Ayland NeXTPC *s = NEXT_PC(opaque); 3510d60da39SMark Cave-Ayland uint64_t val; 3520d60da39SMark Cave-Ayland 3530d60da39SMark Cave-Ayland switch (addr) { 3540d60da39SMark Cave-Ayland case 0x14108: 3550d60da39SMark Cave-Ayland DPRINTF("FD read @ %x\n", (unsigned int)addr); 3560d60da39SMark Cave-Ayland val = 0x40 | 0x04 | 0x2 | 0x1; 3570d60da39SMark Cave-Ayland break; 3580d60da39SMark Cave-Ayland 3590d60da39SMark Cave-Ayland case 0x14020: 3600d60da39SMark Cave-Ayland DPRINTF("SCSI 4020 STATUS READ %X\n", s->scsi_csr_1); 3610d60da39SMark Cave-Ayland val = s->scsi_csr_1; 3620d60da39SMark Cave-Ayland break; 3630d60da39SMark Cave-Ayland 3640d60da39SMark Cave-Ayland case 0x14021: 3650d60da39SMark Cave-Ayland DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2); 3660d60da39SMark Cave-Ayland val = 0x40; 3670d60da39SMark Cave-Ayland break; 3680d60da39SMark Cave-Ayland 3690d60da39SMark Cave-Ayland /* 3700d60da39SMark Cave-Ayland * These 4 registers are the hardware timer, not sure which register 3710d60da39SMark Cave-Ayland * is the latch instead of data, but no problems so far. 3720d60da39SMark Cave-Ayland * 3730d60da39SMark Cave-Ayland * Hack: We need to have the LSB change consistently to make it work 3740d60da39SMark Cave-Ayland */ 3750d60da39SMark Cave-Ayland case 0x1a000 ... 0x1a003: 3760d60da39SMark Cave-Ayland val = extract32(clock(), (4 - (addr - 0x1a000) - size) << 3, 3770d60da39SMark Cave-Ayland size << 3); 3780d60da39SMark Cave-Ayland break; 3790d60da39SMark Cave-Ayland 3800d60da39SMark Cave-Ayland /* For now return dummy byte to allow the Ethernet test to timeout */ 3810d60da39SMark Cave-Ayland case 0x6000: 3820d60da39SMark Cave-Ayland val = 0xff; 3830d60da39SMark Cave-Ayland break; 3840d60da39SMark Cave-Ayland 3850d60da39SMark Cave-Ayland default: 3860d60da39SMark Cave-Ayland DPRINTF("BMAP Read @ 0x%x size %u\n", (unsigned int)addr, size); 3870d60da39SMark Cave-Ayland val = 0; 3880d60da39SMark Cave-Ayland break; 3890d60da39SMark Cave-Ayland } 3900d60da39SMark Cave-Ayland 3910d60da39SMark Cave-Ayland return val; 3920d60da39SMark Cave-Ayland } 3930d60da39SMark Cave-Ayland 3940d60da39SMark Cave-Ayland static void next_scr_writefn(void *opaque, hwaddr addr, uint64_t val, 3950d60da39SMark Cave-Ayland unsigned size) 3960d60da39SMark Cave-Ayland { 3970d60da39SMark Cave-Ayland NeXTPC *s = NEXT_PC(opaque); 3980d60da39SMark Cave-Ayland 399956a7811SThomas Huth switch (addr) { 400956a7811SThomas Huth case 0x14108: 401956a7811SThomas Huth DPRINTF("FDCSR Write: %x\n", value); 4020d60da39SMark Cave-Ayland if (val == 0x0) { 403956a7811SThomas Huth /* qemu_irq_raise(s->fd_irq[0]); */ 404956a7811SThomas Huth } 405956a7811SThomas Huth break; 4060d60da39SMark Cave-Ayland 407956a7811SThomas Huth case 0x14020: /* SCSI Control Register */ 4080d60da39SMark Cave-Ayland if (val & SCSICSR_FIFOFL) { 409956a7811SThomas Huth DPRINTF("SCSICSR FIFO Flush\n"); 410956a7811SThomas Huth /* will have to add another irq to the esp if this is needed */ 411956a7811SThomas Huth /* esp_puflush_fifo(esp_g); */ 412956a7811SThomas Huth } 413956a7811SThomas Huth 4140d60da39SMark Cave-Ayland if (val & SCSICSR_ENABLE) { 415956a7811SThomas Huth DPRINTF("SCSICSR Enable\n"); 416956a7811SThomas Huth /* 417956a7811SThomas Huth * qemu_irq_raise(s->scsi_dma); 418956a7811SThomas Huth * s->scsi_csr_1 = 0xc0; 419956a7811SThomas Huth * s->scsi_csr_1 |= 0x1; 420956a7811SThomas Huth * qemu_irq_pulse(s->scsi_dma); 421956a7811SThomas Huth */ 422956a7811SThomas Huth } 423956a7811SThomas Huth /* 424956a7811SThomas Huth * else 425956a7811SThomas Huth * s->scsi_csr_1 &= ~SCSICSR_ENABLE; 426956a7811SThomas Huth */ 427956a7811SThomas Huth 4280d60da39SMark Cave-Ayland if (val & SCSICSR_RESET) { 429956a7811SThomas Huth DPRINTF("SCSICSR Reset\n"); 430956a7811SThomas Huth /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */ 431f2a80c6eSThomas Huth qemu_irq_raise(s->scsi_reset); 432f2a80c6eSThomas Huth s->scsi_csr_1 &= ~(SCSICSR_INTMASK | 0x80 | 0x1); 433f2a80c6eSThomas Huth qemu_irq_lower(s->scsi_reset); 434956a7811SThomas Huth } 4350d60da39SMark Cave-Ayland if (val & SCSICSR_DMADIR) { 436956a7811SThomas Huth DPRINTF("SCSICSR DMAdir\n"); 437956a7811SThomas Huth } 4380d60da39SMark Cave-Ayland if (val & SCSICSR_CPUDMA) { 439956a7811SThomas Huth DPRINTF("SCSICSR CPUDMA\n"); 440956a7811SThomas Huth /* qemu_irq_raise(s->scsi_dma); */ 441ac99317bSPeter Maydell s->int_status |= 0x4000000; 442956a7811SThomas Huth } else { 443f2a80c6eSThomas Huth /* fprintf(stderr,"SCSICSR CPUDMA disabled\n"); */ 444ac99317bSPeter Maydell s->int_status &= ~(0x4000000); 445f2a80c6eSThomas Huth /* qemu_irq_lower(s->scsi_dma); */ 446956a7811SThomas Huth } 4470d60da39SMark Cave-Ayland if (val & SCSICSR_INTMASK) { 448956a7811SThomas Huth DPRINTF("SCSICSR INTMASK\n"); 449956a7811SThomas Huth /* 450956a7811SThomas Huth * int_mask &= ~0x1000; 4510d60da39SMark Cave-Ayland * s->scsi_csr_1 |= val; 452956a7811SThomas Huth * s->scsi_csr_1 &= ~SCSICSR_INTMASK; 453956a7811SThomas Huth * if (s->scsi_queued) { 454956a7811SThomas Huth * s->scsi_queued = 0; 455956a7811SThomas Huth * next_irq(s, NEXT_SCSI_I, level); 456956a7811SThomas Huth * } 457956a7811SThomas Huth */ 458956a7811SThomas Huth } else { 459956a7811SThomas Huth /* int_mask |= 0x1000; */ 460956a7811SThomas Huth } 4610d60da39SMark Cave-Ayland if (val & 0x80) { 462956a7811SThomas Huth /* int_mask |= 0x1000; */ 463956a7811SThomas Huth /* s->scsi_csr_1 |= 0x80; */ 464956a7811SThomas Huth } 4650d60da39SMark Cave-Ayland DPRINTF("SCSICSR Write: %x\n", val); 4660d60da39SMark Cave-Ayland /* s->scsi_csr_1 = val; */ 4670d60da39SMark Cave-Ayland break; 4680d60da39SMark Cave-Ayland 469956a7811SThomas Huth /* Hardware timer latch - not implemented yet */ 470956a7811SThomas Huth case 0x1a000: 471956a7811SThomas Huth default: 4720d60da39SMark Cave-Ayland DPRINTF("BMAP Write @ 0x%x with 0x%x size %u\n", (unsigned int)addr, 4730d60da39SMark Cave-Ayland val, size); 474956a7811SThomas Huth } 475956a7811SThomas Huth } 476956a7811SThomas Huth 4770d60da39SMark Cave-Ayland static const MemoryRegionOps next_scr_ops = { 4780d60da39SMark Cave-Ayland .read = next_scr_readfn, 4790d60da39SMark Cave-Ayland .write = next_scr_writefn, 480956a7811SThomas Huth .valid.min_access_size = 1, 481956a7811SThomas Huth .valid.max_access_size = 4, 4820d60da39SMark Cave-Ayland .endianness = DEVICE_BIG_ENDIAN, 483956a7811SThomas Huth }; 484956a7811SThomas Huth 485956a7811SThomas Huth #define NEXTDMA_SCSI(x) (0x10 + x) 486956a7811SThomas Huth #define NEXTDMA_FD(x) (0x10 + x) 487956a7811SThomas Huth #define NEXTDMA_ENTX(x) (0x110 + x) 488956a7811SThomas Huth #define NEXTDMA_ENRX(x) (0x150 + x) 489956a7811SThomas Huth #define NEXTDMA_CSR 0x0 490956a7811SThomas Huth #define NEXTDMA_NEXT 0x4000 491956a7811SThomas Huth #define NEXTDMA_LIMIT 0x4004 492956a7811SThomas Huth #define NEXTDMA_START 0x4008 493956a7811SThomas Huth #define NEXTDMA_STOP 0x400c 494956a7811SThomas Huth #define NEXTDMA_NEXT_INIT 0x4200 495956a7811SThomas Huth #define NEXTDMA_SIZE 0x4204 496956a7811SThomas Huth 497c0dedcf4SMark Cave-Ayland static void next_dma_write(void *opaque, hwaddr addr, uint64_t val, 498956a7811SThomas Huth unsigned int size) 499956a7811SThomas Huth { 500956a7811SThomas Huth NeXTState *next_state = NEXT_MACHINE(opaque); 501956a7811SThomas Huth 502956a7811SThomas Huth switch (addr) { 503956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_CSR): 504c0dedcf4SMark Cave-Ayland if (val & DMA_DEV2M) { 505956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M; 506956a7811SThomas Huth } 507956a7811SThomas Huth 508c0dedcf4SMark Cave-Ayland if (val & DMA_SETENABLE) { 509956a7811SThomas Huth /* DPRINTF("SCSI DMA ENABLE\n"); */ 510956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE; 511956a7811SThomas Huth } 512c0dedcf4SMark Cave-Ayland if (val & DMA_SETSUPDATE) { 513956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE; 514956a7811SThomas Huth } 515c0dedcf4SMark Cave-Ayland if (val & DMA_CLRCOMPLETE) { 516956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE; 517956a7811SThomas Huth } 518956a7811SThomas Huth 519c0dedcf4SMark Cave-Ayland if (val & DMA_RESET) { 520956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | 521956a7811SThomas Huth DMA_ENABLE | DMA_DEV2M); 522956a7811SThomas Huth } 523956a7811SThomas Huth /* DPRINTF("RXCSR \tWrite: %x\n",value); */ 524956a7811SThomas Huth break; 525c0dedcf4SMark Cave-Ayland 526956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT): 527c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_ENRX].next_initbuf = val; 528956a7811SThomas Huth break; 529c0dedcf4SMark Cave-Ayland 530956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT): 531c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_ENRX].next = val; 532956a7811SThomas Huth break; 533c0dedcf4SMark Cave-Ayland 534956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_LIMIT): 535c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_ENRX].limit = val; 536956a7811SThomas Huth break; 537c0dedcf4SMark Cave-Ayland 538956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_CSR): 539c0dedcf4SMark Cave-Ayland if (val & DMA_DEV2M) { 540956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M; 541956a7811SThomas Huth } 542c0dedcf4SMark Cave-Ayland if (val & DMA_SETENABLE) { 543956a7811SThomas Huth /* DPRINTF("SCSI DMA ENABLE\n"); */ 544956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE; 545956a7811SThomas Huth } 546c0dedcf4SMark Cave-Ayland if (val & DMA_SETSUPDATE) { 547956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE; 548956a7811SThomas Huth } 549c0dedcf4SMark Cave-Ayland if (val & DMA_CLRCOMPLETE) { 550956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE; 551956a7811SThomas Huth } 552956a7811SThomas Huth 553c0dedcf4SMark Cave-Ayland if (val & DMA_RESET) { 554956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | 555956a7811SThomas Huth DMA_ENABLE | DMA_DEV2M); 556956a7811SThomas Huth /* DPRINTF("SCSI DMA RESET\n"); */ 557956a7811SThomas Huth } 558956a7811SThomas Huth /* DPRINTF("RXCSR \tWrite: %x\n",value); */ 559956a7811SThomas Huth break; 560956a7811SThomas Huth 561956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT): 562c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].next = val; 563956a7811SThomas Huth break; 564956a7811SThomas Huth 565956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_LIMIT): 566c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].limit = val; 567956a7811SThomas Huth break; 568956a7811SThomas Huth 569956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_START): 570c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].start = val; 571956a7811SThomas Huth break; 572956a7811SThomas Huth 573956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_STOP): 574c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].stop = val; 575956a7811SThomas Huth break; 576956a7811SThomas Huth 577956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT): 578c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].next_initbuf = val; 579956a7811SThomas Huth break; 580956a7811SThomas Huth 581956a7811SThomas Huth default: 582956a7811SThomas Huth DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value); 583956a7811SThomas Huth } 584956a7811SThomas Huth } 585956a7811SThomas Huth 586c0dedcf4SMark Cave-Ayland static uint64_t next_dma_read(void *opaque, hwaddr addr, unsigned int size) 587956a7811SThomas Huth { 588956a7811SThomas Huth NeXTState *next_state = NEXT_MACHINE(opaque); 589c0dedcf4SMark Cave-Ayland uint64_t val; 590956a7811SThomas Huth 591956a7811SThomas Huth switch (addr) { 592956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_CSR): 593956a7811SThomas Huth DPRINTF("SCSI DMA CSR READ\n"); 594c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].csr; 595c0dedcf4SMark Cave-Ayland break; 596c0dedcf4SMark Cave-Ayland 597956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_CSR): 598c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].csr; 599c0dedcf4SMark Cave-Ayland break; 600c0dedcf4SMark Cave-Ayland 601956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT): 602c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].next_initbuf; 603c0dedcf4SMark Cave-Ayland break; 604c0dedcf4SMark Cave-Ayland 605956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT): 606c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].next; 607c0dedcf4SMark Cave-Ayland break; 608c0dedcf4SMark Cave-Ayland 609956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_LIMIT): 610c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].limit; 611c0dedcf4SMark Cave-Ayland break; 612956a7811SThomas Huth 613956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT): 614c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].next; 615c0dedcf4SMark Cave-Ayland break; 616c0dedcf4SMark Cave-Ayland 617956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT): 618c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].next_initbuf; 619c0dedcf4SMark Cave-Ayland break; 620c0dedcf4SMark Cave-Ayland 621956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_LIMIT): 622c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].limit; 623c0dedcf4SMark Cave-Ayland break; 624c0dedcf4SMark Cave-Ayland 625956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_START): 626c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].start; 627c0dedcf4SMark Cave-Ayland break; 628c0dedcf4SMark Cave-Ayland 629956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_STOP): 630c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].stop; 631c0dedcf4SMark Cave-Ayland break; 632956a7811SThomas Huth 633956a7811SThomas Huth default: 634956a7811SThomas Huth DPRINTF("DMA read @ %x\n", (unsigned int)addr); 635c0dedcf4SMark Cave-Ayland val = 0; 636956a7811SThomas Huth } 637956a7811SThomas Huth 638956a7811SThomas Huth /* 639956a7811SThomas Huth * once the csr's are done, subtract 0x3FEC from the addr, and that will 640956a7811SThomas Huth * normalize the upper registers 641956a7811SThomas Huth */ 642c0dedcf4SMark Cave-Ayland 643c0dedcf4SMark Cave-Ayland return val; 644956a7811SThomas Huth } 645956a7811SThomas Huth 646c0dedcf4SMark Cave-Ayland static const MemoryRegionOps next_dma_ops = { 647c0dedcf4SMark Cave-Ayland .read = next_dma_read, 648c0dedcf4SMark Cave-Ayland .write = next_dma_write, 649956a7811SThomas Huth .impl.min_access_size = 4, 650956a7811SThomas Huth .valid.min_access_size = 4, 651956a7811SThomas Huth .valid.max_access_size = 4, 652c0dedcf4SMark Cave-Ayland .endianness = DEVICE_BIG_ENDIAN, 653956a7811SThomas Huth }; 654956a7811SThomas Huth 655c8abcc87SPeter Maydell static void next_irq(void *opaque, int number, int level) 656956a7811SThomas Huth { 657b497f4a1SPeter Maydell NeXTPC *s = NEXT_PC(opaque); 658b497f4a1SPeter Maydell M68kCPU *cpu = s->cpu; 659956a7811SThomas Huth int shift = 0; 660956a7811SThomas Huth 6618b81968cSMichael Tokarev /* first switch sets interrupt status */ 662956a7811SThomas Huth /* DPRINTF("IRQ %i\n",number); */ 663956a7811SThomas Huth switch (number) { 664956a7811SThomas Huth /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */ 665956a7811SThomas Huth case NEXT_FD_I: 6665012a894SPhilippe Mathieu-Daudé shift = 7; 667956a7811SThomas Huth break; 668956a7811SThomas Huth case NEXT_KBD_I: 669956a7811SThomas Huth shift = 3; 670956a7811SThomas Huth break; 671956a7811SThomas Huth case NEXT_PWR_I: 672956a7811SThomas Huth shift = 2; 673956a7811SThomas Huth break; 674956a7811SThomas Huth case NEXT_ENRX_I: 675956a7811SThomas Huth shift = 9; 676956a7811SThomas Huth break; 677956a7811SThomas Huth case NEXT_ENTX_I: 678956a7811SThomas Huth shift = 10; 679956a7811SThomas Huth break; 680956a7811SThomas Huth case NEXT_SCSI_I: 681956a7811SThomas Huth shift = 12; 682956a7811SThomas Huth break; 683956a7811SThomas Huth case NEXT_CLK_I: 684956a7811SThomas Huth shift = 5; 685956a7811SThomas Huth break; 686956a7811SThomas Huth 687956a7811SThomas Huth /* level 5 - scc (serial) */ 688956a7811SThomas Huth case NEXT_SCC_I: 689956a7811SThomas Huth shift = 17; 690956a7811SThomas Huth break; 691956a7811SThomas Huth 692956a7811SThomas Huth /* level 6 - audio etherrx/tx dma */ 693956a7811SThomas Huth case NEXT_ENTX_DMA_I: 694956a7811SThomas Huth shift = 28; 695956a7811SThomas Huth break; 696956a7811SThomas Huth case NEXT_ENRX_DMA_I: 697956a7811SThomas Huth shift = 27; 698956a7811SThomas Huth break; 699956a7811SThomas Huth case NEXT_SCSI_DMA_I: 700956a7811SThomas Huth shift = 26; 701956a7811SThomas Huth break; 702956a7811SThomas Huth case NEXT_SND_I: 703956a7811SThomas Huth shift = 23; 704956a7811SThomas Huth break; 705956a7811SThomas Huth case NEXT_SCC_DMA_I: 706956a7811SThomas Huth shift = 21; 707956a7811SThomas Huth break; 708956a7811SThomas Huth 709956a7811SThomas Huth } 710956a7811SThomas Huth /* 711956a7811SThomas Huth * this HAS to be wrong, the interrupt handlers in mach and together 712956a7811SThomas Huth * int_status and int_mask and return if there is a hit 713956a7811SThomas Huth */ 714ac99317bSPeter Maydell if (s->int_mask & (1 << shift)) { 715956a7811SThomas Huth DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc); 716956a7811SThomas Huth /* return; */ 717956a7811SThomas Huth } 718956a7811SThomas Huth 719956a7811SThomas Huth /* second switch triggers the correct interrupt */ 720956a7811SThomas Huth if (level) { 721ac99317bSPeter Maydell s->int_status |= 1 << shift; 722956a7811SThomas Huth 723956a7811SThomas Huth switch (number) { 724956a7811SThomas Huth /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */ 725956a7811SThomas Huth case NEXT_FD_I: 726956a7811SThomas Huth case NEXT_KBD_I: 727956a7811SThomas Huth case NEXT_PWR_I: 728956a7811SThomas Huth case NEXT_ENRX_I: 729956a7811SThomas Huth case NEXT_ENTX_I: 730956a7811SThomas Huth case NEXT_SCSI_I: 731956a7811SThomas Huth case NEXT_CLK_I: 732956a7811SThomas Huth m68k_set_irq_level(cpu, 3, 27); 733956a7811SThomas Huth break; 734956a7811SThomas Huth 735956a7811SThomas Huth /* level 5 - scc (serial) */ 736956a7811SThomas Huth case NEXT_SCC_I: 737956a7811SThomas Huth m68k_set_irq_level(cpu, 5, 29); 738956a7811SThomas Huth break; 739956a7811SThomas Huth 740956a7811SThomas Huth /* level 6 - audio etherrx/tx dma */ 741956a7811SThomas Huth case NEXT_ENTX_DMA_I: 742956a7811SThomas Huth case NEXT_ENRX_DMA_I: 743956a7811SThomas Huth case NEXT_SCSI_DMA_I: 744956a7811SThomas Huth case NEXT_SND_I: 745956a7811SThomas Huth case NEXT_SCC_DMA_I: 746956a7811SThomas Huth m68k_set_irq_level(cpu, 6, 30); 747956a7811SThomas Huth break; 748956a7811SThomas Huth } 749956a7811SThomas Huth } else { 750ac99317bSPeter Maydell s->int_status &= ~(1 << shift); 751956a7811SThomas Huth cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 752956a7811SThomas Huth } 753956a7811SThomas Huth } 754956a7811SThomas Huth 755f2a80c6eSThomas Huth static void nextdma_write(void *opaque, uint8_t *buf, int size, int type) 756f2a80c6eSThomas Huth { 757f2a80c6eSThomas Huth uint32_t base_addr; 758f2a80c6eSThomas Huth int irq = 0; 759f2a80c6eSThomas Huth uint8_t align = 16; 760f2a80c6eSThomas Huth NeXTState *next_state = NEXT_MACHINE(qdev_get_machine()); 761f2a80c6eSThomas Huth 762f2a80c6eSThomas Huth if (type == NEXTDMA_ENRX || type == NEXTDMA_ENTX) { 763f2a80c6eSThomas Huth align = 32; 764f2a80c6eSThomas Huth } 765f2a80c6eSThomas Huth /* Most DMA is supposedly 16 byte aligned */ 766f2a80c6eSThomas Huth if ((size % align) != 0) { 767f2a80c6eSThomas Huth size -= size % align; 768f2a80c6eSThomas Huth size += align; 769f2a80c6eSThomas Huth } 770f2a80c6eSThomas Huth 771f2a80c6eSThomas Huth /* 772f2a80c6eSThomas Huth * prom sets the dma start using initbuf while the bootloader uses next 773f2a80c6eSThomas Huth * so we check to see if initbuf is 0 774f2a80c6eSThomas Huth */ 775f2a80c6eSThomas Huth if (next_state->dma[type].next_initbuf == 0) { 776f2a80c6eSThomas Huth base_addr = next_state->dma[type].next; 777f2a80c6eSThomas Huth } else { 778f2a80c6eSThomas Huth base_addr = next_state->dma[type].next_initbuf; 779f2a80c6eSThomas Huth } 780f2a80c6eSThomas Huth 781f2a80c6eSThomas Huth cpu_physical_memory_write(base_addr, buf, size); 782f2a80c6eSThomas Huth 783f2a80c6eSThomas Huth next_state->dma[type].next_initbuf = 0; 784f2a80c6eSThomas Huth 785f2a80c6eSThomas Huth /* saved limit is checked to calculate packet size by both, rom and netbsd */ 786f2a80c6eSThomas Huth next_state->dma[type].saved_limit = (next_state->dma[type].next + size); 787f2a80c6eSThomas Huth next_state->dma[type].saved_next = (next_state->dma[type].next); 788f2a80c6eSThomas Huth 789f2a80c6eSThomas Huth /* 790f2a80c6eSThomas Huth * 32 bytes under savedbase seems to be some kind of register 791f2a80c6eSThomas Huth * of which the purpose is unknown as of yet 792f2a80c6eSThomas Huth */ 793f2a80c6eSThomas Huth /* stl_phys(s->rx_dma.base-32,0xFFFFFFFF); */ 794f2a80c6eSThomas Huth 795f2a80c6eSThomas Huth if (!(next_state->dma[type].csr & DMA_SUPDATE)) { 796f2a80c6eSThomas Huth next_state->dma[type].next = next_state->dma[type].start; 797f2a80c6eSThomas Huth next_state->dma[type].limit = next_state->dma[type].stop; 798f2a80c6eSThomas Huth } 799f2a80c6eSThomas Huth 800f2a80c6eSThomas Huth /* Set dma registers and raise an irq */ 801f2a80c6eSThomas Huth next_state->dma[type].csr |= DMA_COMPLETE; /* DON'T CHANGE THIS! */ 802f2a80c6eSThomas Huth 803f2a80c6eSThomas Huth switch (type) { 804f2a80c6eSThomas Huth case NEXTDMA_SCSI: 805f2a80c6eSThomas Huth irq = NEXT_SCSI_DMA_I; 806f2a80c6eSThomas Huth break; 807f2a80c6eSThomas Huth } 808f2a80c6eSThomas Huth 809f2a80c6eSThomas Huth next_irq(opaque, irq, 1); 810f2a80c6eSThomas Huth next_irq(opaque, irq, 0); 811f2a80c6eSThomas Huth } 812f2a80c6eSThomas Huth 813f2a80c6eSThomas Huth static void nextscsi_read(void *opaque, uint8_t *buf, int len) 814f2a80c6eSThomas Huth { 815f2a80c6eSThomas Huth DPRINTF("SCSI READ: %x\n", len); 816f2a80c6eSThomas Huth abort(); 817f2a80c6eSThomas Huth } 818f2a80c6eSThomas Huth 819f2a80c6eSThomas Huth static void nextscsi_write(void *opaque, uint8_t *buf, int size) 820f2a80c6eSThomas Huth { 821f2a80c6eSThomas Huth DPRINTF("SCSI WRITE: %i\n", size); 822f2a80c6eSThomas Huth nextdma_write(opaque, buf, size, NEXTDMA_SCSI); 823f2a80c6eSThomas Huth } 824f2a80c6eSThomas Huth 825f2a80c6eSThomas Huth static void next_scsi_init(DeviceState *pcdev, M68kCPU *cpu) 826f2a80c6eSThomas Huth { 827f2a80c6eSThomas Huth struct NeXTPC *next_pc = NEXT_PC(pcdev); 828f2a80c6eSThomas Huth DeviceState *dev; 829f2a80c6eSThomas Huth SysBusDevice *sysbusdev; 830f2a80c6eSThomas Huth SysBusESPState *sysbus_esp; 831f2a80c6eSThomas Huth ESPState *esp; 832f2a80c6eSThomas Huth 833f2a80c6eSThomas Huth dev = qdev_new(TYPE_SYSBUS_ESP); 834f2a80c6eSThomas Huth sysbus_esp = SYSBUS_ESP(dev); 835f2a80c6eSThomas Huth esp = &sysbus_esp->esp; 836f2a80c6eSThomas Huth esp->dma_memory_read = nextscsi_read; 837f2a80c6eSThomas Huth esp->dma_memory_write = nextscsi_write; 838f2a80c6eSThomas Huth esp->dma_opaque = pcdev; 839f2a80c6eSThomas Huth sysbus_esp->it_shift = 0; 840f2a80c6eSThomas Huth esp->dma_enabled = 1; 841f2a80c6eSThomas Huth sysbusdev = SYS_BUS_DEVICE(dev); 842f2a80c6eSThomas Huth sysbus_realize_and_unref(sysbusdev, &error_fatal); 843f2a80c6eSThomas Huth sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(pcdev, NEXT_SCSI_I)); 844f2a80c6eSThomas Huth sysbus_mmio_map(sysbusdev, 0, 0x2114000); 845f2a80c6eSThomas Huth 846f2a80c6eSThomas Huth next_pc->scsi_reset = qdev_get_gpio_in(dev, 0); 847f2a80c6eSThomas Huth next_pc->scsi_dma = qdev_get_gpio_in(dev, 1); 848f2a80c6eSThomas Huth 849f2a80c6eSThomas Huth scsi_bus_legacy_handle_cmdline(&esp->bus); 850f2a80c6eSThomas Huth } 851f2a80c6eSThomas Huth 852b497f4a1SPeter Maydell static void next_escc_init(DeviceState *pcdev) 853b17bed5bSThomas Huth { 854b17bed5bSThomas Huth DeviceState *dev; 855b17bed5bSThomas Huth SysBusDevice *s; 856b17bed5bSThomas Huth 8573e80f690SMarkus Armbruster dev = qdev_new(TYPE_ESCC); 858b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "disabled", 0); 859b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "frequency", 9600 * 384); 860b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "it_shift", 0); 861b17bed5bSThomas Huth qdev_prop_set_bit(dev, "bit_swap", true); 862b17bed5bSThomas Huth qdev_prop_set_chr(dev, "chrB", serial_hd(1)); 863b17bed5bSThomas Huth qdev_prop_set_chr(dev, "chrA", serial_hd(0)); 864b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "chnBtype", escc_serial); 865b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "chnAtype", escc_serial); 866b17bed5bSThomas Huth 867b17bed5bSThomas Huth s = SYS_BUS_DEVICE(dev); 8683c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal); 869d9cd4039SPeter Maydell sysbus_connect_irq(s, 0, qdev_get_gpio_in(pcdev, NEXT_SCC_I)); 870d9cd4039SPeter Maydell sysbus_connect_irq(s, 1, qdev_get_gpio_in(pcdev, NEXT_SCC_DMA_I)); 871b17bed5bSThomas Huth sysbus_mmio_map(s, 0, 0x2118000); 872b17bed5bSThomas Huth } 873b17bed5bSThomas Huth 874660bef33SPeter Maydell static void next_pc_reset(DeviceState *dev) 875660bef33SPeter Maydell { 87640831636SPeter Maydell NeXTPC *s = NEXT_PC(dev); 87740831636SPeter Maydell 87840831636SPeter Maydell /* Set internal registers to initial values */ 87940831636SPeter Maydell /* 0x0000XX00 << vital bits */ 88040831636SPeter Maydell s->scr1 = 0x00011102; 88140831636SPeter Maydell s->scr2 = 0x00ff0c80; 88222cf5ee3SMark Cave-Ayland s->old_scr2 = s->scr2; 8836f0face7SPeter Maydell 8846f0face7SPeter Maydell s->rtc.status = 0x90; 8856f0face7SPeter Maydell 8866f0face7SPeter Maydell /* Load RTC RAM - TODO: provide possibility to load contents from file */ 8876f0face7SPeter Maydell memcpy(s->rtc.ram, rtc_ram2, 32); 888660bef33SPeter Maydell } 889660bef33SPeter Maydell 890660bef33SPeter Maydell static void next_pc_realize(DeviceState *dev, Error **errp) 891660bef33SPeter Maydell { 89240831636SPeter Maydell NeXTPC *s = NEXT_PC(dev); 89340831636SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 89440831636SPeter Maydell 895d9cd4039SPeter Maydell qdev_init_gpio_in(dev, next_irq, NEXT_NUM_IRQS); 896d9cd4039SPeter Maydell 8977e993d93SMark Cave-Ayland memory_region_init_io(&s->mmiomem, OBJECT(s), &next_mmio_ops, s, 8987e993d93SMark Cave-Ayland "next.mmio", 0xd0000); 8990d60da39SMark Cave-Ayland memory_region_init_io(&s->scrmem, OBJECT(s), &next_scr_ops, s, 9001dc7aeaeSPeter Maydell "next.scr", 0x20000); 90140831636SPeter Maydell sysbus_init_mmio(sbd, &s->mmiomem); 9021dc7aeaeSPeter Maydell sysbus_init_mmio(sbd, &s->scrmem); 903660bef33SPeter Maydell } 904660bef33SPeter Maydell 905b497f4a1SPeter Maydell /* 906b497f4a1SPeter Maydell * If the m68k CPU implemented its inbound irq lines as GPIO lines 907b497f4a1SPeter Maydell * rather than via the m68k_set_irq_level() function we would not need 908b497f4a1SPeter Maydell * this cpu link property and could instead provide outbound IRQ lines 909b497f4a1SPeter Maydell * that the board could wire up to the CPU. 910b497f4a1SPeter Maydell */ 911b497f4a1SPeter Maydell static Property next_pc_properties[] = { 912b497f4a1SPeter Maydell DEFINE_PROP_LINK("cpu", NeXTPC, cpu, TYPE_M68K_CPU, M68kCPU *), 913b497f4a1SPeter Maydell DEFINE_PROP_END_OF_LIST(), 914b497f4a1SPeter Maydell }; 915b497f4a1SPeter Maydell 91675ca77ecSPeter Maydell static const VMStateDescription next_rtc_vmstate = { 91775ca77ecSPeter Maydell .name = "next-rtc", 91888d0c5b0SMark Cave-Ayland .version_id = 2, 91988d0c5b0SMark Cave-Ayland .minimum_version_id = 2, 92075ca77ecSPeter Maydell .fields = (VMStateField[]) { 92188d0c5b0SMark Cave-Ayland VMSTATE_INT8(phase, NextRtc), 92275ca77ecSPeter Maydell VMSTATE_UINT8_ARRAY(ram, NextRtc, 32), 92375ca77ecSPeter Maydell VMSTATE_UINT8(command, NextRtc), 92475ca77ecSPeter Maydell VMSTATE_UINT8(value, NextRtc), 92575ca77ecSPeter Maydell VMSTATE_UINT8(status, NextRtc), 92675ca77ecSPeter Maydell VMSTATE_UINT8(control, NextRtc), 92775ca77ecSPeter Maydell VMSTATE_UINT8(retval, NextRtc), 92875ca77ecSPeter Maydell VMSTATE_END_OF_LIST() 92975ca77ecSPeter Maydell }, 93075ca77ecSPeter Maydell }; 93175ca77ecSPeter Maydell 93275ca77ecSPeter Maydell static const VMStateDescription next_pc_vmstate = { 93375ca77ecSPeter Maydell .name = "next-pc", 9348220baa0SMark Cave-Ayland .version_id = 2, 9358220baa0SMark Cave-Ayland .minimum_version_id = 2, 93675ca77ecSPeter Maydell .fields = (VMStateField[]) { 93775ca77ecSPeter Maydell VMSTATE_UINT32(scr1, NeXTPC), 93875ca77ecSPeter Maydell VMSTATE_UINT32(scr2, NeXTPC), 93922cf5ee3SMark Cave-Ayland VMSTATE_UINT32(old_scr2, NeXTPC), 94075ca77ecSPeter Maydell VMSTATE_UINT32(int_mask, NeXTPC), 94175ca77ecSPeter Maydell VMSTATE_UINT32(int_status, NeXTPC), 9428220baa0SMark Cave-Ayland VMSTATE_UINT32(led, NeXTPC), 94375ca77ecSPeter Maydell VMSTATE_UINT8(scsi_csr_1, NeXTPC), 94475ca77ecSPeter Maydell VMSTATE_UINT8(scsi_csr_2, NeXTPC), 94575ca77ecSPeter Maydell VMSTATE_STRUCT(rtc, NeXTPC, 0, next_rtc_vmstate, NextRtc), 94675ca77ecSPeter Maydell VMSTATE_END_OF_LIST() 94775ca77ecSPeter Maydell }, 94875ca77ecSPeter Maydell }; 94975ca77ecSPeter Maydell 950660bef33SPeter Maydell static void next_pc_class_init(ObjectClass *klass, void *data) 951660bef33SPeter Maydell { 952660bef33SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 953660bef33SPeter Maydell 954660bef33SPeter Maydell dc->desc = "NeXT Peripheral Controller"; 955660bef33SPeter Maydell dc->realize = next_pc_realize; 956660bef33SPeter Maydell dc->reset = next_pc_reset; 957b497f4a1SPeter Maydell device_class_set_props(dc, next_pc_properties); 95875ca77ecSPeter Maydell dc->vmsd = &next_pc_vmstate; 959660bef33SPeter Maydell } 960660bef33SPeter Maydell 961660bef33SPeter Maydell static const TypeInfo next_pc_info = { 962660bef33SPeter Maydell .name = TYPE_NEXT_PC, 963660bef33SPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 964660bef33SPeter Maydell .instance_size = sizeof(NeXTPC), 965660bef33SPeter Maydell .class_init = next_pc_class_init, 966660bef33SPeter Maydell }; 967660bef33SPeter Maydell 968956a7811SThomas Huth static void next_cube_init(MachineState *machine) 969956a7811SThomas Huth { 970956a7811SThomas Huth M68kCPU *cpu; 971956a7811SThomas Huth CPUM68KState *env; 972956a7811SThomas Huth MemoryRegion *rom = g_new(MemoryRegion, 1); 97387f4ba9eSThomas Huth MemoryRegion *rom2 = g_new(MemoryRegion, 1); 974956a7811SThomas Huth MemoryRegion *dmamem = g_new(MemoryRegion, 1); 975956a7811SThomas Huth MemoryRegion *bmapm1 = g_new(MemoryRegion, 1); 976956a7811SThomas Huth MemoryRegion *bmapm2 = g_new(MemoryRegion, 1); 977956a7811SThomas Huth MemoryRegion *sysmem = get_system_memory(); 9781684273cSPaolo Bonzini const char *bios_name = machine->firmware ?: ROM_FILE; 979660bef33SPeter Maydell DeviceState *pcdev; 980956a7811SThomas Huth 981956a7811SThomas Huth /* Initialize the cpu core */ 982956a7811SThomas Huth cpu = M68K_CPU(cpu_create(machine->cpu_type)); 983956a7811SThomas Huth if (!cpu) { 984956a7811SThomas Huth error_report("Unable to find m68k CPU definition"); 985956a7811SThomas Huth exit(1); 986956a7811SThomas Huth } 987956a7811SThomas Huth env = &cpu->env; 988956a7811SThomas Huth 989956a7811SThomas Huth /* Initialize CPU registers. */ 990956a7811SThomas Huth env->vbr = 0; 991956a7811SThomas Huth env->sr = 0x2700; 992956a7811SThomas Huth 993660bef33SPeter Maydell /* Peripheral Controller */ 994660bef33SPeter Maydell pcdev = qdev_new(TYPE_NEXT_PC); 995b497f4a1SPeter Maydell object_property_set_link(OBJECT(pcdev), "cpu", OBJECT(cpu), &error_abort); 996660bef33SPeter Maydell sysbus_realize_and_unref(SYS_BUS_DEVICE(pcdev), &error_fatal); 997956a7811SThomas Huth 998956a7811SThomas Huth /* 64MB RAM starting at 0x04000000 */ 99949b64ba9SIgor Mammedov memory_region_add_subregion(sysmem, 0x04000000, machine->ram); 1000956a7811SThomas Huth 1001956a7811SThomas Huth /* Framebuffer */ 1002b2897f7eSPhilippe Mathieu-Daudé sysbus_create_simple(TYPE_NEXTFB, 0x0B000000, NULL); 1003956a7811SThomas Huth 1004956a7811SThomas Huth /* MMIO */ 100540831636SPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000); 1006956a7811SThomas Huth 10071dc7aeaeSPeter Maydell /* BMAP IO - acts as a catch-all for now */ 10081dc7aeaeSPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000); 10091dc7aeaeSPeter Maydell 1010956a7811SThomas Huth /* BMAP memory */ 10117f863cbaSDavid Hildenbrand memory_region_init_ram_flags_nomigrate(bmapm1, NULL, "next.bmapmem", 64, 10127f863cbaSDavid Hildenbrand RAM_SHARED, &error_fatal); 1013956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x020c0000, bmapm1); 1014956a7811SThomas Huth /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */ 1015956a7811SThomas Huth memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64); 1016956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x820c0000, bmapm2); 1017956a7811SThomas Huth 1018956a7811SThomas Huth /* KBD */ 1019b2897f7eSPhilippe Mathieu-Daudé sysbus_create_simple(TYPE_NEXTKBD, 0x0200e000, NULL); 1020956a7811SThomas Huth 1021956a7811SThomas Huth /* Load ROM here */ 1022956a7811SThomas Huth memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal); 1023956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x01000000, rom); 102487f4ba9eSThomas Huth memory_region_init_alias(rom2, NULL, "next.rom2", rom, 0x0, 0x20000); 102587f4ba9eSThomas Huth memory_region_add_subregion(sysmem, 0x0, rom2); 1026956a7811SThomas Huth if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) { 1027956a7811SThomas Huth if (!qtest_enabled()) { 1028956a7811SThomas Huth error_report("Failed to load firmware '%s'.", bios_name); 1029956a7811SThomas Huth } 1030956a7811SThomas Huth } else { 1031956a7811SThomas Huth uint8_t *ptr; 1032956a7811SThomas Huth /* Initial PC is always at offset 4 in firmware binaries */ 1033956a7811SThomas Huth ptr = rom_ptr(0x01000004, 4); 1034956a7811SThomas Huth g_assert(ptr != NULL); 1035956a7811SThomas Huth env->pc = ldl_p(ptr); 1036956a7811SThomas Huth if (env->pc >= 0x01020000) { 1037956a7811SThomas Huth error_report("'%s' does not seem to be a valid firmware image.", 1038956a7811SThomas Huth bios_name); 1039956a7811SThomas Huth exit(1); 1040956a7811SThomas Huth } 1041956a7811SThomas Huth } 1042956a7811SThomas Huth 1043956a7811SThomas Huth /* Serial */ 1044b497f4a1SPeter Maydell next_escc_init(pcdev); 1045b17bed5bSThomas Huth 1046b17bed5bSThomas Huth /* TODO: */ 1047956a7811SThomas Huth /* Network */ 1048956a7811SThomas Huth /* SCSI */ 1049f2a80c6eSThomas Huth next_scsi_init(pcdev, cpu); 1050956a7811SThomas Huth 1051956a7811SThomas Huth /* DMA */ 1052c0dedcf4SMark Cave-Ayland memory_region_init_io(dmamem, NULL, &next_dma_ops, machine, "next.dma", 1053c0dedcf4SMark Cave-Ayland 0x5000); 1054956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x02000000, dmamem); 1055956a7811SThomas Huth } 1056956a7811SThomas Huth 1057956a7811SThomas Huth static void next_machine_class_init(ObjectClass *oc, void *data) 1058956a7811SThomas Huth { 1059956a7811SThomas Huth MachineClass *mc = MACHINE_CLASS(oc); 1060956a7811SThomas Huth 1061956a7811SThomas Huth mc->desc = "NeXT Cube"; 1062956a7811SThomas Huth mc->init = next_cube_init; 1063f2a80c6eSThomas Huth mc->block_default_type = IF_SCSI; 1064956a7811SThomas Huth mc->default_ram_size = RAM_SIZE; 106549b64ba9SIgor Mammedov mc->default_ram_id = "next.ram"; 1066956a7811SThomas Huth mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); 1067956a7811SThomas Huth } 1068956a7811SThomas Huth 1069956a7811SThomas Huth static const TypeInfo next_typeinfo = { 1070956a7811SThomas Huth .name = TYPE_NEXT_MACHINE, 1071956a7811SThomas Huth .parent = TYPE_MACHINE, 1072956a7811SThomas Huth .class_init = next_machine_class_init, 1073956a7811SThomas Huth .instance_size = sizeof(NeXTState), 1074956a7811SThomas Huth }; 1075956a7811SThomas Huth 1076956a7811SThomas Huth static void next_register_type(void) 1077956a7811SThomas Huth { 1078956a7811SThomas Huth type_register_static(&next_typeinfo); 1079660bef33SPeter Maydell type_register_static(&next_pc_info); 1080956a7811SThomas Huth } 1081956a7811SThomas Huth 1082956a7811SThomas Huth type_init(next_register_type) 1083