xref: /qemu/hw/m68k/next-cube.c (revision 75ca77ec)
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"
13b17bed5bSThomas Huth #include "cpu.h"
14956a7811SThomas Huth #include "exec/hwaddr.h"
15956a7811SThomas Huth #include "exec/address-spaces.h"
16956a7811SThomas Huth #include "sysemu/sysemu.h"
17956a7811SThomas Huth #include "sysemu/qtest.h"
18b17bed5bSThomas Huth #include "hw/irq.h"
19956a7811SThomas Huth #include "hw/m68k/next-cube.h"
20956a7811SThomas Huth #include "hw/boards.h"
21956a7811SThomas Huth #include "hw/loader.h"
22956a7811SThomas Huth #include "hw/scsi/esp.h"
23956a7811SThomas Huth #include "hw/sysbus.h"
24db1015e9SEduardo Habkost #include "qom/object.h"
25956a7811SThomas Huth #include "hw/char/escc.h" /* ZILOG 8530 Serial Emulation */
26956a7811SThomas Huth #include "hw/block/fdc.h"
27b17bed5bSThomas Huth #include "hw/qdev-properties.h"
28956a7811SThomas Huth #include "qapi/error.h"
29956a7811SThomas Huth #include "ui/console.h"
30956a7811SThomas Huth #include "target/m68k/cpu.h"
31*75ca77ecSPeter Maydell #include "migration/vmstate.h"
32956a7811SThomas Huth 
33956a7811SThomas Huth /* #define DEBUG_NEXT */
34956a7811SThomas Huth #ifdef DEBUG_NEXT
35956a7811SThomas Huth #define DPRINTF(fmt, ...) \
36956a7811SThomas Huth     do { printf("NeXT: " fmt , ## __VA_ARGS__); } while (0)
37956a7811SThomas Huth #else
38956a7811SThomas Huth #define DPRINTF(fmt, ...) do { } while (0)
39956a7811SThomas Huth #endif
40956a7811SThomas Huth 
41956a7811SThomas Huth #define TYPE_NEXT_MACHINE MACHINE_TYPE_NAME("next-cube")
428063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(NeXTState, NEXT_MACHINE)
43956a7811SThomas Huth 
44956a7811SThomas Huth #define ENTRY       0x0100001e
45956a7811SThomas Huth #define RAM_SIZE    0x4000000
46956a7811SThomas Huth #define ROM_FILE    "Rev_2.5_v66.bin"
47956a7811SThomas Huth 
48956a7811SThomas Huth typedef struct next_dma {
49956a7811SThomas Huth     uint32_t csr;
50956a7811SThomas Huth 
51956a7811SThomas Huth     uint32_t saved_next;
52956a7811SThomas Huth     uint32_t saved_limit;
53956a7811SThomas Huth     uint32_t saved_start;
54956a7811SThomas Huth     uint32_t saved_stop;
55956a7811SThomas Huth 
56956a7811SThomas Huth     uint32_t next;
57956a7811SThomas Huth     uint32_t limit;
58956a7811SThomas Huth     uint32_t start;
59956a7811SThomas Huth     uint32_t stop;
60956a7811SThomas Huth 
61956a7811SThomas Huth     uint32_t next_initbuf;
62956a7811SThomas Huth     uint32_t size;
63956a7811SThomas Huth } next_dma;
64956a7811SThomas Huth 
65cd4fc142SThomas Huth typedef struct NextRtc {
66cd4fc142SThomas Huth     uint8_t ram[32];
67cd4fc142SThomas Huth     uint8_t command;
68cd4fc142SThomas Huth     uint8_t value;
69cd4fc142SThomas Huth     uint8_t status;
70cd4fc142SThomas Huth     uint8_t control;
71cd4fc142SThomas Huth     uint8_t retval;
72cd4fc142SThomas Huth } NextRtc;
73cd4fc142SThomas Huth 
74db1015e9SEduardo Habkost struct NeXTState {
75956a7811SThomas Huth     MachineState parent;
76956a7811SThomas Huth 
77956a7811SThomas Huth     next_dma dma[10];
78db1015e9SEduardo Habkost };
79956a7811SThomas Huth 
80660bef33SPeter Maydell #define TYPE_NEXT_PC "next-pc"
81660bef33SPeter Maydell OBJECT_DECLARE_SIMPLE_TYPE(NeXTPC, NEXT_PC)
82660bef33SPeter Maydell 
83660bef33SPeter Maydell /* NeXT Peripheral Controller */
84660bef33SPeter Maydell struct NeXTPC {
85660bef33SPeter Maydell     SysBusDevice parent_obj;
86660bef33SPeter Maydell 
87b497f4a1SPeter Maydell     M68kCPU *cpu;
88b497f4a1SPeter Maydell 
8940831636SPeter Maydell     MemoryRegion mmiomem;
901dc7aeaeSPeter Maydell     MemoryRegion scrmem;
9140831636SPeter Maydell 
9240831636SPeter Maydell     uint32_t scr1;
9340831636SPeter Maydell     uint32_t scr2;
941dc7aeaeSPeter Maydell     uint8_t scsi_csr_1;
951dc7aeaeSPeter Maydell     uint8_t scsi_csr_2;
96ac99317bSPeter Maydell     uint32_t int_mask;
97ac99317bSPeter Maydell     uint32_t int_status;
986f0face7SPeter Maydell 
996f0face7SPeter Maydell     NextRtc rtc;
100660bef33SPeter Maydell };
101660bef33SPeter Maydell 
102956a7811SThomas Huth /* Thanks to NeXT forums for this */
103956a7811SThomas Huth /*
104956a7811SThomas Huth static const uint8_t rtc_ram3[32] = {
105956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
106956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00,
107956a7811SThomas Huth     0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00,
108956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13
109956a7811SThomas Huth };
110956a7811SThomas Huth */
111956a7811SThomas Huth static const uint8_t rtc_ram2[32] = {
112956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00,
113956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00,
114956a7811SThomas Huth     0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
115956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e,
116956a7811SThomas Huth };
117956a7811SThomas Huth 
118956a7811SThomas Huth #define SCR2_RTCLK 0x2
119956a7811SThomas Huth #define SCR2_RTDATA 0x4
120956a7811SThomas Huth #define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10))
121956a7811SThomas Huth 
12240831636SPeter Maydell static void nextscr2_write(NeXTPC *s, uint32_t val, int size)
123956a7811SThomas Huth {
124956a7811SThomas Huth     static int led;
125956a7811SThomas Huth     static int phase;
126956a7811SThomas Huth     static uint8_t old_scr2;
127956a7811SThomas Huth     uint8_t scr2_2;
1286f0face7SPeter Maydell     NextRtc *rtc = &s->rtc;
129956a7811SThomas Huth 
130956a7811SThomas Huth     if (size == 4) {
131956a7811SThomas Huth         scr2_2 = (val >> 8) & 0xFF;
132956a7811SThomas Huth     } else {
133956a7811SThomas Huth         scr2_2 = val & 0xFF;
134956a7811SThomas Huth     }
135956a7811SThomas Huth 
136956a7811SThomas Huth     if (val & 0x1) {
137956a7811SThomas Huth         DPRINTF("fault!\n");
138956a7811SThomas Huth         led++;
139956a7811SThomas Huth         if (led == 10) {
140956a7811SThomas Huth             DPRINTF("LED flashing, possible fault!\n");
141956a7811SThomas Huth             led = 0;
142956a7811SThomas Huth         }
143956a7811SThomas Huth     }
144956a7811SThomas Huth 
145956a7811SThomas Huth     if (scr2_2 & 0x1) {
146956a7811SThomas Huth         /* DPRINTF("RTC %x phase %i\n", scr2_2, phase); */
147956a7811SThomas Huth         if (phase == -1) {
148956a7811SThomas Huth             phase = 0;
149956a7811SThomas Huth         }
150956a7811SThomas Huth         /* If we are in going down clock... do something */
151956a7811SThomas Huth         if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) &&
152956a7811SThomas Huth                 ((scr2_2 & SCR2_RTCLK) == 0)) {
153956a7811SThomas Huth             if (phase < 8) {
154cd4fc142SThomas Huth                 rtc->command = (rtc->command << 1) |
155956a7811SThomas Huth                                ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
156956a7811SThomas Huth             }
157956a7811SThomas Huth             if (phase >= 8 && phase < 16) {
158cd4fc142SThomas Huth                 rtc->value = (rtc->value << 1) |
159cd4fc142SThomas Huth                              ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
160956a7811SThomas Huth 
161956a7811SThomas Huth                 /* if we read RAM register, output RT_DATA bit */
162cd4fc142SThomas Huth                 if (rtc->command <= 0x1F) {
163956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
164cd4fc142SThomas Huth                     if (rtc->ram[rtc->command] & (0x80 >> (phase - 8))) {
165956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
166956a7811SThomas Huth                     }
167956a7811SThomas Huth 
168cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
169956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
170956a7811SThomas Huth                 }
171956a7811SThomas Huth                 /* read the status 0x30 */
172cd4fc142SThomas Huth                 if (rtc->command == 0x30) {
173956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
174956a7811SThomas Huth                     /* for now status = 0x98 (new rtc + FTU) */
175cd4fc142SThomas Huth                     if (rtc->status & (0x80 >> (phase - 8))) {
176956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
177956a7811SThomas Huth                     }
178956a7811SThomas Huth 
179cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
180956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
181956a7811SThomas Huth                 }
182956a7811SThomas Huth                 /* read the status 0x31 */
183cd4fc142SThomas Huth                 if (rtc->command == 0x31) {
184956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
185cd4fc142SThomas Huth                     if (rtc->control & (0x80 >> (phase - 8))) {
186956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
187956a7811SThomas Huth                     }
188cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
189956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
190956a7811SThomas Huth                 }
191956a7811SThomas Huth 
192cd4fc142SThomas Huth                 if ((rtc->command >= 0x20) && (rtc->command <= 0x2F)) {
193956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
194956a7811SThomas Huth                     /* for now 0x00 */
195956a7811SThomas Huth                     time_t time_h = time(NULL);
196956a7811SThomas Huth                     struct tm *info = localtime(&time_h);
197956a7811SThomas Huth                     int ret = 0;
198956a7811SThomas Huth 
199cd4fc142SThomas Huth                     switch (rtc->command) {
200956a7811SThomas Huth                     case 0x20:
201956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_sec);
202956a7811SThomas Huth                         break;
203956a7811SThomas Huth                     case 0x21:
204956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_min);
205956a7811SThomas Huth                         break;
206956a7811SThomas Huth                     case 0x22:
207956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_hour);
208956a7811SThomas Huth                         break;
209956a7811SThomas Huth                     case 0x24:
210956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_mday);
211956a7811SThomas Huth                         break;
212956a7811SThomas Huth                     case 0x25:
213956a7811SThomas Huth                         ret = SCR2_TOBCD((info->tm_mon + 1));
214956a7811SThomas Huth                         break;
215956a7811SThomas Huth                     case 0x26:
216956a7811SThomas Huth                         ret = SCR2_TOBCD((info->tm_year - 100));
217956a7811SThomas Huth                         break;
218956a7811SThomas Huth 
219956a7811SThomas Huth                     }
220956a7811SThomas Huth 
221956a7811SThomas Huth                     if (ret & (0x80 >> (phase - 8))) {
222956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
223956a7811SThomas Huth                     }
224cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
225956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
226956a7811SThomas Huth                 }
227956a7811SThomas Huth 
228956a7811SThomas Huth             }
229956a7811SThomas Huth 
230956a7811SThomas Huth             phase++;
231956a7811SThomas Huth             if (phase == 16) {
232cd4fc142SThomas Huth                 if (rtc->command >= 0x80 && rtc->command <= 0x9F) {
233cd4fc142SThomas Huth                     rtc->ram[rtc->command - 0x80] = rtc->value;
234956a7811SThomas Huth                 }
235956a7811SThomas Huth                 /* write to x30 register */
236cd4fc142SThomas Huth                 if (rtc->command == 0xB1) {
237956a7811SThomas Huth                     /* clear FTU */
238cd4fc142SThomas Huth                     if (rtc->value & 0x04) {
239cd4fc142SThomas Huth                         rtc->status = rtc->status & (~0x18);
240ac99317bSPeter Maydell                         s->int_status = s->int_status & (~0x04);
241956a7811SThomas Huth                     }
242956a7811SThomas Huth                 }
243956a7811SThomas Huth             }
244956a7811SThomas Huth         }
245956a7811SThomas Huth     } else {
246956a7811SThomas Huth         /* else end or abort */
247956a7811SThomas Huth         phase = -1;
248cd4fc142SThomas Huth         rtc->command = 0;
249cd4fc142SThomas Huth         rtc->value = 0;
250956a7811SThomas Huth     }
251956a7811SThomas Huth     s->scr2 = val & 0xFFFF00FF;
252956a7811SThomas Huth     s->scr2 |= scr2_2 << 8;
253956a7811SThomas Huth     old_scr2 = scr2_2;
254956a7811SThomas Huth }
255956a7811SThomas Huth 
25640831636SPeter Maydell static uint32_t mmio_readb(NeXTPC *s, hwaddr addr)
257956a7811SThomas Huth {
258956a7811SThomas Huth     switch (addr) {
259956a7811SThomas Huth     case 0xc000:
260956a7811SThomas Huth         return (s->scr1 >> 24) & 0xFF;
261956a7811SThomas Huth     case 0xc001:
262956a7811SThomas Huth         return (s->scr1 >> 16) & 0xFF;
263956a7811SThomas Huth     case 0xc002:
264956a7811SThomas Huth         return (s->scr1 >> 8)  & 0xFF;
265956a7811SThomas Huth     case 0xc003:
266956a7811SThomas Huth         return (s->scr1 >> 0)  & 0xFF;
267956a7811SThomas Huth 
268956a7811SThomas Huth     case 0xd000:
269956a7811SThomas Huth         return (s->scr2 >> 24) & 0xFF;
270956a7811SThomas Huth     case 0xd001:
271956a7811SThomas Huth         return (s->scr2 >> 16) & 0xFF;
272956a7811SThomas Huth     case 0xd002:
273956a7811SThomas Huth         return (s->scr2 >> 8)  & 0xFF;
274956a7811SThomas Huth     case 0xd003:
275956a7811SThomas Huth         return (s->scr2 >> 0)  & 0xFF;
276956a7811SThomas Huth     case 0x14020:
277956a7811SThomas Huth         DPRINTF("MMIO Read 0x4020\n");
278956a7811SThomas Huth         return 0x7f;
279956a7811SThomas Huth 
280956a7811SThomas Huth     default:
281956a7811SThomas Huth         DPRINTF("MMIO Read B @ %"HWADDR_PRIx"\n", addr);
282956a7811SThomas Huth         return 0x0;
283956a7811SThomas Huth     }
284956a7811SThomas Huth }
285956a7811SThomas Huth 
28640831636SPeter Maydell static uint32_t mmio_readw(NeXTPC *s, hwaddr addr)
287956a7811SThomas Huth {
288956a7811SThomas Huth     switch (addr) {
289956a7811SThomas Huth     default:
290956a7811SThomas Huth         DPRINTF("MMIO Read W @ %"HWADDR_PRIx"\n", addr);
291956a7811SThomas Huth         return 0x0;
292956a7811SThomas Huth     }
293956a7811SThomas Huth }
294956a7811SThomas Huth 
29540831636SPeter Maydell static uint32_t mmio_readl(NeXTPC *s, hwaddr addr)
296956a7811SThomas Huth {
297956a7811SThomas Huth     switch (addr) {
298956a7811SThomas Huth     case 0x7000:
299ac99317bSPeter Maydell         /* DPRINTF("Read INT status: %x\n", s->int_status); */
300ac99317bSPeter Maydell         return s->int_status;
301956a7811SThomas Huth 
302956a7811SThomas Huth     case 0x7800:
303ac99317bSPeter Maydell         DPRINTF("MMIO Read INT mask: %x\n", s->int_mask);
304ac99317bSPeter Maydell         return s->int_mask;
305956a7811SThomas Huth 
306956a7811SThomas Huth     case 0xc000:
307956a7811SThomas Huth         return s->scr1;
308956a7811SThomas Huth 
309956a7811SThomas Huth     case 0xd000:
310956a7811SThomas Huth         return s->scr2;
311956a7811SThomas Huth 
312956a7811SThomas Huth     default:
313956a7811SThomas Huth         DPRINTF("MMIO Read L @ %"HWADDR_PRIx"\n", addr);
314956a7811SThomas Huth         return 0x0;
315956a7811SThomas Huth     }
316956a7811SThomas Huth }
317956a7811SThomas Huth 
31840831636SPeter Maydell static void mmio_writeb(NeXTPC *s, hwaddr addr, uint32_t val)
319956a7811SThomas Huth {
320956a7811SThomas Huth     switch (addr) {
321956a7811SThomas Huth     case 0xd003:
322956a7811SThomas Huth         nextscr2_write(s, val, 1);
323956a7811SThomas Huth         break;
324956a7811SThomas Huth     default:
325956a7811SThomas Huth         DPRINTF("MMIO Write B @ %x with %x\n", (unsigned int)addr, val);
326956a7811SThomas Huth     }
327956a7811SThomas Huth 
328956a7811SThomas Huth }
329956a7811SThomas Huth 
33040831636SPeter Maydell static void mmio_writew(NeXTPC *s, hwaddr addr, uint32_t val)
331956a7811SThomas Huth {
332956a7811SThomas Huth     DPRINTF("MMIO Write W\n");
333956a7811SThomas Huth }
334956a7811SThomas Huth 
33540831636SPeter Maydell static void mmio_writel(NeXTPC *s, hwaddr addr, uint32_t val)
336956a7811SThomas Huth {
337956a7811SThomas Huth     switch (addr) {
338956a7811SThomas Huth     case 0x7000:
339ac99317bSPeter Maydell         DPRINTF("INT Status old: %x new: %x\n", s->int_status, val);
340ac99317bSPeter Maydell         s->int_status = val;
341956a7811SThomas Huth         break;
342956a7811SThomas Huth     case 0x7800:
343ac99317bSPeter Maydell         DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, val);
344ac99317bSPeter Maydell         s->int_mask  = val;
345956a7811SThomas Huth         break;
346956a7811SThomas Huth     case 0xc000:
347956a7811SThomas Huth         DPRINTF("SCR1 Write: %x\n", val);
348956a7811SThomas Huth         break;
349956a7811SThomas Huth     case 0xd000:
350956a7811SThomas Huth         nextscr2_write(s, val, 4);
351956a7811SThomas Huth         break;
352956a7811SThomas Huth 
353956a7811SThomas Huth     default:
354956a7811SThomas Huth         DPRINTF("MMIO Write l @ %x with %x\n", (unsigned int)addr, val);
355956a7811SThomas Huth     }
356956a7811SThomas Huth }
357956a7811SThomas Huth 
358956a7811SThomas Huth static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size)
359956a7811SThomas Huth {
36040831636SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
361956a7811SThomas Huth 
362956a7811SThomas Huth     switch (size) {
363956a7811SThomas Huth     case 1:
36440831636SPeter Maydell         return mmio_readb(s, addr);
365956a7811SThomas Huth     case 2:
36640831636SPeter Maydell         return mmio_readw(s, addr);
367956a7811SThomas Huth     case 4:
36840831636SPeter Maydell         return mmio_readl(s, addr);
369956a7811SThomas Huth     default:
370956a7811SThomas Huth         g_assert_not_reached();
371956a7811SThomas Huth     }
372956a7811SThomas Huth }
373956a7811SThomas Huth 
374956a7811SThomas Huth static void mmio_writefn(void *opaque, hwaddr addr, uint64_t value,
375956a7811SThomas Huth                          unsigned size)
376956a7811SThomas Huth {
37740831636SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
378956a7811SThomas Huth 
379956a7811SThomas Huth     switch (size) {
380956a7811SThomas Huth     case 1:
38140831636SPeter Maydell         mmio_writeb(s, addr, value);
382956a7811SThomas Huth         break;
383956a7811SThomas Huth     case 2:
38440831636SPeter Maydell         mmio_writew(s, addr, value);
385956a7811SThomas Huth         break;
386956a7811SThomas Huth     case 4:
38740831636SPeter Maydell         mmio_writel(s, addr, value);
388956a7811SThomas Huth         break;
389956a7811SThomas Huth     default:
390956a7811SThomas Huth         g_assert_not_reached();
391956a7811SThomas Huth     }
392956a7811SThomas Huth }
393956a7811SThomas Huth 
394956a7811SThomas Huth static const MemoryRegionOps mmio_ops = {
395956a7811SThomas Huth     .read = mmio_readfn,
396956a7811SThomas Huth     .write = mmio_writefn,
397956a7811SThomas Huth     .valid.min_access_size = 1,
398956a7811SThomas Huth     .valid.max_access_size = 4,
399956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
400956a7811SThomas Huth };
401956a7811SThomas Huth 
4021dc7aeaeSPeter Maydell static uint32_t scr_readb(NeXTPC *s, hwaddr addr)
403956a7811SThomas Huth {
404956a7811SThomas Huth     switch (addr) {
405956a7811SThomas Huth     case 0x14108:
406956a7811SThomas Huth         DPRINTF("FD read @ %x\n", (unsigned int)addr);
407956a7811SThomas Huth         return 0x40 | 0x04 | 0x2 | 0x1;
408956a7811SThomas Huth     case 0x14020:
409956a7811SThomas Huth         DPRINTF("SCSI 4020  STATUS READ %X\n", s->scsi_csr_1);
410956a7811SThomas Huth         return s->scsi_csr_1;
411956a7811SThomas Huth 
412956a7811SThomas Huth     case 0x14021:
413956a7811SThomas Huth         DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2);
414956a7811SThomas Huth         return 0x40;
415956a7811SThomas Huth 
416956a7811SThomas Huth     /*
417956a7811SThomas Huth      * These 4 registers are the hardware timer, not sure which register
418956a7811SThomas Huth      * is the latch instead of data, but no problems so far
419956a7811SThomas Huth      */
420956a7811SThomas Huth     case 0x1a000:
421956a7811SThomas Huth         return 0xff & (clock() >> 24);
422956a7811SThomas Huth     case 0x1a001:
423956a7811SThomas Huth         return 0xff & (clock() >> 16);
424956a7811SThomas Huth     case 0x1a002:
425956a7811SThomas Huth         return 0xff & (clock() >> 8);
426956a7811SThomas Huth     case 0x1a003:
427956a7811SThomas Huth         /* Hack: We need to have this change consistently to make it work */
428956a7811SThomas Huth         return 0xFF & clock();
429956a7811SThomas Huth 
430956a7811SThomas Huth     default:
431956a7811SThomas Huth         DPRINTF("BMAP Read B @ %x\n", (unsigned int)addr);
432956a7811SThomas Huth         return 0;
433956a7811SThomas Huth     }
434956a7811SThomas Huth }
435956a7811SThomas Huth 
4361dc7aeaeSPeter Maydell static uint32_t scr_readw(NeXTPC *s, hwaddr addr)
437956a7811SThomas Huth {
438956a7811SThomas Huth     DPRINTF("BMAP Read W @ %x\n", (unsigned int)addr);
439956a7811SThomas Huth     return 0;
440956a7811SThomas Huth }
441956a7811SThomas Huth 
4421dc7aeaeSPeter Maydell static uint32_t scr_readl(NeXTPC *s, hwaddr addr)
443956a7811SThomas Huth {
444956a7811SThomas Huth     DPRINTF("BMAP Read L @ %x\n", (unsigned int)addr);
445956a7811SThomas Huth     return 0;
446956a7811SThomas Huth }
447956a7811SThomas Huth 
448956a7811SThomas Huth #define SCSICSR_ENABLE  0x01
449956a7811SThomas Huth #define SCSICSR_RESET   0x02  /* reset scsi dma */
450956a7811SThomas Huth #define SCSICSR_FIFOFL  0x04
451956a7811SThomas Huth #define SCSICSR_DMADIR  0x08  /* if set, scsi to mem */
452956a7811SThomas Huth #define SCSICSR_CPUDMA  0x10  /* if set, dma enabled */
453956a7811SThomas Huth #define SCSICSR_INTMASK 0x20  /* if set, interrupt enabled */
454956a7811SThomas Huth 
4551dc7aeaeSPeter Maydell static void scr_writeb(NeXTPC *s, hwaddr addr, uint32_t value)
456956a7811SThomas Huth {
457956a7811SThomas Huth     switch (addr) {
458956a7811SThomas Huth     case 0x14108:
459956a7811SThomas Huth         DPRINTF("FDCSR Write: %x\n", value);
460956a7811SThomas Huth 
461956a7811SThomas Huth         if (value == 0x0) {
462956a7811SThomas Huth             /* qemu_irq_raise(s->fd_irq[0]); */
463956a7811SThomas Huth         }
464956a7811SThomas Huth         break;
465956a7811SThomas Huth     case 0x14020: /* SCSI Control Register */
466956a7811SThomas Huth         if (value & SCSICSR_FIFOFL) {
467956a7811SThomas Huth             DPRINTF("SCSICSR FIFO Flush\n");
468956a7811SThomas Huth             /* will have to add another irq to the esp if this is needed */
469956a7811SThomas Huth             /* esp_puflush_fifo(esp_g); */
470956a7811SThomas Huth             /* qemu_irq_pulse(s->scsi_dma); */
471956a7811SThomas Huth         }
472956a7811SThomas Huth 
473956a7811SThomas Huth         if (value & SCSICSR_ENABLE) {
474956a7811SThomas Huth             DPRINTF("SCSICSR Enable\n");
475956a7811SThomas Huth             /*
476956a7811SThomas Huth              * qemu_irq_raise(s->scsi_dma);
477956a7811SThomas Huth              * s->scsi_csr_1 = 0xc0;
478956a7811SThomas Huth              * s->scsi_csr_1 |= 0x1;
479956a7811SThomas Huth              * qemu_irq_pulse(s->scsi_dma);
480956a7811SThomas Huth              */
481956a7811SThomas Huth         }
482956a7811SThomas Huth         /*
483956a7811SThomas Huth          * else
484956a7811SThomas Huth          *     s->scsi_csr_1 &= ~SCSICSR_ENABLE;
485956a7811SThomas Huth          */
486956a7811SThomas Huth 
487956a7811SThomas Huth         if (value & SCSICSR_RESET) {
488956a7811SThomas Huth             DPRINTF("SCSICSR Reset\n");
489956a7811SThomas Huth             /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */
490956a7811SThomas Huth             /* qemu_irq_raise(s->scsi_reset); */
491956a7811SThomas Huth             /* s->scsi_csr_1 &= ~(SCSICSR_INTMASK |0x80|0x1); */
492956a7811SThomas Huth 
493956a7811SThomas Huth         }
494956a7811SThomas Huth         if (value & SCSICSR_DMADIR) {
495956a7811SThomas Huth             DPRINTF("SCSICSR DMAdir\n");
496956a7811SThomas Huth         }
497956a7811SThomas Huth         if (value & SCSICSR_CPUDMA) {
498956a7811SThomas Huth             DPRINTF("SCSICSR CPUDMA\n");
499956a7811SThomas Huth             /* qemu_irq_raise(s->scsi_dma); */
500956a7811SThomas Huth 
501ac99317bSPeter Maydell             s->int_status |= 0x4000000;
502956a7811SThomas Huth         } else {
503ac99317bSPeter Maydell             s->int_status &= ~(0x4000000);
504956a7811SThomas Huth         }
505956a7811SThomas Huth         if (value & SCSICSR_INTMASK) {
506956a7811SThomas Huth             DPRINTF("SCSICSR INTMASK\n");
507956a7811SThomas Huth             /*
508956a7811SThomas Huth              * int_mask &= ~0x1000;
509956a7811SThomas Huth              * s->scsi_csr_1 |= value;
510956a7811SThomas Huth              * s->scsi_csr_1 &= ~SCSICSR_INTMASK;
511956a7811SThomas Huth              * if (s->scsi_queued) {
512956a7811SThomas Huth              *     s->scsi_queued = 0;
513956a7811SThomas Huth              *     next_irq(s, NEXT_SCSI_I, level);
514956a7811SThomas Huth              * }
515956a7811SThomas Huth              */
516956a7811SThomas Huth         } else {
517956a7811SThomas Huth             /* int_mask |= 0x1000; */
518956a7811SThomas Huth         }
519956a7811SThomas Huth         if (value & 0x80) {
520956a7811SThomas Huth             /* int_mask |= 0x1000; */
521956a7811SThomas Huth             /* s->scsi_csr_1 |= 0x80; */
522956a7811SThomas Huth         }
523956a7811SThomas Huth         DPRINTF("SCSICSR Write: %x\n", value);
524956a7811SThomas Huth         /* s->scsi_csr_1 = value; */
525956a7811SThomas Huth         return;
526956a7811SThomas Huth     /* Hardware timer latch - not implemented yet */
527956a7811SThomas Huth     case 0x1a000:
528956a7811SThomas Huth     default:
529956a7811SThomas Huth         DPRINTF("BMAP Write B @ %x with %x\n", (unsigned int)addr, value);
530956a7811SThomas Huth     }
531956a7811SThomas Huth }
532956a7811SThomas Huth 
5331dc7aeaeSPeter Maydell static void scr_writew(NeXTPC *s, hwaddr addr, uint32_t value)
534956a7811SThomas Huth {
535956a7811SThomas Huth     DPRINTF("BMAP Write W @ %x with %x\n", (unsigned int)addr, value);
536956a7811SThomas Huth }
537956a7811SThomas Huth 
5381dc7aeaeSPeter Maydell static void scr_writel(NeXTPC *s, hwaddr addr, uint32_t value)
539956a7811SThomas Huth {
540956a7811SThomas Huth     DPRINTF("BMAP Write L @ %x with %x\n", (unsigned int)addr, value);
541956a7811SThomas Huth }
542956a7811SThomas Huth 
543956a7811SThomas Huth static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size)
544956a7811SThomas Huth {
5451dc7aeaeSPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
546956a7811SThomas Huth 
547956a7811SThomas Huth     switch (size) {
548956a7811SThomas Huth     case 1:
5491dc7aeaeSPeter Maydell         return scr_readb(s, addr);
550956a7811SThomas Huth     case 2:
5511dc7aeaeSPeter Maydell         return scr_readw(s, addr);
552956a7811SThomas Huth     case 4:
5531dc7aeaeSPeter Maydell         return scr_readl(s, addr);
554956a7811SThomas Huth     default:
555956a7811SThomas Huth         g_assert_not_reached();
556956a7811SThomas Huth     }
557956a7811SThomas Huth }
558956a7811SThomas Huth 
559956a7811SThomas Huth static void scr_writefn(void *opaque, hwaddr addr, uint64_t value,
560956a7811SThomas Huth                         unsigned size)
561956a7811SThomas Huth {
5621dc7aeaeSPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
563956a7811SThomas Huth 
564956a7811SThomas Huth     switch (size) {
565956a7811SThomas Huth     case 1:
5661dc7aeaeSPeter Maydell         scr_writeb(s, addr, value);
567956a7811SThomas Huth         break;
568956a7811SThomas Huth     case 2:
5691dc7aeaeSPeter Maydell         scr_writew(s, addr, value);
570956a7811SThomas Huth         break;
571956a7811SThomas Huth     case 4:
5721dc7aeaeSPeter Maydell         scr_writel(s, addr, value);
573956a7811SThomas Huth         break;
574956a7811SThomas Huth     default:
575956a7811SThomas Huth         g_assert_not_reached();
576956a7811SThomas Huth     }
577956a7811SThomas Huth }
578956a7811SThomas Huth 
579956a7811SThomas Huth static const MemoryRegionOps scr_ops = {
580956a7811SThomas Huth     .read = scr_readfn,
581956a7811SThomas Huth     .write = scr_writefn,
582956a7811SThomas Huth     .valid.min_access_size = 1,
583956a7811SThomas Huth     .valid.max_access_size = 4,
584956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
585956a7811SThomas Huth };
586956a7811SThomas Huth 
587956a7811SThomas Huth #define NEXTDMA_SCSI(x)      (0x10 + x)
588956a7811SThomas Huth #define NEXTDMA_FD(x)        (0x10 + x)
589956a7811SThomas Huth #define NEXTDMA_ENTX(x)      (0x110 + x)
590956a7811SThomas Huth #define NEXTDMA_ENRX(x)      (0x150 + x)
591956a7811SThomas Huth #define NEXTDMA_CSR          0x0
592956a7811SThomas Huth #define NEXTDMA_NEXT         0x4000
593956a7811SThomas Huth #define NEXTDMA_LIMIT        0x4004
594956a7811SThomas Huth #define NEXTDMA_START        0x4008
595956a7811SThomas Huth #define NEXTDMA_STOP         0x400c
596956a7811SThomas Huth #define NEXTDMA_NEXT_INIT    0x4200
597956a7811SThomas Huth #define NEXTDMA_SIZE         0x4204
598956a7811SThomas Huth 
599956a7811SThomas Huth static void dma_writel(void *opaque, hwaddr addr, uint64_t value,
600956a7811SThomas Huth                        unsigned int size)
601956a7811SThomas Huth {
602956a7811SThomas Huth     NeXTState *next_state = NEXT_MACHINE(opaque);
603956a7811SThomas Huth 
604956a7811SThomas Huth     switch (addr) {
605956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_CSR):
606956a7811SThomas Huth         if (value & DMA_DEV2M) {
607956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M;
608956a7811SThomas Huth         }
609956a7811SThomas Huth 
610956a7811SThomas Huth         if (value & DMA_SETENABLE) {
611956a7811SThomas Huth             /* DPRINTF("SCSI DMA ENABLE\n"); */
612956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE;
613956a7811SThomas Huth         }
614956a7811SThomas Huth         if (value & DMA_SETSUPDATE) {
615956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE;
616956a7811SThomas Huth         }
617956a7811SThomas Huth         if (value & DMA_CLRCOMPLETE) {
618956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE;
619956a7811SThomas Huth         }
620956a7811SThomas Huth 
621956a7811SThomas Huth         if (value & DMA_RESET) {
622956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
623956a7811SThomas Huth                                                   DMA_ENABLE | DMA_DEV2M);
624956a7811SThomas Huth         }
625956a7811SThomas Huth         /* DPRINTF("RXCSR \tWrite: %x\n",value); */
626956a7811SThomas Huth         break;
627956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
628956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].next_initbuf = value;
629956a7811SThomas Huth         break;
630956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
631956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].next = value;
632956a7811SThomas Huth         break;
633956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
634956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].limit = value;
635956a7811SThomas Huth         break;
636956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_CSR):
637956a7811SThomas Huth         if (value & DMA_DEV2M) {
638956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M;
639956a7811SThomas Huth         }
640956a7811SThomas Huth         if (value & DMA_SETENABLE) {
641956a7811SThomas Huth             /* DPRINTF("SCSI DMA ENABLE\n"); */
642956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE;
643956a7811SThomas Huth         }
644956a7811SThomas Huth         if (value & DMA_SETSUPDATE) {
645956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE;
646956a7811SThomas Huth         }
647956a7811SThomas Huth         if (value & DMA_CLRCOMPLETE) {
648956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE;
649956a7811SThomas Huth         }
650956a7811SThomas Huth 
651956a7811SThomas Huth         if (value & DMA_RESET) {
652956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
653956a7811SThomas Huth                                                   DMA_ENABLE | DMA_DEV2M);
654956a7811SThomas Huth             /* DPRINTF("SCSI DMA RESET\n"); */
655956a7811SThomas Huth         }
656956a7811SThomas Huth         /* DPRINTF("RXCSR \tWrite: %x\n",value); */
657956a7811SThomas Huth         break;
658956a7811SThomas Huth 
659956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT):
660956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].next = value;
661956a7811SThomas Huth         break;
662956a7811SThomas Huth 
663956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
664956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].limit = value;
665956a7811SThomas Huth         break;
666956a7811SThomas Huth 
667956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
668956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].start = value;
669956a7811SThomas Huth         break;
670956a7811SThomas Huth 
671956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
672956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].stop = value;
673956a7811SThomas Huth         break;
674956a7811SThomas Huth 
675956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
676956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].next_initbuf = value;
677956a7811SThomas Huth         break;
678956a7811SThomas Huth 
679956a7811SThomas Huth     default:
680956a7811SThomas Huth         DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value);
681956a7811SThomas Huth     }
682956a7811SThomas Huth }
683956a7811SThomas Huth 
684956a7811SThomas Huth static uint64_t dma_readl(void *opaque, hwaddr addr, unsigned int size)
685956a7811SThomas Huth {
686956a7811SThomas Huth     NeXTState *next_state = NEXT_MACHINE(opaque);
687956a7811SThomas Huth 
688956a7811SThomas Huth     switch (addr) {
689956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_CSR):
690956a7811SThomas Huth         DPRINTF("SCSI DMA CSR READ\n");
691956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].csr;
692956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_CSR):
693956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].csr;
694956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
695956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].next_initbuf;
696956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
697956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].next;
698956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
699956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].limit;
700956a7811SThomas Huth 
701956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT):
702956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].next;
703956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
704956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].next_initbuf;
705956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
706956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].limit;
707956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
708956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].start;
709956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
710956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].stop;
711956a7811SThomas Huth 
712956a7811SThomas Huth     default:
713956a7811SThomas Huth         DPRINTF("DMA read @ %x\n", (unsigned int)addr);
714956a7811SThomas Huth         return 0;
715956a7811SThomas Huth     }
716956a7811SThomas Huth 
717956a7811SThomas Huth     /*
718956a7811SThomas Huth      * once the csr's are done, subtract 0x3FEC from the addr, and that will
719956a7811SThomas Huth      * normalize the upper registers
720956a7811SThomas Huth      */
721956a7811SThomas Huth }
722956a7811SThomas Huth 
723956a7811SThomas Huth static const MemoryRegionOps dma_ops = {
724956a7811SThomas Huth     .read = dma_readl,
725956a7811SThomas Huth     .write = dma_writel,
726956a7811SThomas Huth     .impl.min_access_size = 4,
727956a7811SThomas Huth     .valid.min_access_size = 4,
728956a7811SThomas Huth     .valid.max_access_size = 4,
729956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
730956a7811SThomas Huth };
731956a7811SThomas Huth 
732c8abcc87SPeter Maydell static void next_irq(void *opaque, int number, int level)
733956a7811SThomas Huth {
734b497f4a1SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
735b497f4a1SPeter Maydell     M68kCPU *cpu = s->cpu;
736956a7811SThomas Huth     int shift = 0;
737956a7811SThomas Huth 
738956a7811SThomas Huth     /* first switch sets interupt status */
739956a7811SThomas Huth     /* DPRINTF("IRQ %i\n",number); */
740956a7811SThomas Huth     switch (number) {
741956a7811SThomas Huth     /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
742956a7811SThomas Huth     case NEXT_FD_I:
7435012a894SPhilippe Mathieu-Daudé         shift = 7;
744956a7811SThomas Huth         break;
745956a7811SThomas Huth     case NEXT_KBD_I:
746956a7811SThomas Huth         shift = 3;
747956a7811SThomas Huth         break;
748956a7811SThomas Huth     case NEXT_PWR_I:
749956a7811SThomas Huth         shift = 2;
750956a7811SThomas Huth         break;
751956a7811SThomas Huth     case NEXT_ENRX_I:
752956a7811SThomas Huth         shift = 9;
753956a7811SThomas Huth         break;
754956a7811SThomas Huth     case NEXT_ENTX_I:
755956a7811SThomas Huth         shift = 10;
756956a7811SThomas Huth         break;
757956a7811SThomas Huth     case NEXT_SCSI_I:
758956a7811SThomas Huth         shift = 12;
759956a7811SThomas Huth         break;
760956a7811SThomas Huth     case NEXT_CLK_I:
761956a7811SThomas Huth         shift = 5;
762956a7811SThomas Huth         break;
763956a7811SThomas Huth 
764956a7811SThomas Huth     /* level 5 - scc (serial) */
765956a7811SThomas Huth     case NEXT_SCC_I:
766956a7811SThomas Huth         shift = 17;
767956a7811SThomas Huth         break;
768956a7811SThomas Huth 
769956a7811SThomas Huth     /* level 6 - audio etherrx/tx dma */
770956a7811SThomas Huth     case NEXT_ENTX_DMA_I:
771956a7811SThomas Huth         shift = 28;
772956a7811SThomas Huth         break;
773956a7811SThomas Huth     case NEXT_ENRX_DMA_I:
774956a7811SThomas Huth         shift = 27;
775956a7811SThomas Huth         break;
776956a7811SThomas Huth     case NEXT_SCSI_DMA_I:
777956a7811SThomas Huth         shift = 26;
778956a7811SThomas Huth         break;
779956a7811SThomas Huth     case NEXT_SND_I:
780956a7811SThomas Huth         shift = 23;
781956a7811SThomas Huth         break;
782956a7811SThomas Huth     case NEXT_SCC_DMA_I:
783956a7811SThomas Huth         shift = 21;
784956a7811SThomas Huth         break;
785956a7811SThomas Huth 
786956a7811SThomas Huth     }
787956a7811SThomas Huth     /*
788956a7811SThomas Huth      * this HAS to be wrong, the interrupt handlers in mach and together
789956a7811SThomas Huth      * int_status and int_mask and return if there is a hit
790956a7811SThomas Huth      */
791ac99317bSPeter Maydell     if (s->int_mask & (1 << shift)) {
792956a7811SThomas Huth         DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc);
793956a7811SThomas Huth         /* return; */
794956a7811SThomas Huth     }
795956a7811SThomas Huth 
796956a7811SThomas Huth     /* second switch triggers the correct interrupt */
797956a7811SThomas Huth     if (level) {
798ac99317bSPeter Maydell         s->int_status |= 1 << shift;
799956a7811SThomas Huth 
800956a7811SThomas Huth         switch (number) {
801956a7811SThomas Huth         /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
802956a7811SThomas Huth         case NEXT_FD_I:
803956a7811SThomas Huth         case NEXT_KBD_I:
804956a7811SThomas Huth         case NEXT_PWR_I:
805956a7811SThomas Huth         case NEXT_ENRX_I:
806956a7811SThomas Huth         case NEXT_ENTX_I:
807956a7811SThomas Huth         case NEXT_SCSI_I:
808956a7811SThomas Huth         case NEXT_CLK_I:
809956a7811SThomas Huth             m68k_set_irq_level(cpu, 3, 27);
810956a7811SThomas Huth             break;
811956a7811SThomas Huth 
812956a7811SThomas Huth         /* level 5 - scc (serial) */
813956a7811SThomas Huth         case NEXT_SCC_I:
814956a7811SThomas Huth             m68k_set_irq_level(cpu, 5, 29);
815956a7811SThomas Huth             break;
816956a7811SThomas Huth 
817956a7811SThomas Huth         /* level 6 - audio etherrx/tx dma */
818956a7811SThomas Huth         case NEXT_ENTX_DMA_I:
819956a7811SThomas Huth         case NEXT_ENRX_DMA_I:
820956a7811SThomas Huth         case NEXT_SCSI_DMA_I:
821956a7811SThomas Huth         case NEXT_SND_I:
822956a7811SThomas Huth         case NEXT_SCC_DMA_I:
823956a7811SThomas Huth             m68k_set_irq_level(cpu, 6, 30);
824956a7811SThomas Huth             break;
825956a7811SThomas Huth         }
826956a7811SThomas Huth     } else {
827ac99317bSPeter Maydell         s->int_status &= ~(1 << shift);
828956a7811SThomas Huth         cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
829956a7811SThomas Huth     }
830956a7811SThomas Huth }
831956a7811SThomas Huth 
832b497f4a1SPeter Maydell static void next_escc_init(DeviceState *pcdev)
833b17bed5bSThomas Huth {
834b17bed5bSThomas Huth     DeviceState *dev;
835b17bed5bSThomas Huth     SysBusDevice *s;
836b17bed5bSThomas Huth 
8373e80f690SMarkus Armbruster     dev = qdev_new(TYPE_ESCC);
838b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "disabled", 0);
839b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "frequency", 9600 * 384);
840b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "it_shift", 0);
841b17bed5bSThomas Huth     qdev_prop_set_bit(dev, "bit_swap", true);
842b17bed5bSThomas Huth     qdev_prop_set_chr(dev, "chrB", serial_hd(1));
843b17bed5bSThomas Huth     qdev_prop_set_chr(dev, "chrA", serial_hd(0));
844b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
845b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
846b17bed5bSThomas Huth 
847b17bed5bSThomas Huth     s = SYS_BUS_DEVICE(dev);
8483c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
849d9cd4039SPeter Maydell     sysbus_connect_irq(s, 0, qdev_get_gpio_in(pcdev, NEXT_SCC_I));
850d9cd4039SPeter Maydell     sysbus_connect_irq(s, 1, qdev_get_gpio_in(pcdev, NEXT_SCC_DMA_I));
851b17bed5bSThomas Huth     sysbus_mmio_map(s, 0, 0x2118000);
852b17bed5bSThomas Huth }
853b17bed5bSThomas Huth 
854660bef33SPeter Maydell static void next_pc_reset(DeviceState *dev)
855660bef33SPeter Maydell {
85640831636SPeter Maydell     NeXTPC *s = NEXT_PC(dev);
85740831636SPeter Maydell 
85840831636SPeter Maydell     /* Set internal registers to initial values */
85940831636SPeter Maydell     /*     0x0000XX00 << vital bits */
86040831636SPeter Maydell     s->scr1 = 0x00011102;
86140831636SPeter Maydell     s->scr2 = 0x00ff0c80;
8626f0face7SPeter Maydell 
8636f0face7SPeter Maydell     s->rtc.status = 0x90;
8646f0face7SPeter Maydell 
8656f0face7SPeter Maydell     /* Load RTC RAM - TODO: provide possibility to load contents from file */
8666f0face7SPeter Maydell     memcpy(s->rtc.ram, rtc_ram2, 32);
867660bef33SPeter Maydell }
868660bef33SPeter Maydell 
869660bef33SPeter Maydell static void next_pc_realize(DeviceState *dev, Error **errp)
870660bef33SPeter Maydell {
87140831636SPeter Maydell     NeXTPC *s = NEXT_PC(dev);
87240831636SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
87340831636SPeter Maydell 
874d9cd4039SPeter Maydell     qdev_init_gpio_in(dev, next_irq, NEXT_NUM_IRQS);
875d9cd4039SPeter Maydell 
87640831636SPeter Maydell     memory_region_init_io(&s->mmiomem, OBJECT(s), &mmio_ops, s,
87740831636SPeter Maydell                           "next.mmio", 0xD0000);
8781dc7aeaeSPeter Maydell     memory_region_init_io(&s->scrmem, OBJECT(s), &scr_ops, s,
8791dc7aeaeSPeter Maydell                           "next.scr", 0x20000);
88040831636SPeter Maydell     sysbus_init_mmio(sbd, &s->mmiomem);
8811dc7aeaeSPeter Maydell     sysbus_init_mmio(sbd, &s->scrmem);
882660bef33SPeter Maydell }
883660bef33SPeter Maydell 
884b497f4a1SPeter Maydell /*
885b497f4a1SPeter Maydell  * If the m68k CPU implemented its inbound irq lines as GPIO lines
886b497f4a1SPeter Maydell  * rather than via the m68k_set_irq_level() function we would not need
887b497f4a1SPeter Maydell  * this cpu link property and could instead provide outbound IRQ lines
888b497f4a1SPeter Maydell  * that the board could wire up to the CPU.
889b497f4a1SPeter Maydell  */
890b497f4a1SPeter Maydell static Property next_pc_properties[] = {
891b497f4a1SPeter Maydell     DEFINE_PROP_LINK("cpu", NeXTPC, cpu, TYPE_M68K_CPU, M68kCPU *),
892b497f4a1SPeter Maydell     DEFINE_PROP_END_OF_LIST(),
893b497f4a1SPeter Maydell };
894b497f4a1SPeter Maydell 
895*75ca77ecSPeter Maydell static const VMStateDescription next_rtc_vmstate = {
896*75ca77ecSPeter Maydell     .name = "next-rtc",
897*75ca77ecSPeter Maydell     .version_id = 1,
898*75ca77ecSPeter Maydell     .minimum_version_id = 1,
899*75ca77ecSPeter Maydell     .fields = (VMStateField[]) {
900*75ca77ecSPeter Maydell         VMSTATE_UINT8_ARRAY(ram, NextRtc, 32),
901*75ca77ecSPeter Maydell         VMSTATE_UINT8(command, NextRtc),
902*75ca77ecSPeter Maydell         VMSTATE_UINT8(value, NextRtc),
903*75ca77ecSPeter Maydell         VMSTATE_UINT8(status, NextRtc),
904*75ca77ecSPeter Maydell         VMSTATE_UINT8(control, NextRtc),
905*75ca77ecSPeter Maydell         VMSTATE_UINT8(retval, NextRtc),
906*75ca77ecSPeter Maydell         VMSTATE_END_OF_LIST()
907*75ca77ecSPeter Maydell     },
908*75ca77ecSPeter Maydell };
909*75ca77ecSPeter Maydell 
910*75ca77ecSPeter Maydell static const VMStateDescription next_pc_vmstate = {
911*75ca77ecSPeter Maydell     .name = "next-pc",
912*75ca77ecSPeter Maydell     .version_id = 1,
913*75ca77ecSPeter Maydell     .minimum_version_id = 1,
914*75ca77ecSPeter Maydell     .fields = (VMStateField[]) {
915*75ca77ecSPeter Maydell         VMSTATE_UINT32(scr1, NeXTPC),
916*75ca77ecSPeter Maydell         VMSTATE_UINT32(scr2, NeXTPC),
917*75ca77ecSPeter Maydell         VMSTATE_UINT32(int_mask, NeXTPC),
918*75ca77ecSPeter Maydell         VMSTATE_UINT32(int_status, NeXTPC),
919*75ca77ecSPeter Maydell         VMSTATE_UINT8(scsi_csr_1, NeXTPC),
920*75ca77ecSPeter Maydell         VMSTATE_UINT8(scsi_csr_2, NeXTPC),
921*75ca77ecSPeter Maydell         VMSTATE_STRUCT(rtc, NeXTPC, 0, next_rtc_vmstate, NextRtc),
922*75ca77ecSPeter Maydell         VMSTATE_END_OF_LIST()
923*75ca77ecSPeter Maydell     },
924*75ca77ecSPeter Maydell };
925*75ca77ecSPeter Maydell 
926660bef33SPeter Maydell static void next_pc_class_init(ObjectClass *klass, void *data)
927660bef33SPeter Maydell {
928660bef33SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
929660bef33SPeter Maydell 
930660bef33SPeter Maydell     dc->desc = "NeXT Peripheral Controller";
931660bef33SPeter Maydell     dc->realize = next_pc_realize;
932660bef33SPeter Maydell     dc->reset = next_pc_reset;
933b497f4a1SPeter Maydell     device_class_set_props(dc, next_pc_properties);
934*75ca77ecSPeter Maydell     dc->vmsd = &next_pc_vmstate;
935660bef33SPeter Maydell }
936660bef33SPeter Maydell 
937660bef33SPeter Maydell static const TypeInfo next_pc_info = {
938660bef33SPeter Maydell     .name = TYPE_NEXT_PC,
939660bef33SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
940660bef33SPeter Maydell     .instance_size = sizeof(NeXTPC),
941660bef33SPeter Maydell     .class_init = next_pc_class_init,
942660bef33SPeter Maydell };
943660bef33SPeter Maydell 
944956a7811SThomas Huth static void next_cube_init(MachineState *machine)
945956a7811SThomas Huth {
946956a7811SThomas Huth     M68kCPU *cpu;
947956a7811SThomas Huth     CPUM68KState *env;
948956a7811SThomas Huth     MemoryRegion *rom = g_new(MemoryRegion, 1);
949956a7811SThomas Huth     MemoryRegion *dmamem = g_new(MemoryRegion, 1);
950956a7811SThomas Huth     MemoryRegion *bmapm1 = g_new(MemoryRegion, 1);
951956a7811SThomas Huth     MemoryRegion *bmapm2 = g_new(MemoryRegion, 1);
952956a7811SThomas Huth     MemoryRegion *sysmem = get_system_memory();
9531684273cSPaolo Bonzini     const char *bios_name = machine->firmware ?: ROM_FILE;
954956a7811SThomas Huth     DeviceState *dev;
955660bef33SPeter Maydell     DeviceState *pcdev;
956956a7811SThomas Huth 
957956a7811SThomas Huth     /* Initialize the cpu core */
958956a7811SThomas Huth     cpu = M68K_CPU(cpu_create(machine->cpu_type));
959956a7811SThomas Huth     if (!cpu) {
960956a7811SThomas Huth         error_report("Unable to find m68k CPU definition");
961956a7811SThomas Huth         exit(1);
962956a7811SThomas Huth     }
963956a7811SThomas Huth     env = &cpu->env;
964956a7811SThomas Huth 
965956a7811SThomas Huth     /* Initialize CPU registers.  */
966956a7811SThomas Huth     env->vbr = 0;
967956a7811SThomas Huth     env->sr  = 0x2700;
968956a7811SThomas Huth 
969660bef33SPeter Maydell     /* Peripheral Controller */
970660bef33SPeter Maydell     pcdev = qdev_new(TYPE_NEXT_PC);
971b497f4a1SPeter Maydell     object_property_set_link(OBJECT(pcdev), "cpu", OBJECT(cpu), &error_abort);
972660bef33SPeter Maydell     sysbus_realize_and_unref(SYS_BUS_DEVICE(pcdev), &error_fatal);
973956a7811SThomas Huth 
974956a7811SThomas Huth     /* 64MB RAM starting at 0x04000000  */
97549b64ba9SIgor Mammedov     memory_region_add_subregion(sysmem, 0x04000000, machine->ram);
976956a7811SThomas Huth 
977956a7811SThomas Huth     /* Framebuffer */
9783e80f690SMarkus Armbruster     dev = qdev_new(TYPE_NEXTFB);
9793c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
980956a7811SThomas Huth     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000);
981956a7811SThomas Huth 
982956a7811SThomas Huth     /* MMIO */
98340831636SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000);
984956a7811SThomas Huth 
9851dc7aeaeSPeter Maydell     /* BMAP IO - acts as a catch-all for now */
9861dc7aeaeSPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000);
9871dc7aeaeSPeter Maydell 
988956a7811SThomas Huth     /* BMAP memory */
989956a7811SThomas Huth     memory_region_init_ram_shared_nomigrate(bmapm1, NULL, "next.bmapmem", 64,
990956a7811SThomas Huth                                             true, &error_fatal);
991956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x020c0000, bmapm1);
992956a7811SThomas Huth     /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */
993956a7811SThomas Huth     memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64);
994956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x820c0000, bmapm2);
995956a7811SThomas Huth 
996956a7811SThomas Huth     /* KBD */
9973e80f690SMarkus Armbruster     dev = qdev_new(TYPE_NEXTKBD);
9983c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
999956a7811SThomas Huth     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0200e000);
1000956a7811SThomas Huth 
1001956a7811SThomas Huth     /* Load ROM here */
1002956a7811SThomas Huth     /* still not sure if the rom should also be mapped at 0x0*/
1003956a7811SThomas Huth     memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal);
1004956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x01000000, rom);
1005956a7811SThomas Huth     if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) {
1006956a7811SThomas Huth         if (!qtest_enabled()) {
1007956a7811SThomas Huth             error_report("Failed to load firmware '%s'.", bios_name);
1008956a7811SThomas Huth         }
1009956a7811SThomas Huth     } else {
1010956a7811SThomas Huth         uint8_t *ptr;
1011956a7811SThomas Huth         /* Initial PC is always at offset 4 in firmware binaries */
1012956a7811SThomas Huth         ptr = rom_ptr(0x01000004, 4);
1013956a7811SThomas Huth         g_assert(ptr != NULL);
1014956a7811SThomas Huth         env->pc = ldl_p(ptr);
1015956a7811SThomas Huth         if (env->pc >= 0x01020000) {
1016956a7811SThomas Huth             error_report("'%s' does not seem to be a valid firmware image.",
1017956a7811SThomas Huth                          bios_name);
1018956a7811SThomas Huth             exit(1);
1019956a7811SThomas Huth         }
1020956a7811SThomas Huth     }
1021956a7811SThomas Huth 
1022956a7811SThomas Huth     /* Serial */
1023b497f4a1SPeter Maydell     next_escc_init(pcdev);
1024b17bed5bSThomas Huth 
1025b17bed5bSThomas Huth     /* TODO: */
1026956a7811SThomas Huth     /* Network */
1027956a7811SThomas Huth     /* SCSI */
1028956a7811SThomas Huth 
1029956a7811SThomas Huth     /* DMA */
1030956a7811SThomas Huth     memory_region_init_io(dmamem, NULL, &dma_ops, machine, "next.dma", 0x5000);
1031956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x02000000, dmamem);
1032956a7811SThomas Huth }
1033956a7811SThomas Huth 
1034956a7811SThomas Huth static void next_machine_class_init(ObjectClass *oc, void *data)
1035956a7811SThomas Huth {
1036956a7811SThomas Huth     MachineClass *mc = MACHINE_CLASS(oc);
1037956a7811SThomas Huth 
1038956a7811SThomas Huth     mc->desc = "NeXT Cube";
1039956a7811SThomas Huth     mc->init = next_cube_init;
1040956a7811SThomas Huth     mc->default_ram_size = RAM_SIZE;
104149b64ba9SIgor Mammedov     mc->default_ram_id = "next.ram";
1042956a7811SThomas Huth     mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
1043956a7811SThomas Huth }
1044956a7811SThomas Huth 
1045956a7811SThomas Huth static const TypeInfo next_typeinfo = {
1046956a7811SThomas Huth     .name = TYPE_NEXT_MACHINE,
1047956a7811SThomas Huth     .parent = TYPE_MACHINE,
1048956a7811SThomas Huth     .class_init = next_machine_class_init,
1049956a7811SThomas Huth     .instance_size = sizeof(NeXTState),
1050956a7811SThomas Huth };
1051956a7811SThomas Huth 
1052956a7811SThomas Huth static void next_register_type(void)
1053956a7811SThomas Huth {
1054956a7811SThomas Huth     type_register_static(&next_typeinfo);
1055660bef33SPeter Maydell     type_register_static(&next_pc_info);
1056956a7811SThomas Huth }
1057956a7811SThomas Huth 
1058956a7811SThomas Huth type_init(next_register_type)
1059