xref: /qemu/hw/m68k/next-cube.c (revision c0dedcf4)
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;
95f2a80c6eSThomas Huth     uint8_t scsi_csr_1;
96f2a80c6eSThomas Huth     uint8_t scsi_csr_2;
97f2a80c6eSThomas Huth 
98f2a80c6eSThomas Huth     qemu_irq scsi_reset;
99f2a80c6eSThomas Huth     qemu_irq scsi_dma;
1006f0face7SPeter Maydell 
1016f0face7SPeter Maydell     NextRtc rtc;
102660bef33SPeter Maydell };
103660bef33SPeter Maydell 
104956a7811SThomas Huth /* Thanks to NeXT forums for this */
105956a7811SThomas Huth /*
106956a7811SThomas Huth static const uint8_t rtc_ram3[32] = {
107956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
108956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00,
109956a7811SThomas Huth     0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00,
110956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13
111956a7811SThomas Huth };
112956a7811SThomas Huth */
113956a7811SThomas Huth static const uint8_t rtc_ram2[32] = {
114956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00,
115956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00,
116956a7811SThomas Huth     0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
117956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e,
118956a7811SThomas Huth };
119956a7811SThomas Huth 
120956a7811SThomas Huth #define SCR2_RTCLK 0x2
121956a7811SThomas Huth #define SCR2_RTDATA 0x4
122956a7811SThomas Huth #define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10))
123956a7811SThomas Huth 
12440831636SPeter Maydell static void nextscr2_write(NeXTPC *s, uint32_t val, int size)
125956a7811SThomas Huth {
126956a7811SThomas Huth     static int led;
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");
140956a7811SThomas Huth         led++;
141956a7811SThomas Huth         if (led == 10) {
142956a7811SThomas Huth             DPRINTF("LED flashing, possible fault!\n");
143956a7811SThomas Huth             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 
494*c0dedcf4SMark 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):
501*c0dedcf4SMark Cave-Ayland         if (val & DMA_DEV2M) {
502956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M;
503956a7811SThomas Huth         }
504956a7811SThomas Huth 
505*c0dedcf4SMark 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         }
509*c0dedcf4SMark Cave-Ayland         if (val & DMA_SETSUPDATE) {
510956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE;
511956a7811SThomas Huth         }
512*c0dedcf4SMark Cave-Ayland         if (val & DMA_CLRCOMPLETE) {
513956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE;
514956a7811SThomas Huth         }
515956a7811SThomas Huth 
516*c0dedcf4SMark 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;
522*c0dedcf4SMark Cave-Ayland 
523956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
524*c0dedcf4SMark Cave-Ayland         next_state->dma[NEXTDMA_ENRX].next_initbuf = val;
525956a7811SThomas Huth         break;
526*c0dedcf4SMark Cave-Ayland 
527956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
528*c0dedcf4SMark Cave-Ayland         next_state->dma[NEXTDMA_ENRX].next = val;
529956a7811SThomas Huth         break;
530*c0dedcf4SMark Cave-Ayland 
531956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
532*c0dedcf4SMark Cave-Ayland         next_state->dma[NEXTDMA_ENRX].limit = val;
533956a7811SThomas Huth         break;
534*c0dedcf4SMark Cave-Ayland 
535956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_CSR):
536*c0dedcf4SMark Cave-Ayland         if (val & DMA_DEV2M) {
537956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M;
538956a7811SThomas Huth         }
539*c0dedcf4SMark 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         }
543*c0dedcf4SMark Cave-Ayland         if (val & DMA_SETSUPDATE) {
544956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE;
545956a7811SThomas Huth         }
546*c0dedcf4SMark Cave-Ayland         if (val & DMA_CLRCOMPLETE) {
547956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE;
548956a7811SThomas Huth         }
549956a7811SThomas Huth 
550*c0dedcf4SMark 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):
559*c0dedcf4SMark Cave-Ayland         next_state->dma[NEXTDMA_SCSI].next = val;
560956a7811SThomas Huth         break;
561956a7811SThomas Huth 
562956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
563*c0dedcf4SMark Cave-Ayland         next_state->dma[NEXTDMA_SCSI].limit = val;
564956a7811SThomas Huth         break;
565956a7811SThomas Huth 
566956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
567*c0dedcf4SMark Cave-Ayland         next_state->dma[NEXTDMA_SCSI].start = val;
568956a7811SThomas Huth         break;
569956a7811SThomas Huth 
570956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
571*c0dedcf4SMark Cave-Ayland         next_state->dma[NEXTDMA_SCSI].stop = val;
572956a7811SThomas Huth         break;
573956a7811SThomas Huth 
574956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
575*c0dedcf4SMark 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 
583*c0dedcf4SMark 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);
586*c0dedcf4SMark 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");
591*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_SCSI].csr;
592*c0dedcf4SMark Cave-Ayland         break;
593*c0dedcf4SMark Cave-Ayland 
594956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_CSR):
595*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_ENRX].csr;
596*c0dedcf4SMark Cave-Ayland         break;
597*c0dedcf4SMark Cave-Ayland 
598956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
599*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_ENRX].next_initbuf;
600*c0dedcf4SMark Cave-Ayland         break;
601*c0dedcf4SMark Cave-Ayland 
602956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
603*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_ENRX].next;
604*c0dedcf4SMark Cave-Ayland         break;
605*c0dedcf4SMark Cave-Ayland 
606956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
607*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_ENRX].limit;
608*c0dedcf4SMark Cave-Ayland         break;
609956a7811SThomas Huth 
610956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT):
611*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_SCSI].next;
612*c0dedcf4SMark Cave-Ayland         break;
613*c0dedcf4SMark Cave-Ayland 
614956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
615*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_SCSI].next_initbuf;
616*c0dedcf4SMark Cave-Ayland         break;
617*c0dedcf4SMark Cave-Ayland 
618956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
619*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_SCSI].limit;
620*c0dedcf4SMark Cave-Ayland         break;
621*c0dedcf4SMark Cave-Ayland 
622956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
623*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_SCSI].start;
624*c0dedcf4SMark Cave-Ayland         break;
625*c0dedcf4SMark Cave-Ayland 
626956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
627*c0dedcf4SMark Cave-Ayland         val = next_state->dma[NEXTDMA_SCSI].stop;
628*c0dedcf4SMark Cave-Ayland         break;
629956a7811SThomas Huth 
630956a7811SThomas Huth     default:
631956a7811SThomas Huth         DPRINTF("DMA read @ %x\n", (unsigned int)addr);
632*c0dedcf4SMark 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      */
639*c0dedcf4SMark Cave-Ayland 
640*c0dedcf4SMark Cave-Ayland     return val;
641956a7811SThomas Huth }
642956a7811SThomas Huth 
643*c0dedcf4SMark Cave-Ayland static const MemoryRegionOps next_dma_ops = {
644*c0dedcf4SMark Cave-Ayland     .read = next_dma_read,
645*c0dedcf4SMark 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,
649*c0dedcf4SMark 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",
92975ca77ecSPeter Maydell     .version_id = 1,
93075ca77ecSPeter Maydell     .minimum_version_id = 1,
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),
93675ca77ecSPeter Maydell         VMSTATE_UINT8(scsi_csr_1, NeXTPC),
93775ca77ecSPeter Maydell         VMSTATE_UINT8(scsi_csr_2, NeXTPC),
93875ca77ecSPeter Maydell         VMSTATE_STRUCT(rtc, NeXTPC, 0, next_rtc_vmstate, NextRtc),
93975ca77ecSPeter Maydell         VMSTATE_END_OF_LIST()
94075ca77ecSPeter Maydell     },
94175ca77ecSPeter Maydell };
94275ca77ecSPeter Maydell 
943660bef33SPeter Maydell static void next_pc_class_init(ObjectClass *klass, void *data)
944660bef33SPeter Maydell {
945660bef33SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
946660bef33SPeter Maydell 
947660bef33SPeter Maydell     dc->desc = "NeXT Peripheral Controller";
948660bef33SPeter Maydell     dc->realize = next_pc_realize;
949660bef33SPeter Maydell     dc->reset = next_pc_reset;
950b497f4a1SPeter Maydell     device_class_set_props(dc, next_pc_properties);
95175ca77ecSPeter Maydell     dc->vmsd = &next_pc_vmstate;
952660bef33SPeter Maydell }
953660bef33SPeter Maydell 
954660bef33SPeter Maydell static const TypeInfo next_pc_info = {
955660bef33SPeter Maydell     .name = TYPE_NEXT_PC,
956660bef33SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
957660bef33SPeter Maydell     .instance_size = sizeof(NeXTPC),
958660bef33SPeter Maydell     .class_init = next_pc_class_init,
959660bef33SPeter Maydell };
960660bef33SPeter Maydell 
961956a7811SThomas Huth static void next_cube_init(MachineState *machine)
962956a7811SThomas Huth {
963956a7811SThomas Huth     M68kCPU *cpu;
964956a7811SThomas Huth     CPUM68KState *env;
965956a7811SThomas Huth     MemoryRegion *rom = g_new(MemoryRegion, 1);
96687f4ba9eSThomas Huth     MemoryRegion *rom2 = g_new(MemoryRegion, 1);
967956a7811SThomas Huth     MemoryRegion *dmamem = g_new(MemoryRegion, 1);
968956a7811SThomas Huth     MemoryRegion *bmapm1 = g_new(MemoryRegion, 1);
969956a7811SThomas Huth     MemoryRegion *bmapm2 = g_new(MemoryRegion, 1);
970956a7811SThomas Huth     MemoryRegion *sysmem = get_system_memory();
9711684273cSPaolo Bonzini     const char *bios_name = machine->firmware ?: ROM_FILE;
972660bef33SPeter Maydell     DeviceState *pcdev;
973956a7811SThomas Huth 
974956a7811SThomas Huth     /* Initialize the cpu core */
975956a7811SThomas Huth     cpu = M68K_CPU(cpu_create(machine->cpu_type));
976956a7811SThomas Huth     if (!cpu) {
977956a7811SThomas Huth         error_report("Unable to find m68k CPU definition");
978956a7811SThomas Huth         exit(1);
979956a7811SThomas Huth     }
980956a7811SThomas Huth     env = &cpu->env;
981956a7811SThomas Huth 
982956a7811SThomas Huth     /* Initialize CPU registers.  */
983956a7811SThomas Huth     env->vbr = 0;
984956a7811SThomas Huth     env->sr  = 0x2700;
985956a7811SThomas Huth 
986660bef33SPeter Maydell     /* Peripheral Controller */
987660bef33SPeter Maydell     pcdev = qdev_new(TYPE_NEXT_PC);
988b497f4a1SPeter Maydell     object_property_set_link(OBJECT(pcdev), "cpu", OBJECT(cpu), &error_abort);
989660bef33SPeter Maydell     sysbus_realize_and_unref(SYS_BUS_DEVICE(pcdev), &error_fatal);
990956a7811SThomas Huth 
991956a7811SThomas Huth     /* 64MB RAM starting at 0x04000000  */
99249b64ba9SIgor Mammedov     memory_region_add_subregion(sysmem, 0x04000000, machine->ram);
993956a7811SThomas Huth 
994956a7811SThomas Huth     /* Framebuffer */
995b2897f7eSPhilippe Mathieu-Daudé     sysbus_create_simple(TYPE_NEXTFB, 0x0B000000, NULL);
996956a7811SThomas Huth 
997956a7811SThomas Huth     /* MMIO */
99840831636SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000);
999956a7811SThomas Huth 
10001dc7aeaeSPeter Maydell     /* BMAP IO - acts as a catch-all for now */
10011dc7aeaeSPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000);
10021dc7aeaeSPeter Maydell 
1003956a7811SThomas Huth     /* BMAP memory */
10047f863cbaSDavid Hildenbrand     memory_region_init_ram_flags_nomigrate(bmapm1, NULL, "next.bmapmem", 64,
10057f863cbaSDavid Hildenbrand                                            RAM_SHARED, &error_fatal);
1006956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x020c0000, bmapm1);
1007956a7811SThomas Huth     /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */
1008956a7811SThomas Huth     memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64);
1009956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x820c0000, bmapm2);
1010956a7811SThomas Huth 
1011956a7811SThomas Huth     /* KBD */
1012b2897f7eSPhilippe Mathieu-Daudé     sysbus_create_simple(TYPE_NEXTKBD, 0x0200e000, NULL);
1013956a7811SThomas Huth 
1014956a7811SThomas Huth     /* Load ROM here */
1015956a7811SThomas Huth     memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal);
1016956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x01000000, rom);
101787f4ba9eSThomas Huth     memory_region_init_alias(rom2, NULL, "next.rom2", rom, 0x0, 0x20000);
101887f4ba9eSThomas Huth     memory_region_add_subregion(sysmem, 0x0, rom2);
1019956a7811SThomas Huth     if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) {
1020956a7811SThomas Huth         if (!qtest_enabled()) {
1021956a7811SThomas Huth             error_report("Failed to load firmware '%s'.", bios_name);
1022956a7811SThomas Huth         }
1023956a7811SThomas Huth     } else {
1024956a7811SThomas Huth         uint8_t *ptr;
1025956a7811SThomas Huth         /* Initial PC is always at offset 4 in firmware binaries */
1026956a7811SThomas Huth         ptr = rom_ptr(0x01000004, 4);
1027956a7811SThomas Huth         g_assert(ptr != NULL);
1028956a7811SThomas Huth         env->pc = ldl_p(ptr);
1029956a7811SThomas Huth         if (env->pc >= 0x01020000) {
1030956a7811SThomas Huth             error_report("'%s' does not seem to be a valid firmware image.",
1031956a7811SThomas Huth                          bios_name);
1032956a7811SThomas Huth             exit(1);
1033956a7811SThomas Huth         }
1034956a7811SThomas Huth     }
1035956a7811SThomas Huth 
1036956a7811SThomas Huth     /* Serial */
1037b497f4a1SPeter Maydell     next_escc_init(pcdev);
1038b17bed5bSThomas Huth 
1039b17bed5bSThomas Huth     /* TODO: */
1040956a7811SThomas Huth     /* Network */
1041956a7811SThomas Huth     /* SCSI */
1042f2a80c6eSThomas Huth     next_scsi_init(pcdev, cpu);
1043956a7811SThomas Huth 
1044956a7811SThomas Huth     /* DMA */
1045*c0dedcf4SMark Cave-Ayland     memory_region_init_io(dmamem, NULL, &next_dma_ops, machine, "next.dma",
1046*c0dedcf4SMark Cave-Ayland                           0x5000);
1047956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x02000000, dmamem);
1048956a7811SThomas Huth }
1049956a7811SThomas Huth 
1050956a7811SThomas Huth static void next_machine_class_init(ObjectClass *oc, void *data)
1051956a7811SThomas Huth {
1052956a7811SThomas Huth     MachineClass *mc = MACHINE_CLASS(oc);
1053956a7811SThomas Huth 
1054956a7811SThomas Huth     mc->desc = "NeXT Cube";
1055956a7811SThomas Huth     mc->init = next_cube_init;
1056f2a80c6eSThomas Huth     mc->block_default_type = IF_SCSI;
1057956a7811SThomas Huth     mc->default_ram_size = RAM_SIZE;
105849b64ba9SIgor Mammedov     mc->default_ram_id = "next.ram";
1059956a7811SThomas Huth     mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
1060956a7811SThomas Huth }
1061956a7811SThomas Huth 
1062956a7811SThomas Huth static const TypeInfo next_typeinfo = {
1063956a7811SThomas Huth     .name = TYPE_NEXT_MACHINE,
1064956a7811SThomas Huth     .parent = TYPE_MACHINE,
1065956a7811SThomas Huth     .class_init = next_machine_class_init,
1066956a7811SThomas Huth     .instance_size = sizeof(NeXTState),
1067956a7811SThomas Huth };
1068956a7811SThomas Huth 
1069956a7811SThomas Huth static void next_register_type(void)
1070956a7811SThomas Huth {
1071956a7811SThomas Huth     type_register_static(&next_typeinfo);
1072660bef33SPeter Maydell     type_register_static(&next_pc_info);
1073956a7811SThomas Huth }
1074956a7811SThomas Huth 
1075956a7811SThomas Huth type_init(next_register_type)
1076