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 { 65cd4fc142SThomas Huth uint8_t ram[32]; 66cd4fc142SThomas Huth uint8_t command; 67cd4fc142SThomas Huth uint8_t value; 68cd4fc142SThomas Huth uint8_t status; 69cd4fc142SThomas Huth uint8_t control; 70cd4fc142SThomas Huth uint8_t retval; 71cd4fc142SThomas Huth } NextRtc; 72cd4fc142SThomas Huth 73db1015e9SEduardo Habkost struct NeXTState { 74956a7811SThomas Huth MachineState parent; 75956a7811SThomas Huth 76956a7811SThomas Huth next_dma dma[10]; 77db1015e9SEduardo Habkost }; 78956a7811SThomas Huth 79660bef33SPeter Maydell #define TYPE_NEXT_PC "next-pc" 80660bef33SPeter Maydell OBJECT_DECLARE_SIMPLE_TYPE(NeXTPC, NEXT_PC) 81660bef33SPeter Maydell 82660bef33SPeter Maydell /* NeXT Peripheral Controller */ 83660bef33SPeter Maydell struct NeXTPC { 84660bef33SPeter Maydell SysBusDevice parent_obj; 85660bef33SPeter Maydell 86b497f4a1SPeter Maydell M68kCPU *cpu; 87b497f4a1SPeter Maydell 8840831636SPeter Maydell MemoryRegion mmiomem; 891dc7aeaeSPeter Maydell MemoryRegion scrmem; 9040831636SPeter Maydell 9140831636SPeter Maydell uint32_t scr1; 9240831636SPeter Maydell uint32_t scr2; 93ac99317bSPeter Maydell uint32_t int_mask; 94ac99317bSPeter Maydell uint32_t int_status; 95*8220baa0SMark Cave-Ayland uint32_t led; 96f2a80c6eSThomas Huth uint8_t scsi_csr_1; 97f2a80c6eSThomas Huth uint8_t scsi_csr_2; 98f2a80c6eSThomas Huth 99f2a80c6eSThomas Huth qemu_irq scsi_reset; 100f2a80c6eSThomas Huth qemu_irq scsi_dma; 1016f0face7SPeter Maydell 1026f0face7SPeter Maydell NextRtc rtc; 103660bef33SPeter Maydell }; 104660bef33SPeter Maydell 105956a7811SThomas Huth /* Thanks to NeXT forums for this */ 106956a7811SThomas Huth /* 107956a7811SThomas Huth static const uint8_t rtc_ram3[32] = { 108956a7811SThomas Huth 0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 109956a7811SThomas Huth 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00, 110956a7811SThomas Huth 0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 111956a7811SThomas Huth 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13 112956a7811SThomas Huth }; 113956a7811SThomas Huth */ 114956a7811SThomas Huth static const uint8_t rtc_ram2[32] = { 115956a7811SThomas Huth 0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 116956a7811SThomas Huth 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00, 117956a7811SThomas Huth 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 118956a7811SThomas Huth 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e, 119956a7811SThomas Huth }; 120956a7811SThomas Huth 121956a7811SThomas Huth #define SCR2_RTCLK 0x2 122956a7811SThomas Huth #define SCR2_RTDATA 0x4 123956a7811SThomas Huth #define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10)) 124956a7811SThomas Huth 12540831636SPeter Maydell static void nextscr2_write(NeXTPC *s, uint32_t val, int size) 126956a7811SThomas Huth { 127956a7811SThomas Huth static int phase; 128956a7811SThomas Huth static uint8_t old_scr2; 129956a7811SThomas Huth uint8_t scr2_2; 1306f0face7SPeter Maydell NextRtc *rtc = &s->rtc; 131956a7811SThomas Huth 132956a7811SThomas Huth if (size == 4) { 133956a7811SThomas Huth scr2_2 = (val >> 8) & 0xFF; 134956a7811SThomas Huth } else { 135956a7811SThomas Huth scr2_2 = val & 0xFF; 136956a7811SThomas Huth } 137956a7811SThomas Huth 138956a7811SThomas Huth if (val & 0x1) { 139956a7811SThomas Huth DPRINTF("fault!\n"); 140*8220baa0SMark Cave-Ayland s->led++; 141*8220baa0SMark Cave-Ayland if (s->led == 10) { 142956a7811SThomas Huth DPRINTF("LED flashing, possible fault!\n"); 143*8220baa0SMark Cave-Ayland s->led = 0; 144956a7811SThomas Huth } 145956a7811SThomas Huth } 146956a7811SThomas Huth 147956a7811SThomas Huth if (scr2_2 & 0x1) { 148956a7811SThomas Huth /* DPRINTF("RTC %x phase %i\n", scr2_2, phase); */ 149956a7811SThomas Huth if (phase == -1) { 150956a7811SThomas Huth 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)) { 155956a7811SThomas Huth if (phase < 8) { 156cd4fc142SThomas Huth rtc->command = (rtc->command << 1) | 157956a7811SThomas Huth ((scr2_2 & SCR2_RTDATA) ? 1 : 0); 158956a7811SThomas Huth } 159956a7811SThomas Huth if (phase >= 8 && 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); 166cd4fc142SThomas Huth if (rtc->ram[rtc->command] & (0x80 >> (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) */ 177cd4fc142SThomas Huth if (rtc->status & (0x80 >> (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); 187cd4fc142SThomas Huth if (rtc->control & (0x80 >> (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 223956a7811SThomas Huth if (ret & (0x80 >> (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 232956a7811SThomas Huth phase++; 233956a7811SThomas Huth if (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 */ 249956a7811SThomas Huth phase = -1; 250cd4fc142SThomas Huth rtc->command = 0; 251cd4fc142SThomas Huth rtc->value = 0; 252956a7811SThomas Huth } 253956a7811SThomas Huth s->scr2 = val & 0xFFFF00FF; 254956a7811SThomas Huth s->scr2 |= scr2_2 << 8; 255956a7811SThomas Huth old_scr2 = scr2_2; 256956a7811SThomas Huth } 257956a7811SThomas Huth 2587e993d93SMark Cave-Ayland static uint64_t next_mmio_read(void *opaque, hwaddr addr, unsigned size) 259956a7811SThomas Huth { 2607e993d93SMark Cave-Ayland NeXTPC *s = NEXT_PC(opaque); 2617e993d93SMark Cave-Ayland uint64_t val; 262956a7811SThomas Huth 263956a7811SThomas Huth switch (addr) { 264956a7811SThomas Huth case 0x7000: 265ac99317bSPeter Maydell /* DPRINTF("Read INT status: %x\n", s->int_status); */ 2667e993d93SMark Cave-Ayland val = s->int_status; 2677e993d93SMark Cave-Ayland break; 268956a7811SThomas Huth 269956a7811SThomas Huth case 0x7800: 270ac99317bSPeter Maydell DPRINTF("MMIO Read INT mask: %x\n", s->int_mask); 2717e993d93SMark Cave-Ayland val = s->int_mask; 272956a7811SThomas Huth break; 273956a7811SThomas Huth 2747e993d93SMark Cave-Ayland case 0xc000 ... 0xc003: 2757e993d93SMark Cave-Ayland val = extract32(s->scr1, (4 - (addr - 0xc000) - size) << 3, 2767e993d93SMark Cave-Ayland size << 3); 2777e993d93SMark Cave-Ayland break; 278956a7811SThomas Huth 2797e993d93SMark Cave-Ayland case 0xd000 ... 0xd003: 2807e993d93SMark Cave-Ayland val = extract32(s->scr2, (4 - (addr - 0xd000) - size) << 3, 2817e993d93SMark Cave-Ayland size << 3); 2827e993d93SMark Cave-Ayland break; 283956a7811SThomas Huth 2847e993d93SMark Cave-Ayland case 0x14020: 2857e993d93SMark Cave-Ayland val = 0x7f; 286956a7811SThomas Huth break; 287956a7811SThomas Huth 288956a7811SThomas Huth default: 2897e993d93SMark Cave-Ayland val = 0; 2907e993d93SMark Cave-Ayland DPRINTF("MMIO Read @ 0x%"HWADDR_PRIx" size %d\n", addr, size); 2917e993d93SMark Cave-Ayland break; 292956a7811SThomas Huth } 293956a7811SThomas Huth 2947e993d93SMark Cave-Ayland return val; 295956a7811SThomas Huth } 296956a7811SThomas Huth 2977e993d93SMark Cave-Ayland static void next_mmio_write(void *opaque, hwaddr addr, uint64_t val, 298956a7811SThomas Huth unsigned size) 299956a7811SThomas Huth { 30040831636SPeter Maydell NeXTPC *s = NEXT_PC(opaque); 301956a7811SThomas Huth 3027e993d93SMark Cave-Ayland switch (addr) { 3037e993d93SMark Cave-Ayland case 0x7000: 3047e993d93SMark Cave-Ayland DPRINTF("INT Status old: %x new: %x\n", s->int_status, 3057e993d93SMark Cave-Ayland (unsigned int)val); 3067e993d93SMark Cave-Ayland s->int_status = val; 307956a7811SThomas Huth break; 3087e993d93SMark Cave-Ayland 3097e993d93SMark Cave-Ayland case 0x7800: 3107e993d93SMark Cave-Ayland DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, (unsigned int)val); 3117e993d93SMark Cave-Ayland s->int_mask = val; 312956a7811SThomas Huth break; 3137e993d93SMark Cave-Ayland 3147e993d93SMark Cave-Ayland case 0xc000 ... 0xc003: 3157e993d93SMark Cave-Ayland DPRINTF("SCR1 Write: %x\n", (unsigned int)val); 3167e993d93SMark Cave-Ayland s->scr1 = deposit32(s->scr1, (4 - (addr - 0xc000) - size) << 3, 3177e993d93SMark Cave-Ayland size << 3, val); 318956a7811SThomas Huth break; 3197e993d93SMark Cave-Ayland 3207e993d93SMark Cave-Ayland case 0xd000 ... 0xd003: 3217e993d93SMark Cave-Ayland nextscr2_write(s, val, size); 3227e993d93SMark Cave-Ayland break; 3237e993d93SMark Cave-Ayland 324956a7811SThomas Huth default: 3257e993d93SMark Cave-Ayland DPRINTF("MMIO Write @ 0x%"HWADDR_PRIx " with 0x%x size %u\n", addr, 3267e993d93SMark Cave-Ayland (unsigned int)val, size); 327956a7811SThomas Huth } 328956a7811SThomas Huth } 329956a7811SThomas Huth 3307e993d93SMark Cave-Ayland static const MemoryRegionOps next_mmio_ops = { 3317e993d93SMark Cave-Ayland .read = next_mmio_read, 3327e993d93SMark Cave-Ayland .write = next_mmio_write, 333956a7811SThomas Huth .valid.min_access_size = 1, 334956a7811SThomas Huth .valid.max_access_size = 4, 3357e993d93SMark Cave-Ayland .endianness = DEVICE_BIG_ENDIAN, 336956a7811SThomas Huth }; 337956a7811SThomas Huth 338956a7811SThomas Huth #define SCSICSR_ENABLE 0x01 339956a7811SThomas Huth #define SCSICSR_RESET 0x02 /* reset scsi dma */ 340956a7811SThomas Huth #define SCSICSR_FIFOFL 0x04 341956a7811SThomas Huth #define SCSICSR_DMADIR 0x08 /* if set, scsi to mem */ 342956a7811SThomas Huth #define SCSICSR_CPUDMA 0x10 /* if set, dma enabled */ 343956a7811SThomas Huth #define SCSICSR_INTMASK 0x20 /* if set, interrupt enabled */ 344956a7811SThomas Huth 3450d60da39SMark Cave-Ayland static uint64_t next_scr_readfn(void *opaque, hwaddr addr, unsigned size) 346956a7811SThomas Huth { 3470d60da39SMark Cave-Ayland NeXTPC *s = NEXT_PC(opaque); 3480d60da39SMark Cave-Ayland uint64_t val; 3490d60da39SMark Cave-Ayland 3500d60da39SMark Cave-Ayland switch (addr) { 3510d60da39SMark Cave-Ayland case 0x14108: 3520d60da39SMark Cave-Ayland DPRINTF("FD read @ %x\n", (unsigned int)addr); 3530d60da39SMark Cave-Ayland val = 0x40 | 0x04 | 0x2 | 0x1; 3540d60da39SMark Cave-Ayland break; 3550d60da39SMark Cave-Ayland 3560d60da39SMark Cave-Ayland case 0x14020: 3570d60da39SMark Cave-Ayland DPRINTF("SCSI 4020 STATUS READ %X\n", s->scsi_csr_1); 3580d60da39SMark Cave-Ayland val = s->scsi_csr_1; 3590d60da39SMark Cave-Ayland break; 3600d60da39SMark Cave-Ayland 3610d60da39SMark Cave-Ayland case 0x14021: 3620d60da39SMark Cave-Ayland DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2); 3630d60da39SMark Cave-Ayland val = 0x40; 3640d60da39SMark Cave-Ayland break; 3650d60da39SMark Cave-Ayland 3660d60da39SMark Cave-Ayland /* 3670d60da39SMark Cave-Ayland * These 4 registers are the hardware timer, not sure which register 3680d60da39SMark Cave-Ayland * is the latch instead of data, but no problems so far. 3690d60da39SMark Cave-Ayland * 3700d60da39SMark Cave-Ayland * Hack: We need to have the LSB change consistently to make it work 3710d60da39SMark Cave-Ayland */ 3720d60da39SMark Cave-Ayland case 0x1a000 ... 0x1a003: 3730d60da39SMark Cave-Ayland val = extract32(clock(), (4 - (addr - 0x1a000) - size) << 3, 3740d60da39SMark Cave-Ayland size << 3); 3750d60da39SMark Cave-Ayland break; 3760d60da39SMark Cave-Ayland 3770d60da39SMark Cave-Ayland /* For now return dummy byte to allow the Ethernet test to timeout */ 3780d60da39SMark Cave-Ayland case 0x6000: 3790d60da39SMark Cave-Ayland val = 0xff; 3800d60da39SMark Cave-Ayland break; 3810d60da39SMark Cave-Ayland 3820d60da39SMark Cave-Ayland default: 3830d60da39SMark Cave-Ayland DPRINTF("BMAP Read @ 0x%x size %u\n", (unsigned int)addr, size); 3840d60da39SMark Cave-Ayland val = 0; 3850d60da39SMark Cave-Ayland break; 3860d60da39SMark Cave-Ayland } 3870d60da39SMark Cave-Ayland 3880d60da39SMark Cave-Ayland return val; 3890d60da39SMark Cave-Ayland } 3900d60da39SMark Cave-Ayland 3910d60da39SMark Cave-Ayland static void next_scr_writefn(void *opaque, hwaddr addr, uint64_t val, 3920d60da39SMark Cave-Ayland unsigned size) 3930d60da39SMark Cave-Ayland { 3940d60da39SMark Cave-Ayland NeXTPC *s = NEXT_PC(opaque); 3950d60da39SMark Cave-Ayland 396956a7811SThomas Huth switch (addr) { 397956a7811SThomas Huth case 0x14108: 398956a7811SThomas Huth DPRINTF("FDCSR Write: %x\n", value); 3990d60da39SMark Cave-Ayland if (val == 0x0) { 400956a7811SThomas Huth /* qemu_irq_raise(s->fd_irq[0]); */ 401956a7811SThomas Huth } 402956a7811SThomas Huth break; 4030d60da39SMark Cave-Ayland 404956a7811SThomas Huth case 0x14020: /* SCSI Control Register */ 4050d60da39SMark Cave-Ayland if (val & SCSICSR_FIFOFL) { 406956a7811SThomas Huth DPRINTF("SCSICSR FIFO Flush\n"); 407956a7811SThomas Huth /* will have to add another irq to the esp if this is needed */ 408956a7811SThomas Huth /* esp_puflush_fifo(esp_g); */ 409956a7811SThomas Huth } 410956a7811SThomas Huth 4110d60da39SMark Cave-Ayland if (val & SCSICSR_ENABLE) { 412956a7811SThomas Huth DPRINTF("SCSICSR Enable\n"); 413956a7811SThomas Huth /* 414956a7811SThomas Huth * qemu_irq_raise(s->scsi_dma); 415956a7811SThomas Huth * s->scsi_csr_1 = 0xc0; 416956a7811SThomas Huth * s->scsi_csr_1 |= 0x1; 417956a7811SThomas Huth * qemu_irq_pulse(s->scsi_dma); 418956a7811SThomas Huth */ 419956a7811SThomas Huth } 420956a7811SThomas Huth /* 421956a7811SThomas Huth * else 422956a7811SThomas Huth * s->scsi_csr_1 &= ~SCSICSR_ENABLE; 423956a7811SThomas Huth */ 424956a7811SThomas Huth 4250d60da39SMark Cave-Ayland if (val & SCSICSR_RESET) { 426956a7811SThomas Huth DPRINTF("SCSICSR Reset\n"); 427956a7811SThomas Huth /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */ 428f2a80c6eSThomas Huth qemu_irq_raise(s->scsi_reset); 429f2a80c6eSThomas Huth s->scsi_csr_1 &= ~(SCSICSR_INTMASK | 0x80 | 0x1); 430f2a80c6eSThomas Huth qemu_irq_lower(s->scsi_reset); 431956a7811SThomas Huth } 4320d60da39SMark Cave-Ayland if (val & SCSICSR_DMADIR) { 433956a7811SThomas Huth DPRINTF("SCSICSR DMAdir\n"); 434956a7811SThomas Huth } 4350d60da39SMark Cave-Ayland if (val & SCSICSR_CPUDMA) { 436956a7811SThomas Huth DPRINTF("SCSICSR CPUDMA\n"); 437956a7811SThomas Huth /* qemu_irq_raise(s->scsi_dma); */ 438ac99317bSPeter Maydell s->int_status |= 0x4000000; 439956a7811SThomas Huth } else { 440f2a80c6eSThomas Huth /* fprintf(stderr,"SCSICSR CPUDMA disabled\n"); */ 441ac99317bSPeter Maydell s->int_status &= ~(0x4000000); 442f2a80c6eSThomas Huth /* qemu_irq_lower(s->scsi_dma); */ 443956a7811SThomas Huth } 4440d60da39SMark Cave-Ayland if (val & SCSICSR_INTMASK) { 445956a7811SThomas Huth DPRINTF("SCSICSR INTMASK\n"); 446956a7811SThomas Huth /* 447956a7811SThomas Huth * int_mask &= ~0x1000; 4480d60da39SMark Cave-Ayland * s->scsi_csr_1 |= val; 449956a7811SThomas Huth * s->scsi_csr_1 &= ~SCSICSR_INTMASK; 450956a7811SThomas Huth * if (s->scsi_queued) { 451956a7811SThomas Huth * s->scsi_queued = 0; 452956a7811SThomas Huth * next_irq(s, NEXT_SCSI_I, level); 453956a7811SThomas Huth * } 454956a7811SThomas Huth */ 455956a7811SThomas Huth } else { 456956a7811SThomas Huth /* int_mask |= 0x1000; */ 457956a7811SThomas Huth } 4580d60da39SMark Cave-Ayland if (val & 0x80) { 459956a7811SThomas Huth /* int_mask |= 0x1000; */ 460956a7811SThomas Huth /* s->scsi_csr_1 |= 0x80; */ 461956a7811SThomas Huth } 4620d60da39SMark Cave-Ayland DPRINTF("SCSICSR Write: %x\n", val); 4630d60da39SMark Cave-Ayland /* s->scsi_csr_1 = val; */ 4640d60da39SMark Cave-Ayland break; 4650d60da39SMark Cave-Ayland 466956a7811SThomas Huth /* Hardware timer latch - not implemented yet */ 467956a7811SThomas Huth case 0x1a000: 468956a7811SThomas Huth default: 4690d60da39SMark Cave-Ayland DPRINTF("BMAP Write @ 0x%x with 0x%x size %u\n", (unsigned int)addr, 4700d60da39SMark Cave-Ayland val, size); 471956a7811SThomas Huth } 472956a7811SThomas Huth } 473956a7811SThomas Huth 4740d60da39SMark Cave-Ayland static const MemoryRegionOps next_scr_ops = { 4750d60da39SMark Cave-Ayland .read = next_scr_readfn, 4760d60da39SMark Cave-Ayland .write = next_scr_writefn, 477956a7811SThomas Huth .valid.min_access_size = 1, 478956a7811SThomas Huth .valid.max_access_size = 4, 4790d60da39SMark Cave-Ayland .endianness = DEVICE_BIG_ENDIAN, 480956a7811SThomas Huth }; 481956a7811SThomas Huth 482956a7811SThomas Huth #define NEXTDMA_SCSI(x) (0x10 + x) 483956a7811SThomas Huth #define NEXTDMA_FD(x) (0x10 + x) 484956a7811SThomas Huth #define NEXTDMA_ENTX(x) (0x110 + x) 485956a7811SThomas Huth #define NEXTDMA_ENRX(x) (0x150 + x) 486956a7811SThomas Huth #define NEXTDMA_CSR 0x0 487956a7811SThomas Huth #define NEXTDMA_NEXT 0x4000 488956a7811SThomas Huth #define NEXTDMA_LIMIT 0x4004 489956a7811SThomas Huth #define NEXTDMA_START 0x4008 490956a7811SThomas Huth #define NEXTDMA_STOP 0x400c 491956a7811SThomas Huth #define NEXTDMA_NEXT_INIT 0x4200 492956a7811SThomas Huth #define NEXTDMA_SIZE 0x4204 493956a7811SThomas Huth 494c0dedcf4SMark Cave-Ayland static void next_dma_write(void *opaque, hwaddr addr, uint64_t val, 495956a7811SThomas Huth unsigned int size) 496956a7811SThomas Huth { 497956a7811SThomas Huth NeXTState *next_state = NEXT_MACHINE(opaque); 498956a7811SThomas Huth 499956a7811SThomas Huth switch (addr) { 500956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_CSR): 501c0dedcf4SMark Cave-Ayland if (val & DMA_DEV2M) { 502956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M; 503956a7811SThomas Huth } 504956a7811SThomas Huth 505c0dedcf4SMark Cave-Ayland if (val & DMA_SETENABLE) { 506956a7811SThomas Huth /* DPRINTF("SCSI DMA ENABLE\n"); */ 507956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE; 508956a7811SThomas Huth } 509c0dedcf4SMark Cave-Ayland if (val & DMA_SETSUPDATE) { 510956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE; 511956a7811SThomas Huth } 512c0dedcf4SMark Cave-Ayland if (val & DMA_CLRCOMPLETE) { 513956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE; 514956a7811SThomas Huth } 515956a7811SThomas Huth 516c0dedcf4SMark Cave-Ayland if (val & DMA_RESET) { 517956a7811SThomas Huth next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | 518956a7811SThomas Huth DMA_ENABLE | DMA_DEV2M); 519956a7811SThomas Huth } 520956a7811SThomas Huth /* DPRINTF("RXCSR \tWrite: %x\n",value); */ 521956a7811SThomas Huth break; 522c0dedcf4SMark Cave-Ayland 523956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT): 524c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_ENRX].next_initbuf = val; 525956a7811SThomas Huth break; 526c0dedcf4SMark Cave-Ayland 527956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT): 528c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_ENRX].next = val; 529956a7811SThomas Huth break; 530c0dedcf4SMark Cave-Ayland 531956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_LIMIT): 532c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_ENRX].limit = val; 533956a7811SThomas Huth break; 534c0dedcf4SMark Cave-Ayland 535956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_CSR): 536c0dedcf4SMark Cave-Ayland if (val & DMA_DEV2M) { 537956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M; 538956a7811SThomas Huth } 539c0dedcf4SMark Cave-Ayland if (val & DMA_SETENABLE) { 540956a7811SThomas Huth /* DPRINTF("SCSI DMA ENABLE\n"); */ 541956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE; 542956a7811SThomas Huth } 543c0dedcf4SMark Cave-Ayland if (val & DMA_SETSUPDATE) { 544956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE; 545956a7811SThomas Huth } 546c0dedcf4SMark Cave-Ayland if (val & DMA_CLRCOMPLETE) { 547956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE; 548956a7811SThomas Huth } 549956a7811SThomas Huth 550c0dedcf4SMark Cave-Ayland if (val & DMA_RESET) { 551956a7811SThomas Huth next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | 552956a7811SThomas Huth DMA_ENABLE | DMA_DEV2M); 553956a7811SThomas Huth /* DPRINTF("SCSI DMA RESET\n"); */ 554956a7811SThomas Huth } 555956a7811SThomas Huth /* DPRINTF("RXCSR \tWrite: %x\n",value); */ 556956a7811SThomas Huth break; 557956a7811SThomas Huth 558956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT): 559c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].next = val; 560956a7811SThomas Huth break; 561956a7811SThomas Huth 562956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_LIMIT): 563c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].limit = val; 564956a7811SThomas Huth break; 565956a7811SThomas Huth 566956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_START): 567c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].start = val; 568956a7811SThomas Huth break; 569956a7811SThomas Huth 570956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_STOP): 571c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].stop = val; 572956a7811SThomas Huth break; 573956a7811SThomas Huth 574956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT): 575c0dedcf4SMark Cave-Ayland next_state->dma[NEXTDMA_SCSI].next_initbuf = val; 576956a7811SThomas Huth break; 577956a7811SThomas Huth 578956a7811SThomas Huth default: 579956a7811SThomas Huth DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value); 580956a7811SThomas Huth } 581956a7811SThomas Huth } 582956a7811SThomas Huth 583c0dedcf4SMark Cave-Ayland static uint64_t next_dma_read(void *opaque, hwaddr addr, unsigned int size) 584956a7811SThomas Huth { 585956a7811SThomas Huth NeXTState *next_state = NEXT_MACHINE(opaque); 586c0dedcf4SMark Cave-Ayland uint64_t val; 587956a7811SThomas Huth 588956a7811SThomas Huth switch (addr) { 589956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_CSR): 590956a7811SThomas Huth DPRINTF("SCSI DMA CSR READ\n"); 591c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].csr; 592c0dedcf4SMark Cave-Ayland break; 593c0dedcf4SMark Cave-Ayland 594956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_CSR): 595c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].csr; 596c0dedcf4SMark Cave-Ayland break; 597c0dedcf4SMark Cave-Ayland 598956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT): 599c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].next_initbuf; 600c0dedcf4SMark Cave-Ayland break; 601c0dedcf4SMark Cave-Ayland 602956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_NEXT): 603c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].next; 604c0dedcf4SMark Cave-Ayland break; 605c0dedcf4SMark Cave-Ayland 606956a7811SThomas Huth case NEXTDMA_ENRX(NEXTDMA_LIMIT): 607c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_ENRX].limit; 608c0dedcf4SMark Cave-Ayland break; 609956a7811SThomas Huth 610956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT): 611c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].next; 612c0dedcf4SMark Cave-Ayland break; 613c0dedcf4SMark Cave-Ayland 614956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT): 615c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].next_initbuf; 616c0dedcf4SMark Cave-Ayland break; 617c0dedcf4SMark Cave-Ayland 618956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_LIMIT): 619c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].limit; 620c0dedcf4SMark Cave-Ayland break; 621c0dedcf4SMark Cave-Ayland 622956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_START): 623c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].start; 624c0dedcf4SMark Cave-Ayland break; 625c0dedcf4SMark Cave-Ayland 626956a7811SThomas Huth case NEXTDMA_SCSI(NEXTDMA_STOP): 627c0dedcf4SMark Cave-Ayland val = next_state->dma[NEXTDMA_SCSI].stop; 628c0dedcf4SMark Cave-Ayland break; 629956a7811SThomas Huth 630956a7811SThomas Huth default: 631956a7811SThomas Huth DPRINTF("DMA read @ %x\n", (unsigned int)addr); 632c0dedcf4SMark Cave-Ayland val = 0; 633956a7811SThomas Huth } 634956a7811SThomas Huth 635956a7811SThomas Huth /* 636956a7811SThomas Huth * once the csr's are done, subtract 0x3FEC from the addr, and that will 637956a7811SThomas Huth * normalize the upper registers 638956a7811SThomas Huth */ 639c0dedcf4SMark Cave-Ayland 640c0dedcf4SMark Cave-Ayland return val; 641956a7811SThomas Huth } 642956a7811SThomas Huth 643c0dedcf4SMark Cave-Ayland static const MemoryRegionOps next_dma_ops = { 644c0dedcf4SMark Cave-Ayland .read = next_dma_read, 645c0dedcf4SMark Cave-Ayland .write = next_dma_write, 646956a7811SThomas Huth .impl.min_access_size = 4, 647956a7811SThomas Huth .valid.min_access_size = 4, 648956a7811SThomas Huth .valid.max_access_size = 4, 649c0dedcf4SMark Cave-Ayland .endianness = DEVICE_BIG_ENDIAN, 650956a7811SThomas Huth }; 651956a7811SThomas Huth 652c8abcc87SPeter Maydell static void next_irq(void *opaque, int number, int level) 653956a7811SThomas Huth { 654b497f4a1SPeter Maydell NeXTPC *s = NEXT_PC(opaque); 655b497f4a1SPeter Maydell M68kCPU *cpu = s->cpu; 656956a7811SThomas Huth int shift = 0; 657956a7811SThomas Huth 6588b81968cSMichael Tokarev /* first switch sets interrupt status */ 659956a7811SThomas Huth /* DPRINTF("IRQ %i\n",number); */ 660956a7811SThomas Huth switch (number) { 661956a7811SThomas Huth /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */ 662956a7811SThomas Huth case NEXT_FD_I: 6635012a894SPhilippe Mathieu-Daudé shift = 7; 664956a7811SThomas Huth break; 665956a7811SThomas Huth case NEXT_KBD_I: 666956a7811SThomas Huth shift = 3; 667956a7811SThomas Huth break; 668956a7811SThomas Huth case NEXT_PWR_I: 669956a7811SThomas Huth shift = 2; 670956a7811SThomas Huth break; 671956a7811SThomas Huth case NEXT_ENRX_I: 672956a7811SThomas Huth shift = 9; 673956a7811SThomas Huth break; 674956a7811SThomas Huth case NEXT_ENTX_I: 675956a7811SThomas Huth shift = 10; 676956a7811SThomas Huth break; 677956a7811SThomas Huth case NEXT_SCSI_I: 678956a7811SThomas Huth shift = 12; 679956a7811SThomas Huth break; 680956a7811SThomas Huth case NEXT_CLK_I: 681956a7811SThomas Huth shift = 5; 682956a7811SThomas Huth break; 683956a7811SThomas Huth 684956a7811SThomas Huth /* level 5 - scc (serial) */ 685956a7811SThomas Huth case NEXT_SCC_I: 686956a7811SThomas Huth shift = 17; 687956a7811SThomas Huth break; 688956a7811SThomas Huth 689956a7811SThomas Huth /* level 6 - audio etherrx/tx dma */ 690956a7811SThomas Huth case NEXT_ENTX_DMA_I: 691956a7811SThomas Huth shift = 28; 692956a7811SThomas Huth break; 693956a7811SThomas Huth case NEXT_ENRX_DMA_I: 694956a7811SThomas Huth shift = 27; 695956a7811SThomas Huth break; 696956a7811SThomas Huth case NEXT_SCSI_DMA_I: 697956a7811SThomas Huth shift = 26; 698956a7811SThomas Huth break; 699956a7811SThomas Huth case NEXT_SND_I: 700956a7811SThomas Huth shift = 23; 701956a7811SThomas Huth break; 702956a7811SThomas Huth case NEXT_SCC_DMA_I: 703956a7811SThomas Huth shift = 21; 704956a7811SThomas Huth break; 705956a7811SThomas Huth 706956a7811SThomas Huth } 707956a7811SThomas Huth /* 708956a7811SThomas Huth * this HAS to be wrong, the interrupt handlers in mach and together 709956a7811SThomas Huth * int_status and int_mask and return if there is a hit 710956a7811SThomas Huth */ 711ac99317bSPeter Maydell if (s->int_mask & (1 << shift)) { 712956a7811SThomas Huth DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc); 713956a7811SThomas Huth /* return; */ 714956a7811SThomas Huth } 715956a7811SThomas Huth 716956a7811SThomas Huth /* second switch triggers the correct interrupt */ 717956a7811SThomas Huth if (level) { 718ac99317bSPeter Maydell s->int_status |= 1 << shift; 719956a7811SThomas Huth 720956a7811SThomas Huth switch (number) { 721956a7811SThomas Huth /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */ 722956a7811SThomas Huth case NEXT_FD_I: 723956a7811SThomas Huth case NEXT_KBD_I: 724956a7811SThomas Huth case NEXT_PWR_I: 725956a7811SThomas Huth case NEXT_ENRX_I: 726956a7811SThomas Huth case NEXT_ENTX_I: 727956a7811SThomas Huth case NEXT_SCSI_I: 728956a7811SThomas Huth case NEXT_CLK_I: 729956a7811SThomas Huth m68k_set_irq_level(cpu, 3, 27); 730956a7811SThomas Huth break; 731956a7811SThomas Huth 732956a7811SThomas Huth /* level 5 - scc (serial) */ 733956a7811SThomas Huth case NEXT_SCC_I: 734956a7811SThomas Huth m68k_set_irq_level(cpu, 5, 29); 735956a7811SThomas Huth break; 736956a7811SThomas Huth 737956a7811SThomas Huth /* level 6 - audio etherrx/tx dma */ 738956a7811SThomas Huth case NEXT_ENTX_DMA_I: 739956a7811SThomas Huth case NEXT_ENRX_DMA_I: 740956a7811SThomas Huth case NEXT_SCSI_DMA_I: 741956a7811SThomas Huth case NEXT_SND_I: 742956a7811SThomas Huth case NEXT_SCC_DMA_I: 743956a7811SThomas Huth m68k_set_irq_level(cpu, 6, 30); 744956a7811SThomas Huth break; 745956a7811SThomas Huth } 746956a7811SThomas Huth } else { 747ac99317bSPeter Maydell s->int_status &= ~(1 << shift); 748956a7811SThomas Huth cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 749956a7811SThomas Huth } 750956a7811SThomas Huth } 751956a7811SThomas Huth 752f2a80c6eSThomas Huth static void nextdma_write(void *opaque, uint8_t *buf, int size, int type) 753f2a80c6eSThomas Huth { 754f2a80c6eSThomas Huth uint32_t base_addr; 755f2a80c6eSThomas Huth int irq = 0; 756f2a80c6eSThomas Huth uint8_t align = 16; 757f2a80c6eSThomas Huth NeXTState *next_state = NEXT_MACHINE(qdev_get_machine()); 758f2a80c6eSThomas Huth 759f2a80c6eSThomas Huth if (type == NEXTDMA_ENRX || type == NEXTDMA_ENTX) { 760f2a80c6eSThomas Huth align = 32; 761f2a80c6eSThomas Huth } 762f2a80c6eSThomas Huth /* Most DMA is supposedly 16 byte aligned */ 763f2a80c6eSThomas Huth if ((size % align) != 0) { 764f2a80c6eSThomas Huth size -= size % align; 765f2a80c6eSThomas Huth size += align; 766f2a80c6eSThomas Huth } 767f2a80c6eSThomas Huth 768f2a80c6eSThomas Huth /* 769f2a80c6eSThomas Huth * prom sets the dma start using initbuf while the bootloader uses next 770f2a80c6eSThomas Huth * so we check to see if initbuf is 0 771f2a80c6eSThomas Huth */ 772f2a80c6eSThomas Huth if (next_state->dma[type].next_initbuf == 0) { 773f2a80c6eSThomas Huth base_addr = next_state->dma[type].next; 774f2a80c6eSThomas Huth } else { 775f2a80c6eSThomas Huth base_addr = next_state->dma[type].next_initbuf; 776f2a80c6eSThomas Huth } 777f2a80c6eSThomas Huth 778f2a80c6eSThomas Huth cpu_physical_memory_write(base_addr, buf, size); 779f2a80c6eSThomas Huth 780f2a80c6eSThomas Huth next_state->dma[type].next_initbuf = 0; 781f2a80c6eSThomas Huth 782f2a80c6eSThomas Huth /* saved limit is checked to calculate packet size by both, rom and netbsd */ 783f2a80c6eSThomas Huth next_state->dma[type].saved_limit = (next_state->dma[type].next + size); 784f2a80c6eSThomas Huth next_state->dma[type].saved_next = (next_state->dma[type].next); 785f2a80c6eSThomas Huth 786f2a80c6eSThomas Huth /* 787f2a80c6eSThomas Huth * 32 bytes under savedbase seems to be some kind of register 788f2a80c6eSThomas Huth * of which the purpose is unknown as of yet 789f2a80c6eSThomas Huth */ 790f2a80c6eSThomas Huth /* stl_phys(s->rx_dma.base-32,0xFFFFFFFF); */ 791f2a80c6eSThomas Huth 792f2a80c6eSThomas Huth if (!(next_state->dma[type].csr & DMA_SUPDATE)) { 793f2a80c6eSThomas Huth next_state->dma[type].next = next_state->dma[type].start; 794f2a80c6eSThomas Huth next_state->dma[type].limit = next_state->dma[type].stop; 795f2a80c6eSThomas Huth } 796f2a80c6eSThomas Huth 797f2a80c6eSThomas Huth /* Set dma registers and raise an irq */ 798f2a80c6eSThomas Huth next_state->dma[type].csr |= DMA_COMPLETE; /* DON'T CHANGE THIS! */ 799f2a80c6eSThomas Huth 800f2a80c6eSThomas Huth switch (type) { 801f2a80c6eSThomas Huth case NEXTDMA_SCSI: 802f2a80c6eSThomas Huth irq = NEXT_SCSI_DMA_I; 803f2a80c6eSThomas Huth break; 804f2a80c6eSThomas Huth } 805f2a80c6eSThomas Huth 806f2a80c6eSThomas Huth next_irq(opaque, irq, 1); 807f2a80c6eSThomas Huth next_irq(opaque, irq, 0); 808f2a80c6eSThomas Huth } 809f2a80c6eSThomas Huth 810f2a80c6eSThomas Huth static void nextscsi_read(void *opaque, uint8_t *buf, int len) 811f2a80c6eSThomas Huth { 812f2a80c6eSThomas Huth DPRINTF("SCSI READ: %x\n", len); 813f2a80c6eSThomas Huth abort(); 814f2a80c6eSThomas Huth } 815f2a80c6eSThomas Huth 816f2a80c6eSThomas Huth static void nextscsi_write(void *opaque, uint8_t *buf, int size) 817f2a80c6eSThomas Huth { 818f2a80c6eSThomas Huth DPRINTF("SCSI WRITE: %i\n", size); 819f2a80c6eSThomas Huth nextdma_write(opaque, buf, size, NEXTDMA_SCSI); 820f2a80c6eSThomas Huth } 821f2a80c6eSThomas Huth 822f2a80c6eSThomas Huth static void next_scsi_init(DeviceState *pcdev, M68kCPU *cpu) 823f2a80c6eSThomas Huth { 824f2a80c6eSThomas Huth struct NeXTPC *next_pc = NEXT_PC(pcdev); 825f2a80c6eSThomas Huth DeviceState *dev; 826f2a80c6eSThomas Huth SysBusDevice *sysbusdev; 827f2a80c6eSThomas Huth SysBusESPState *sysbus_esp; 828f2a80c6eSThomas Huth ESPState *esp; 829f2a80c6eSThomas Huth 830f2a80c6eSThomas Huth dev = qdev_new(TYPE_SYSBUS_ESP); 831f2a80c6eSThomas Huth sysbus_esp = SYSBUS_ESP(dev); 832f2a80c6eSThomas Huth esp = &sysbus_esp->esp; 833f2a80c6eSThomas Huth esp->dma_memory_read = nextscsi_read; 834f2a80c6eSThomas Huth esp->dma_memory_write = nextscsi_write; 835f2a80c6eSThomas Huth esp->dma_opaque = pcdev; 836f2a80c6eSThomas Huth sysbus_esp->it_shift = 0; 837f2a80c6eSThomas Huth esp->dma_enabled = 1; 838f2a80c6eSThomas Huth sysbusdev = SYS_BUS_DEVICE(dev); 839f2a80c6eSThomas Huth sysbus_realize_and_unref(sysbusdev, &error_fatal); 840f2a80c6eSThomas Huth sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(pcdev, NEXT_SCSI_I)); 841f2a80c6eSThomas Huth sysbus_mmio_map(sysbusdev, 0, 0x2114000); 842f2a80c6eSThomas Huth 843f2a80c6eSThomas Huth next_pc->scsi_reset = qdev_get_gpio_in(dev, 0); 844f2a80c6eSThomas Huth next_pc->scsi_dma = qdev_get_gpio_in(dev, 1); 845f2a80c6eSThomas Huth 846f2a80c6eSThomas Huth scsi_bus_legacy_handle_cmdline(&esp->bus); 847f2a80c6eSThomas Huth } 848f2a80c6eSThomas Huth 849b497f4a1SPeter Maydell static void next_escc_init(DeviceState *pcdev) 850b17bed5bSThomas Huth { 851b17bed5bSThomas Huth DeviceState *dev; 852b17bed5bSThomas Huth SysBusDevice *s; 853b17bed5bSThomas Huth 8543e80f690SMarkus Armbruster dev = qdev_new(TYPE_ESCC); 855b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "disabled", 0); 856b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "frequency", 9600 * 384); 857b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "it_shift", 0); 858b17bed5bSThomas Huth qdev_prop_set_bit(dev, "bit_swap", true); 859b17bed5bSThomas Huth qdev_prop_set_chr(dev, "chrB", serial_hd(1)); 860b17bed5bSThomas Huth qdev_prop_set_chr(dev, "chrA", serial_hd(0)); 861b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "chnBtype", escc_serial); 862b17bed5bSThomas Huth qdev_prop_set_uint32(dev, "chnAtype", escc_serial); 863b17bed5bSThomas Huth 864b17bed5bSThomas Huth s = SYS_BUS_DEVICE(dev); 8653c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal); 866d9cd4039SPeter Maydell sysbus_connect_irq(s, 0, qdev_get_gpio_in(pcdev, NEXT_SCC_I)); 867d9cd4039SPeter Maydell sysbus_connect_irq(s, 1, qdev_get_gpio_in(pcdev, NEXT_SCC_DMA_I)); 868b17bed5bSThomas Huth sysbus_mmio_map(s, 0, 0x2118000); 869b17bed5bSThomas Huth } 870b17bed5bSThomas Huth 871660bef33SPeter Maydell static void next_pc_reset(DeviceState *dev) 872660bef33SPeter Maydell { 87340831636SPeter Maydell NeXTPC *s = NEXT_PC(dev); 87440831636SPeter Maydell 87540831636SPeter Maydell /* Set internal registers to initial values */ 87640831636SPeter Maydell /* 0x0000XX00 << vital bits */ 87740831636SPeter Maydell s->scr1 = 0x00011102; 87840831636SPeter Maydell s->scr2 = 0x00ff0c80; 8796f0face7SPeter Maydell 8806f0face7SPeter Maydell s->rtc.status = 0x90; 8816f0face7SPeter Maydell 8826f0face7SPeter Maydell /* Load RTC RAM - TODO: provide possibility to load contents from file */ 8836f0face7SPeter Maydell memcpy(s->rtc.ram, rtc_ram2, 32); 884660bef33SPeter Maydell } 885660bef33SPeter Maydell 886660bef33SPeter Maydell static void next_pc_realize(DeviceState *dev, Error **errp) 887660bef33SPeter Maydell { 88840831636SPeter Maydell NeXTPC *s = NEXT_PC(dev); 88940831636SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 89040831636SPeter Maydell 891d9cd4039SPeter Maydell qdev_init_gpio_in(dev, next_irq, NEXT_NUM_IRQS); 892d9cd4039SPeter Maydell 8937e993d93SMark Cave-Ayland memory_region_init_io(&s->mmiomem, OBJECT(s), &next_mmio_ops, s, 8947e993d93SMark Cave-Ayland "next.mmio", 0xd0000); 8950d60da39SMark Cave-Ayland memory_region_init_io(&s->scrmem, OBJECT(s), &next_scr_ops, s, 8961dc7aeaeSPeter Maydell "next.scr", 0x20000); 89740831636SPeter Maydell sysbus_init_mmio(sbd, &s->mmiomem); 8981dc7aeaeSPeter Maydell sysbus_init_mmio(sbd, &s->scrmem); 899660bef33SPeter Maydell } 900660bef33SPeter Maydell 901b497f4a1SPeter Maydell /* 902b497f4a1SPeter Maydell * If the m68k CPU implemented its inbound irq lines as GPIO lines 903b497f4a1SPeter Maydell * rather than via the m68k_set_irq_level() function we would not need 904b497f4a1SPeter Maydell * this cpu link property and could instead provide outbound IRQ lines 905b497f4a1SPeter Maydell * that the board could wire up to the CPU. 906b497f4a1SPeter Maydell */ 907b497f4a1SPeter Maydell static Property next_pc_properties[] = { 908b497f4a1SPeter Maydell DEFINE_PROP_LINK("cpu", NeXTPC, cpu, TYPE_M68K_CPU, M68kCPU *), 909b497f4a1SPeter Maydell DEFINE_PROP_END_OF_LIST(), 910b497f4a1SPeter Maydell }; 911b497f4a1SPeter Maydell 91275ca77ecSPeter Maydell static const VMStateDescription next_rtc_vmstate = { 91375ca77ecSPeter Maydell .name = "next-rtc", 91475ca77ecSPeter Maydell .version_id = 1, 91575ca77ecSPeter Maydell .minimum_version_id = 1, 91675ca77ecSPeter Maydell .fields = (VMStateField[]) { 91775ca77ecSPeter Maydell VMSTATE_UINT8_ARRAY(ram, NextRtc, 32), 91875ca77ecSPeter Maydell VMSTATE_UINT8(command, NextRtc), 91975ca77ecSPeter Maydell VMSTATE_UINT8(value, NextRtc), 92075ca77ecSPeter Maydell VMSTATE_UINT8(status, NextRtc), 92175ca77ecSPeter Maydell VMSTATE_UINT8(control, NextRtc), 92275ca77ecSPeter Maydell VMSTATE_UINT8(retval, NextRtc), 92375ca77ecSPeter Maydell VMSTATE_END_OF_LIST() 92475ca77ecSPeter Maydell }, 92575ca77ecSPeter Maydell }; 92675ca77ecSPeter Maydell 92775ca77ecSPeter Maydell static const VMStateDescription next_pc_vmstate = { 92875ca77ecSPeter Maydell .name = "next-pc", 929*8220baa0SMark Cave-Ayland .version_id = 2, 930*8220baa0SMark Cave-Ayland .minimum_version_id = 2, 93175ca77ecSPeter Maydell .fields = (VMStateField[]) { 93275ca77ecSPeter Maydell VMSTATE_UINT32(scr1, NeXTPC), 93375ca77ecSPeter Maydell VMSTATE_UINT32(scr2, NeXTPC), 93475ca77ecSPeter Maydell VMSTATE_UINT32(int_mask, NeXTPC), 93575ca77ecSPeter Maydell VMSTATE_UINT32(int_status, NeXTPC), 936*8220baa0SMark Cave-Ayland VMSTATE_UINT32(led, NeXTPC), 93775ca77ecSPeter Maydell VMSTATE_UINT8(scsi_csr_1, NeXTPC), 93875ca77ecSPeter Maydell VMSTATE_UINT8(scsi_csr_2, NeXTPC), 93975ca77ecSPeter Maydell VMSTATE_STRUCT(rtc, NeXTPC, 0, next_rtc_vmstate, NextRtc), 94075ca77ecSPeter Maydell VMSTATE_END_OF_LIST() 94175ca77ecSPeter Maydell }, 94275ca77ecSPeter Maydell }; 94375ca77ecSPeter Maydell 944660bef33SPeter Maydell static void next_pc_class_init(ObjectClass *klass, void *data) 945660bef33SPeter Maydell { 946660bef33SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 947660bef33SPeter Maydell 948660bef33SPeter Maydell dc->desc = "NeXT Peripheral Controller"; 949660bef33SPeter Maydell dc->realize = next_pc_realize; 950660bef33SPeter Maydell dc->reset = next_pc_reset; 951b497f4a1SPeter Maydell device_class_set_props(dc, next_pc_properties); 95275ca77ecSPeter Maydell dc->vmsd = &next_pc_vmstate; 953660bef33SPeter Maydell } 954660bef33SPeter Maydell 955660bef33SPeter Maydell static const TypeInfo next_pc_info = { 956660bef33SPeter Maydell .name = TYPE_NEXT_PC, 957660bef33SPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 958660bef33SPeter Maydell .instance_size = sizeof(NeXTPC), 959660bef33SPeter Maydell .class_init = next_pc_class_init, 960660bef33SPeter Maydell }; 961660bef33SPeter Maydell 962956a7811SThomas Huth static void next_cube_init(MachineState *machine) 963956a7811SThomas Huth { 964956a7811SThomas Huth M68kCPU *cpu; 965956a7811SThomas Huth CPUM68KState *env; 966956a7811SThomas Huth MemoryRegion *rom = g_new(MemoryRegion, 1); 96787f4ba9eSThomas Huth MemoryRegion *rom2 = g_new(MemoryRegion, 1); 968956a7811SThomas Huth MemoryRegion *dmamem = g_new(MemoryRegion, 1); 969956a7811SThomas Huth MemoryRegion *bmapm1 = g_new(MemoryRegion, 1); 970956a7811SThomas Huth MemoryRegion *bmapm2 = g_new(MemoryRegion, 1); 971956a7811SThomas Huth MemoryRegion *sysmem = get_system_memory(); 9721684273cSPaolo Bonzini const char *bios_name = machine->firmware ?: ROM_FILE; 973660bef33SPeter Maydell DeviceState *pcdev; 974956a7811SThomas Huth 975956a7811SThomas Huth /* Initialize the cpu core */ 976956a7811SThomas Huth cpu = M68K_CPU(cpu_create(machine->cpu_type)); 977956a7811SThomas Huth if (!cpu) { 978956a7811SThomas Huth error_report("Unable to find m68k CPU definition"); 979956a7811SThomas Huth exit(1); 980956a7811SThomas Huth } 981956a7811SThomas Huth env = &cpu->env; 982956a7811SThomas Huth 983956a7811SThomas Huth /* Initialize CPU registers. */ 984956a7811SThomas Huth env->vbr = 0; 985956a7811SThomas Huth env->sr = 0x2700; 986956a7811SThomas Huth 987660bef33SPeter Maydell /* Peripheral Controller */ 988660bef33SPeter Maydell pcdev = qdev_new(TYPE_NEXT_PC); 989b497f4a1SPeter Maydell object_property_set_link(OBJECT(pcdev), "cpu", OBJECT(cpu), &error_abort); 990660bef33SPeter Maydell sysbus_realize_and_unref(SYS_BUS_DEVICE(pcdev), &error_fatal); 991956a7811SThomas Huth 992956a7811SThomas Huth /* 64MB RAM starting at 0x04000000 */ 99349b64ba9SIgor Mammedov memory_region_add_subregion(sysmem, 0x04000000, machine->ram); 994956a7811SThomas Huth 995956a7811SThomas Huth /* Framebuffer */ 996b2897f7eSPhilippe Mathieu-Daudé sysbus_create_simple(TYPE_NEXTFB, 0x0B000000, NULL); 997956a7811SThomas Huth 998956a7811SThomas Huth /* MMIO */ 99940831636SPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000); 1000956a7811SThomas Huth 10011dc7aeaeSPeter Maydell /* BMAP IO - acts as a catch-all for now */ 10021dc7aeaeSPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000); 10031dc7aeaeSPeter Maydell 1004956a7811SThomas Huth /* BMAP memory */ 10057f863cbaSDavid Hildenbrand memory_region_init_ram_flags_nomigrate(bmapm1, NULL, "next.bmapmem", 64, 10067f863cbaSDavid Hildenbrand RAM_SHARED, &error_fatal); 1007956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x020c0000, bmapm1); 1008956a7811SThomas Huth /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */ 1009956a7811SThomas Huth memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64); 1010956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x820c0000, bmapm2); 1011956a7811SThomas Huth 1012956a7811SThomas Huth /* KBD */ 1013b2897f7eSPhilippe Mathieu-Daudé sysbus_create_simple(TYPE_NEXTKBD, 0x0200e000, NULL); 1014956a7811SThomas Huth 1015956a7811SThomas Huth /* Load ROM here */ 1016956a7811SThomas Huth memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal); 1017956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x01000000, rom); 101887f4ba9eSThomas Huth memory_region_init_alias(rom2, NULL, "next.rom2", rom, 0x0, 0x20000); 101987f4ba9eSThomas Huth memory_region_add_subregion(sysmem, 0x0, rom2); 1020956a7811SThomas Huth if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) { 1021956a7811SThomas Huth if (!qtest_enabled()) { 1022956a7811SThomas Huth error_report("Failed to load firmware '%s'.", bios_name); 1023956a7811SThomas Huth } 1024956a7811SThomas Huth } else { 1025956a7811SThomas Huth uint8_t *ptr; 1026956a7811SThomas Huth /* Initial PC is always at offset 4 in firmware binaries */ 1027956a7811SThomas Huth ptr = rom_ptr(0x01000004, 4); 1028956a7811SThomas Huth g_assert(ptr != NULL); 1029956a7811SThomas Huth env->pc = ldl_p(ptr); 1030956a7811SThomas Huth if (env->pc >= 0x01020000) { 1031956a7811SThomas Huth error_report("'%s' does not seem to be a valid firmware image.", 1032956a7811SThomas Huth bios_name); 1033956a7811SThomas Huth exit(1); 1034956a7811SThomas Huth } 1035956a7811SThomas Huth } 1036956a7811SThomas Huth 1037956a7811SThomas Huth /* Serial */ 1038b497f4a1SPeter Maydell next_escc_init(pcdev); 1039b17bed5bSThomas Huth 1040b17bed5bSThomas Huth /* TODO: */ 1041956a7811SThomas Huth /* Network */ 1042956a7811SThomas Huth /* SCSI */ 1043f2a80c6eSThomas Huth next_scsi_init(pcdev, cpu); 1044956a7811SThomas Huth 1045956a7811SThomas Huth /* DMA */ 1046c0dedcf4SMark Cave-Ayland memory_region_init_io(dmamem, NULL, &next_dma_ops, machine, "next.dma", 1047c0dedcf4SMark Cave-Ayland 0x5000); 1048956a7811SThomas Huth memory_region_add_subregion(sysmem, 0x02000000, dmamem); 1049956a7811SThomas Huth } 1050956a7811SThomas Huth 1051956a7811SThomas Huth static void next_machine_class_init(ObjectClass *oc, void *data) 1052956a7811SThomas Huth { 1053956a7811SThomas Huth MachineClass *mc = MACHINE_CLASS(oc); 1054956a7811SThomas Huth 1055956a7811SThomas Huth mc->desc = "NeXT Cube"; 1056956a7811SThomas Huth mc->init = next_cube_init; 1057f2a80c6eSThomas Huth mc->block_default_type = IF_SCSI; 1058956a7811SThomas Huth mc->default_ram_size = RAM_SIZE; 105949b64ba9SIgor Mammedov mc->default_ram_id = "next.ram"; 1060956a7811SThomas Huth mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); 1061956a7811SThomas Huth } 1062956a7811SThomas Huth 1063956a7811SThomas Huth static const TypeInfo next_typeinfo = { 1064956a7811SThomas Huth .name = TYPE_NEXT_MACHINE, 1065956a7811SThomas Huth .parent = TYPE_MACHINE, 1066956a7811SThomas Huth .class_init = next_machine_class_init, 1067956a7811SThomas Huth .instance_size = sizeof(NeXTState), 1068956a7811SThomas Huth }; 1069956a7811SThomas Huth 1070956a7811SThomas Huth static void next_register_type(void) 1071956a7811SThomas Huth { 1072956a7811SThomas Huth type_register_static(&next_typeinfo); 1073660bef33SPeter Maydell type_register_static(&next_pc_info); 1074956a7811SThomas Huth } 1075956a7811SThomas Huth 1076956a7811SThomas Huth type_init(next_register_type) 1077