xref: /qemu/hw/m68k/next-cube.c (revision b2897f7e)
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;
931dc7aeaeSPeter Maydell     uint8_t scsi_csr_1;
941dc7aeaeSPeter Maydell     uint8_t scsi_csr_2;
95ac99317bSPeter Maydell     uint32_t int_mask;
96ac99317bSPeter Maydell     uint32_t int_status;
976f0face7SPeter Maydell 
986f0face7SPeter Maydell     NextRtc rtc;
99660bef33SPeter Maydell };
100660bef33SPeter Maydell 
101956a7811SThomas Huth /* Thanks to NeXT forums for this */
102956a7811SThomas Huth /*
103956a7811SThomas Huth static const uint8_t rtc_ram3[32] = {
104956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
105956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00,
106956a7811SThomas Huth     0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00,
107956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13
108956a7811SThomas Huth };
109956a7811SThomas Huth */
110956a7811SThomas Huth static const uint8_t rtc_ram2[32] = {
111956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00,
112956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00,
113956a7811SThomas Huth     0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
114956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e,
115956a7811SThomas Huth };
116956a7811SThomas Huth 
117956a7811SThomas Huth #define SCR2_RTCLK 0x2
118956a7811SThomas Huth #define SCR2_RTDATA 0x4
119956a7811SThomas Huth #define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10))
120956a7811SThomas Huth 
12140831636SPeter Maydell static void nextscr2_write(NeXTPC *s, uint32_t val, int size)
122956a7811SThomas Huth {
123956a7811SThomas Huth     static int led;
124956a7811SThomas Huth     static int phase;
125956a7811SThomas Huth     static uint8_t old_scr2;
126956a7811SThomas Huth     uint8_t scr2_2;
1276f0face7SPeter Maydell     NextRtc *rtc = &s->rtc;
128956a7811SThomas Huth 
129956a7811SThomas Huth     if (size == 4) {
130956a7811SThomas Huth         scr2_2 = (val >> 8) & 0xFF;
131956a7811SThomas Huth     } else {
132956a7811SThomas Huth         scr2_2 = val & 0xFF;
133956a7811SThomas Huth     }
134956a7811SThomas Huth 
135956a7811SThomas Huth     if (val & 0x1) {
136956a7811SThomas Huth         DPRINTF("fault!\n");
137956a7811SThomas Huth         led++;
138956a7811SThomas Huth         if (led == 10) {
139956a7811SThomas Huth             DPRINTF("LED flashing, possible fault!\n");
140956a7811SThomas Huth             led = 0;
141956a7811SThomas Huth         }
142956a7811SThomas Huth     }
143956a7811SThomas Huth 
144956a7811SThomas Huth     if (scr2_2 & 0x1) {
145956a7811SThomas Huth         /* DPRINTF("RTC %x phase %i\n", scr2_2, phase); */
146956a7811SThomas Huth         if (phase == -1) {
147956a7811SThomas Huth             phase = 0;
148956a7811SThomas Huth         }
149956a7811SThomas Huth         /* If we are in going down clock... do something */
150956a7811SThomas Huth         if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) &&
151956a7811SThomas Huth                 ((scr2_2 & SCR2_RTCLK) == 0)) {
152956a7811SThomas Huth             if (phase < 8) {
153cd4fc142SThomas Huth                 rtc->command = (rtc->command << 1) |
154956a7811SThomas Huth                                ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
155956a7811SThomas Huth             }
156956a7811SThomas Huth             if (phase >= 8 && phase < 16) {
157cd4fc142SThomas Huth                 rtc->value = (rtc->value << 1) |
158cd4fc142SThomas Huth                              ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
159956a7811SThomas Huth 
160956a7811SThomas Huth                 /* if we read RAM register, output RT_DATA bit */
161cd4fc142SThomas Huth                 if (rtc->command <= 0x1F) {
162956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
163cd4fc142SThomas Huth                     if (rtc->ram[rtc->command] & (0x80 >> (phase - 8))) {
164956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
165956a7811SThomas Huth                     }
166956a7811SThomas Huth 
167cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
168956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
169956a7811SThomas Huth                 }
170956a7811SThomas Huth                 /* read the status 0x30 */
171cd4fc142SThomas Huth                 if (rtc->command == 0x30) {
172956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
173956a7811SThomas Huth                     /* for now status = 0x98 (new rtc + FTU) */
174cd4fc142SThomas Huth                     if (rtc->status & (0x80 >> (phase - 8))) {
175956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
176956a7811SThomas Huth                     }
177956a7811SThomas Huth 
178cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
179956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
180956a7811SThomas Huth                 }
181956a7811SThomas Huth                 /* read the status 0x31 */
182cd4fc142SThomas Huth                 if (rtc->command == 0x31) {
183956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
184cd4fc142SThomas Huth                     if (rtc->control & (0x80 >> (phase - 8))) {
185956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
186956a7811SThomas Huth                     }
187cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
188956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
189956a7811SThomas Huth                 }
190956a7811SThomas Huth 
191cd4fc142SThomas Huth                 if ((rtc->command >= 0x20) && (rtc->command <= 0x2F)) {
192956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
193956a7811SThomas Huth                     /* for now 0x00 */
194956a7811SThomas Huth                     time_t time_h = time(NULL);
195956a7811SThomas Huth                     struct tm *info = localtime(&time_h);
196956a7811SThomas Huth                     int ret = 0;
197956a7811SThomas Huth 
198cd4fc142SThomas Huth                     switch (rtc->command) {
199956a7811SThomas Huth                     case 0x20:
200956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_sec);
201956a7811SThomas Huth                         break;
202956a7811SThomas Huth                     case 0x21:
203956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_min);
204956a7811SThomas Huth                         break;
205956a7811SThomas Huth                     case 0x22:
206956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_hour);
207956a7811SThomas Huth                         break;
208956a7811SThomas Huth                     case 0x24:
209956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_mday);
210956a7811SThomas Huth                         break;
211956a7811SThomas Huth                     case 0x25:
212956a7811SThomas Huth                         ret = SCR2_TOBCD((info->tm_mon + 1));
213956a7811SThomas Huth                         break;
214956a7811SThomas Huth                     case 0x26:
215956a7811SThomas Huth                         ret = SCR2_TOBCD((info->tm_year - 100));
216956a7811SThomas Huth                         break;
217956a7811SThomas Huth 
218956a7811SThomas Huth                     }
219956a7811SThomas Huth 
220956a7811SThomas Huth                     if (ret & (0x80 >> (phase - 8))) {
221956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
222956a7811SThomas Huth                     }
223cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
224956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
225956a7811SThomas Huth                 }
226956a7811SThomas Huth 
227956a7811SThomas Huth             }
228956a7811SThomas Huth 
229956a7811SThomas Huth             phase++;
230956a7811SThomas Huth             if (phase == 16) {
231cd4fc142SThomas Huth                 if (rtc->command >= 0x80 && rtc->command <= 0x9F) {
232cd4fc142SThomas Huth                     rtc->ram[rtc->command - 0x80] = rtc->value;
233956a7811SThomas Huth                 }
234956a7811SThomas Huth                 /* write to x30 register */
235cd4fc142SThomas Huth                 if (rtc->command == 0xB1) {
236956a7811SThomas Huth                     /* clear FTU */
237cd4fc142SThomas Huth                     if (rtc->value & 0x04) {
238cd4fc142SThomas Huth                         rtc->status = rtc->status & (~0x18);
239ac99317bSPeter Maydell                         s->int_status = s->int_status & (~0x04);
240956a7811SThomas Huth                     }
241956a7811SThomas Huth                 }
242956a7811SThomas Huth             }
243956a7811SThomas Huth         }
244956a7811SThomas Huth     } else {
245956a7811SThomas Huth         /* else end or abort */
246956a7811SThomas Huth         phase = -1;
247cd4fc142SThomas Huth         rtc->command = 0;
248cd4fc142SThomas Huth         rtc->value = 0;
249956a7811SThomas Huth     }
250956a7811SThomas Huth     s->scr2 = val & 0xFFFF00FF;
251956a7811SThomas Huth     s->scr2 |= scr2_2 << 8;
252956a7811SThomas Huth     old_scr2 = scr2_2;
253956a7811SThomas Huth }
254956a7811SThomas Huth 
25540831636SPeter Maydell static uint32_t mmio_readb(NeXTPC *s, hwaddr addr)
256956a7811SThomas Huth {
257956a7811SThomas Huth     switch (addr) {
258956a7811SThomas Huth     case 0xc000:
259956a7811SThomas Huth         return (s->scr1 >> 24) & 0xFF;
260956a7811SThomas Huth     case 0xc001:
261956a7811SThomas Huth         return (s->scr1 >> 16) & 0xFF;
262956a7811SThomas Huth     case 0xc002:
263956a7811SThomas Huth         return (s->scr1 >> 8)  & 0xFF;
264956a7811SThomas Huth     case 0xc003:
265956a7811SThomas Huth         return (s->scr1 >> 0)  & 0xFF;
266956a7811SThomas Huth 
267956a7811SThomas Huth     case 0xd000:
268956a7811SThomas Huth         return (s->scr2 >> 24) & 0xFF;
269956a7811SThomas Huth     case 0xd001:
270956a7811SThomas Huth         return (s->scr2 >> 16) & 0xFF;
271956a7811SThomas Huth     case 0xd002:
272956a7811SThomas Huth         return (s->scr2 >> 8)  & 0xFF;
273956a7811SThomas Huth     case 0xd003:
274956a7811SThomas Huth         return (s->scr2 >> 0)  & 0xFF;
275956a7811SThomas Huth     case 0x14020:
276956a7811SThomas Huth         DPRINTF("MMIO Read 0x4020\n");
277956a7811SThomas Huth         return 0x7f;
278956a7811SThomas Huth 
279956a7811SThomas Huth     default:
280956a7811SThomas Huth         DPRINTF("MMIO Read B @ %"HWADDR_PRIx"\n", addr);
281956a7811SThomas Huth         return 0x0;
282956a7811SThomas Huth     }
283956a7811SThomas Huth }
284956a7811SThomas Huth 
28540831636SPeter Maydell static uint32_t mmio_readw(NeXTPC *s, hwaddr addr)
286956a7811SThomas Huth {
287956a7811SThomas Huth     switch (addr) {
288956a7811SThomas Huth     default:
289956a7811SThomas Huth         DPRINTF("MMIO Read W @ %"HWADDR_PRIx"\n", addr);
290956a7811SThomas Huth         return 0x0;
291956a7811SThomas Huth     }
292956a7811SThomas Huth }
293956a7811SThomas Huth 
29440831636SPeter Maydell static uint32_t mmio_readl(NeXTPC *s, hwaddr addr)
295956a7811SThomas Huth {
296956a7811SThomas Huth     switch (addr) {
297956a7811SThomas Huth     case 0x7000:
298ac99317bSPeter Maydell         /* DPRINTF("Read INT status: %x\n", s->int_status); */
299ac99317bSPeter Maydell         return s->int_status;
300956a7811SThomas Huth 
301956a7811SThomas Huth     case 0x7800:
302ac99317bSPeter Maydell         DPRINTF("MMIO Read INT mask: %x\n", s->int_mask);
303ac99317bSPeter Maydell         return s->int_mask;
304956a7811SThomas Huth 
305956a7811SThomas Huth     case 0xc000:
306956a7811SThomas Huth         return s->scr1;
307956a7811SThomas Huth 
308956a7811SThomas Huth     case 0xd000:
309956a7811SThomas Huth         return s->scr2;
310956a7811SThomas Huth 
311956a7811SThomas Huth     default:
312956a7811SThomas Huth         DPRINTF("MMIO Read L @ %"HWADDR_PRIx"\n", addr);
313956a7811SThomas Huth         return 0x0;
314956a7811SThomas Huth     }
315956a7811SThomas Huth }
316956a7811SThomas Huth 
31740831636SPeter Maydell static void mmio_writeb(NeXTPC *s, hwaddr addr, uint32_t val)
318956a7811SThomas Huth {
319956a7811SThomas Huth     switch (addr) {
320956a7811SThomas Huth     case 0xd003:
321956a7811SThomas Huth         nextscr2_write(s, val, 1);
322956a7811SThomas Huth         break;
323956a7811SThomas Huth     default:
324956a7811SThomas Huth         DPRINTF("MMIO Write B @ %x with %x\n", (unsigned int)addr, val);
325956a7811SThomas Huth     }
326956a7811SThomas Huth 
327956a7811SThomas Huth }
328956a7811SThomas Huth 
32940831636SPeter Maydell static void mmio_writew(NeXTPC *s, hwaddr addr, uint32_t val)
330956a7811SThomas Huth {
331956a7811SThomas Huth     DPRINTF("MMIO Write W\n");
332956a7811SThomas Huth }
333956a7811SThomas Huth 
33440831636SPeter Maydell static void mmio_writel(NeXTPC *s, hwaddr addr, uint32_t val)
335956a7811SThomas Huth {
336956a7811SThomas Huth     switch (addr) {
337956a7811SThomas Huth     case 0x7000:
338ac99317bSPeter Maydell         DPRINTF("INT Status old: %x new: %x\n", s->int_status, val);
339ac99317bSPeter Maydell         s->int_status = val;
340956a7811SThomas Huth         break;
341956a7811SThomas Huth     case 0x7800:
342ac99317bSPeter Maydell         DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, val);
343ac99317bSPeter Maydell         s->int_mask  = val;
344956a7811SThomas Huth         break;
345956a7811SThomas Huth     case 0xc000:
346956a7811SThomas Huth         DPRINTF("SCR1 Write: %x\n", val);
347956a7811SThomas Huth         break;
348956a7811SThomas Huth     case 0xd000:
349956a7811SThomas Huth         nextscr2_write(s, val, 4);
350956a7811SThomas Huth         break;
351956a7811SThomas Huth 
352956a7811SThomas Huth     default:
353956a7811SThomas Huth         DPRINTF("MMIO Write l @ %x with %x\n", (unsigned int)addr, val);
354956a7811SThomas Huth     }
355956a7811SThomas Huth }
356956a7811SThomas Huth 
357956a7811SThomas Huth static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size)
358956a7811SThomas Huth {
35940831636SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
360956a7811SThomas Huth 
361956a7811SThomas Huth     switch (size) {
362956a7811SThomas Huth     case 1:
36340831636SPeter Maydell         return mmio_readb(s, addr);
364956a7811SThomas Huth     case 2:
36540831636SPeter Maydell         return mmio_readw(s, addr);
366956a7811SThomas Huth     case 4:
36740831636SPeter Maydell         return mmio_readl(s, addr);
368956a7811SThomas Huth     default:
369956a7811SThomas Huth         g_assert_not_reached();
370956a7811SThomas Huth     }
371956a7811SThomas Huth }
372956a7811SThomas Huth 
373956a7811SThomas Huth static void mmio_writefn(void *opaque, hwaddr addr, uint64_t value,
374956a7811SThomas Huth                          unsigned size)
375956a7811SThomas Huth {
37640831636SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
377956a7811SThomas Huth 
378956a7811SThomas Huth     switch (size) {
379956a7811SThomas Huth     case 1:
38040831636SPeter Maydell         mmio_writeb(s, addr, value);
381956a7811SThomas Huth         break;
382956a7811SThomas Huth     case 2:
38340831636SPeter Maydell         mmio_writew(s, addr, value);
384956a7811SThomas Huth         break;
385956a7811SThomas Huth     case 4:
38640831636SPeter Maydell         mmio_writel(s, addr, value);
387956a7811SThomas Huth         break;
388956a7811SThomas Huth     default:
389956a7811SThomas Huth         g_assert_not_reached();
390956a7811SThomas Huth     }
391956a7811SThomas Huth }
392956a7811SThomas Huth 
393956a7811SThomas Huth static const MemoryRegionOps mmio_ops = {
394956a7811SThomas Huth     .read = mmio_readfn,
395956a7811SThomas Huth     .write = mmio_writefn,
396956a7811SThomas Huth     .valid.min_access_size = 1,
397956a7811SThomas Huth     .valid.max_access_size = 4,
398956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
399956a7811SThomas Huth };
400956a7811SThomas Huth 
4011dc7aeaeSPeter Maydell static uint32_t scr_readb(NeXTPC *s, hwaddr addr)
402956a7811SThomas Huth {
403956a7811SThomas Huth     switch (addr) {
404956a7811SThomas Huth     case 0x14108:
405956a7811SThomas Huth         DPRINTF("FD read @ %x\n", (unsigned int)addr);
406956a7811SThomas Huth         return 0x40 | 0x04 | 0x2 | 0x1;
407956a7811SThomas Huth     case 0x14020:
408956a7811SThomas Huth         DPRINTF("SCSI 4020  STATUS READ %X\n", s->scsi_csr_1);
409956a7811SThomas Huth         return s->scsi_csr_1;
410956a7811SThomas Huth 
411956a7811SThomas Huth     case 0x14021:
412956a7811SThomas Huth         DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2);
413956a7811SThomas Huth         return 0x40;
414956a7811SThomas Huth 
415956a7811SThomas Huth     /*
416956a7811SThomas Huth      * These 4 registers are the hardware timer, not sure which register
417956a7811SThomas Huth      * is the latch instead of data, but no problems so far
418956a7811SThomas Huth      */
419956a7811SThomas Huth     case 0x1a000:
420956a7811SThomas Huth         return 0xff & (clock() >> 24);
421956a7811SThomas Huth     case 0x1a001:
422956a7811SThomas Huth         return 0xff & (clock() >> 16);
423956a7811SThomas Huth     case 0x1a002:
424956a7811SThomas Huth         return 0xff & (clock() >> 8);
425956a7811SThomas Huth     case 0x1a003:
426956a7811SThomas Huth         /* Hack: We need to have this change consistently to make it work */
427956a7811SThomas Huth         return 0xFF & clock();
428956a7811SThomas Huth 
429956a7811SThomas Huth     default:
430956a7811SThomas Huth         DPRINTF("BMAP Read B @ %x\n", (unsigned int)addr);
431956a7811SThomas Huth         return 0;
432956a7811SThomas Huth     }
433956a7811SThomas Huth }
434956a7811SThomas Huth 
4351dc7aeaeSPeter Maydell static uint32_t scr_readw(NeXTPC *s, hwaddr addr)
436956a7811SThomas Huth {
437956a7811SThomas Huth     DPRINTF("BMAP Read W @ %x\n", (unsigned int)addr);
438956a7811SThomas Huth     return 0;
439956a7811SThomas Huth }
440956a7811SThomas Huth 
4411dc7aeaeSPeter Maydell static uint32_t scr_readl(NeXTPC *s, hwaddr addr)
442956a7811SThomas Huth {
443956a7811SThomas Huth     DPRINTF("BMAP Read L @ %x\n", (unsigned int)addr);
444956a7811SThomas Huth     return 0;
445956a7811SThomas Huth }
446956a7811SThomas Huth 
447956a7811SThomas Huth #define SCSICSR_ENABLE  0x01
448956a7811SThomas Huth #define SCSICSR_RESET   0x02  /* reset scsi dma */
449956a7811SThomas Huth #define SCSICSR_FIFOFL  0x04
450956a7811SThomas Huth #define SCSICSR_DMADIR  0x08  /* if set, scsi to mem */
451956a7811SThomas Huth #define SCSICSR_CPUDMA  0x10  /* if set, dma enabled */
452956a7811SThomas Huth #define SCSICSR_INTMASK 0x20  /* if set, interrupt enabled */
453956a7811SThomas Huth 
4541dc7aeaeSPeter Maydell static void scr_writeb(NeXTPC *s, hwaddr addr, uint32_t value)
455956a7811SThomas Huth {
456956a7811SThomas Huth     switch (addr) {
457956a7811SThomas Huth     case 0x14108:
458956a7811SThomas Huth         DPRINTF("FDCSR Write: %x\n", value);
459956a7811SThomas Huth 
460956a7811SThomas Huth         if (value == 0x0) {
461956a7811SThomas Huth             /* qemu_irq_raise(s->fd_irq[0]); */
462956a7811SThomas Huth         }
463956a7811SThomas Huth         break;
464956a7811SThomas Huth     case 0x14020: /* SCSI Control Register */
465956a7811SThomas Huth         if (value & SCSICSR_FIFOFL) {
466956a7811SThomas Huth             DPRINTF("SCSICSR FIFO Flush\n");
467956a7811SThomas Huth             /* will have to add another irq to the esp if this is needed */
468956a7811SThomas Huth             /* esp_puflush_fifo(esp_g); */
469956a7811SThomas Huth             /* qemu_irq_pulse(s->scsi_dma); */
470956a7811SThomas Huth         }
471956a7811SThomas Huth 
472956a7811SThomas Huth         if (value & SCSICSR_ENABLE) {
473956a7811SThomas Huth             DPRINTF("SCSICSR Enable\n");
474956a7811SThomas Huth             /*
475956a7811SThomas Huth              * qemu_irq_raise(s->scsi_dma);
476956a7811SThomas Huth              * s->scsi_csr_1 = 0xc0;
477956a7811SThomas Huth              * s->scsi_csr_1 |= 0x1;
478956a7811SThomas Huth              * qemu_irq_pulse(s->scsi_dma);
479956a7811SThomas Huth              */
480956a7811SThomas Huth         }
481956a7811SThomas Huth         /*
482956a7811SThomas Huth          * else
483956a7811SThomas Huth          *     s->scsi_csr_1 &= ~SCSICSR_ENABLE;
484956a7811SThomas Huth          */
485956a7811SThomas Huth 
486956a7811SThomas Huth         if (value & SCSICSR_RESET) {
487956a7811SThomas Huth             DPRINTF("SCSICSR Reset\n");
488956a7811SThomas Huth             /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */
489956a7811SThomas Huth             /* qemu_irq_raise(s->scsi_reset); */
490956a7811SThomas Huth             /* s->scsi_csr_1 &= ~(SCSICSR_INTMASK |0x80|0x1); */
491956a7811SThomas Huth 
492956a7811SThomas Huth         }
493956a7811SThomas Huth         if (value & SCSICSR_DMADIR) {
494956a7811SThomas Huth             DPRINTF("SCSICSR DMAdir\n");
495956a7811SThomas Huth         }
496956a7811SThomas Huth         if (value & SCSICSR_CPUDMA) {
497956a7811SThomas Huth             DPRINTF("SCSICSR CPUDMA\n");
498956a7811SThomas Huth             /* qemu_irq_raise(s->scsi_dma); */
499956a7811SThomas Huth 
500ac99317bSPeter Maydell             s->int_status |= 0x4000000;
501956a7811SThomas Huth         } else {
502ac99317bSPeter Maydell             s->int_status &= ~(0x4000000);
503956a7811SThomas Huth         }
504956a7811SThomas Huth         if (value & SCSICSR_INTMASK) {
505956a7811SThomas Huth             DPRINTF("SCSICSR INTMASK\n");
506956a7811SThomas Huth             /*
507956a7811SThomas Huth              * int_mask &= ~0x1000;
508956a7811SThomas Huth              * s->scsi_csr_1 |= value;
509956a7811SThomas Huth              * s->scsi_csr_1 &= ~SCSICSR_INTMASK;
510956a7811SThomas Huth              * if (s->scsi_queued) {
511956a7811SThomas Huth              *     s->scsi_queued = 0;
512956a7811SThomas Huth              *     next_irq(s, NEXT_SCSI_I, level);
513956a7811SThomas Huth              * }
514956a7811SThomas Huth              */
515956a7811SThomas Huth         } else {
516956a7811SThomas Huth             /* int_mask |= 0x1000; */
517956a7811SThomas Huth         }
518956a7811SThomas Huth         if (value & 0x80) {
519956a7811SThomas Huth             /* int_mask |= 0x1000; */
520956a7811SThomas Huth             /* s->scsi_csr_1 |= 0x80; */
521956a7811SThomas Huth         }
522956a7811SThomas Huth         DPRINTF("SCSICSR Write: %x\n", value);
523956a7811SThomas Huth         /* s->scsi_csr_1 = value; */
524956a7811SThomas Huth         return;
525956a7811SThomas Huth     /* Hardware timer latch - not implemented yet */
526956a7811SThomas Huth     case 0x1a000:
527956a7811SThomas Huth     default:
528956a7811SThomas Huth         DPRINTF("BMAP Write B @ %x with %x\n", (unsigned int)addr, value);
529956a7811SThomas Huth     }
530956a7811SThomas Huth }
531956a7811SThomas Huth 
5321dc7aeaeSPeter Maydell static void scr_writew(NeXTPC *s, hwaddr addr, uint32_t value)
533956a7811SThomas Huth {
534956a7811SThomas Huth     DPRINTF("BMAP Write W @ %x with %x\n", (unsigned int)addr, value);
535956a7811SThomas Huth }
536956a7811SThomas Huth 
5371dc7aeaeSPeter Maydell static void scr_writel(NeXTPC *s, hwaddr addr, uint32_t value)
538956a7811SThomas Huth {
539956a7811SThomas Huth     DPRINTF("BMAP Write L @ %x with %x\n", (unsigned int)addr, value);
540956a7811SThomas Huth }
541956a7811SThomas Huth 
542956a7811SThomas Huth static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size)
543956a7811SThomas Huth {
5441dc7aeaeSPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
545956a7811SThomas Huth 
546956a7811SThomas Huth     switch (size) {
547956a7811SThomas Huth     case 1:
5481dc7aeaeSPeter Maydell         return scr_readb(s, addr);
549956a7811SThomas Huth     case 2:
5501dc7aeaeSPeter Maydell         return scr_readw(s, addr);
551956a7811SThomas Huth     case 4:
5521dc7aeaeSPeter Maydell         return scr_readl(s, addr);
553956a7811SThomas Huth     default:
554956a7811SThomas Huth         g_assert_not_reached();
555956a7811SThomas Huth     }
556956a7811SThomas Huth }
557956a7811SThomas Huth 
558956a7811SThomas Huth static void scr_writefn(void *opaque, hwaddr addr, uint64_t value,
559956a7811SThomas Huth                         unsigned size)
560956a7811SThomas Huth {
5611dc7aeaeSPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
562956a7811SThomas Huth 
563956a7811SThomas Huth     switch (size) {
564956a7811SThomas Huth     case 1:
5651dc7aeaeSPeter Maydell         scr_writeb(s, addr, value);
566956a7811SThomas Huth         break;
567956a7811SThomas Huth     case 2:
5681dc7aeaeSPeter Maydell         scr_writew(s, addr, value);
569956a7811SThomas Huth         break;
570956a7811SThomas Huth     case 4:
5711dc7aeaeSPeter Maydell         scr_writel(s, addr, value);
572956a7811SThomas Huth         break;
573956a7811SThomas Huth     default:
574956a7811SThomas Huth         g_assert_not_reached();
575956a7811SThomas Huth     }
576956a7811SThomas Huth }
577956a7811SThomas Huth 
578956a7811SThomas Huth static const MemoryRegionOps scr_ops = {
579956a7811SThomas Huth     .read = scr_readfn,
580956a7811SThomas Huth     .write = scr_writefn,
581956a7811SThomas Huth     .valid.min_access_size = 1,
582956a7811SThomas Huth     .valid.max_access_size = 4,
583956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
584956a7811SThomas Huth };
585956a7811SThomas Huth 
586956a7811SThomas Huth #define NEXTDMA_SCSI(x)      (0x10 + x)
587956a7811SThomas Huth #define NEXTDMA_FD(x)        (0x10 + x)
588956a7811SThomas Huth #define NEXTDMA_ENTX(x)      (0x110 + x)
589956a7811SThomas Huth #define NEXTDMA_ENRX(x)      (0x150 + x)
590956a7811SThomas Huth #define NEXTDMA_CSR          0x0
591956a7811SThomas Huth #define NEXTDMA_NEXT         0x4000
592956a7811SThomas Huth #define NEXTDMA_LIMIT        0x4004
593956a7811SThomas Huth #define NEXTDMA_START        0x4008
594956a7811SThomas Huth #define NEXTDMA_STOP         0x400c
595956a7811SThomas Huth #define NEXTDMA_NEXT_INIT    0x4200
596956a7811SThomas Huth #define NEXTDMA_SIZE         0x4204
597956a7811SThomas Huth 
598956a7811SThomas Huth static void dma_writel(void *opaque, hwaddr addr, uint64_t value,
599956a7811SThomas Huth                        unsigned int size)
600956a7811SThomas Huth {
601956a7811SThomas Huth     NeXTState *next_state = NEXT_MACHINE(opaque);
602956a7811SThomas Huth 
603956a7811SThomas Huth     switch (addr) {
604956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_CSR):
605956a7811SThomas Huth         if (value & DMA_DEV2M) {
606956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M;
607956a7811SThomas Huth         }
608956a7811SThomas Huth 
609956a7811SThomas Huth         if (value & DMA_SETENABLE) {
610956a7811SThomas Huth             /* DPRINTF("SCSI DMA ENABLE\n"); */
611956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE;
612956a7811SThomas Huth         }
613956a7811SThomas Huth         if (value & DMA_SETSUPDATE) {
614956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE;
615956a7811SThomas Huth         }
616956a7811SThomas Huth         if (value & DMA_CLRCOMPLETE) {
617956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE;
618956a7811SThomas Huth         }
619956a7811SThomas Huth 
620956a7811SThomas Huth         if (value & DMA_RESET) {
621956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
622956a7811SThomas Huth                                                   DMA_ENABLE | DMA_DEV2M);
623956a7811SThomas Huth         }
624956a7811SThomas Huth         /* DPRINTF("RXCSR \tWrite: %x\n",value); */
625956a7811SThomas Huth         break;
626956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
627956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].next_initbuf = value;
628956a7811SThomas Huth         break;
629956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
630956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].next = value;
631956a7811SThomas Huth         break;
632956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
633956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].limit = value;
634956a7811SThomas Huth         break;
635956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_CSR):
636956a7811SThomas Huth         if (value & DMA_DEV2M) {
637956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M;
638956a7811SThomas Huth         }
639956a7811SThomas Huth         if (value & DMA_SETENABLE) {
640956a7811SThomas Huth             /* DPRINTF("SCSI DMA ENABLE\n"); */
641956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE;
642956a7811SThomas Huth         }
643956a7811SThomas Huth         if (value & DMA_SETSUPDATE) {
644956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE;
645956a7811SThomas Huth         }
646956a7811SThomas Huth         if (value & DMA_CLRCOMPLETE) {
647956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE;
648956a7811SThomas Huth         }
649956a7811SThomas Huth 
650956a7811SThomas Huth         if (value & DMA_RESET) {
651956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
652956a7811SThomas Huth                                                   DMA_ENABLE | DMA_DEV2M);
653956a7811SThomas Huth             /* DPRINTF("SCSI DMA RESET\n"); */
654956a7811SThomas Huth         }
655956a7811SThomas Huth         /* DPRINTF("RXCSR \tWrite: %x\n",value); */
656956a7811SThomas Huth         break;
657956a7811SThomas Huth 
658956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT):
659956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].next = value;
660956a7811SThomas Huth         break;
661956a7811SThomas Huth 
662956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
663956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].limit = value;
664956a7811SThomas Huth         break;
665956a7811SThomas Huth 
666956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
667956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].start = value;
668956a7811SThomas Huth         break;
669956a7811SThomas Huth 
670956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
671956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].stop = value;
672956a7811SThomas Huth         break;
673956a7811SThomas Huth 
674956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
675956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].next_initbuf = value;
676956a7811SThomas Huth         break;
677956a7811SThomas Huth 
678956a7811SThomas Huth     default:
679956a7811SThomas Huth         DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value);
680956a7811SThomas Huth     }
681956a7811SThomas Huth }
682956a7811SThomas Huth 
683956a7811SThomas Huth static uint64_t dma_readl(void *opaque, hwaddr addr, unsigned int size)
684956a7811SThomas Huth {
685956a7811SThomas Huth     NeXTState *next_state = NEXT_MACHINE(opaque);
686956a7811SThomas Huth 
687956a7811SThomas Huth     switch (addr) {
688956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_CSR):
689956a7811SThomas Huth         DPRINTF("SCSI DMA CSR READ\n");
690956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].csr;
691956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_CSR):
692956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].csr;
693956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
694956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].next_initbuf;
695956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
696956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].next;
697956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
698956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].limit;
699956a7811SThomas Huth 
700956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT):
701956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].next;
702956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
703956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].next_initbuf;
704956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
705956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].limit;
706956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
707956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].start;
708956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
709956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].stop;
710956a7811SThomas Huth 
711956a7811SThomas Huth     default:
712956a7811SThomas Huth         DPRINTF("DMA read @ %x\n", (unsigned int)addr);
713956a7811SThomas Huth         return 0;
714956a7811SThomas Huth     }
715956a7811SThomas Huth 
716956a7811SThomas Huth     /*
717956a7811SThomas Huth      * once the csr's are done, subtract 0x3FEC from the addr, and that will
718956a7811SThomas Huth      * normalize the upper registers
719956a7811SThomas Huth      */
720956a7811SThomas Huth }
721956a7811SThomas Huth 
722956a7811SThomas Huth static const MemoryRegionOps dma_ops = {
723956a7811SThomas Huth     .read = dma_readl,
724956a7811SThomas Huth     .write = dma_writel,
725956a7811SThomas Huth     .impl.min_access_size = 4,
726956a7811SThomas Huth     .valid.min_access_size = 4,
727956a7811SThomas Huth     .valid.max_access_size = 4,
728956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
729956a7811SThomas Huth };
730956a7811SThomas Huth 
731c8abcc87SPeter Maydell static void next_irq(void *opaque, int number, int level)
732956a7811SThomas Huth {
733b497f4a1SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
734b497f4a1SPeter Maydell     M68kCPU *cpu = s->cpu;
735956a7811SThomas Huth     int shift = 0;
736956a7811SThomas Huth 
7378b81968cSMichael Tokarev     /* first switch sets interrupt status */
738956a7811SThomas Huth     /* DPRINTF("IRQ %i\n",number); */
739956a7811SThomas Huth     switch (number) {
740956a7811SThomas Huth     /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
741956a7811SThomas Huth     case NEXT_FD_I:
7425012a894SPhilippe Mathieu-Daudé         shift = 7;
743956a7811SThomas Huth         break;
744956a7811SThomas Huth     case NEXT_KBD_I:
745956a7811SThomas Huth         shift = 3;
746956a7811SThomas Huth         break;
747956a7811SThomas Huth     case NEXT_PWR_I:
748956a7811SThomas Huth         shift = 2;
749956a7811SThomas Huth         break;
750956a7811SThomas Huth     case NEXT_ENRX_I:
751956a7811SThomas Huth         shift = 9;
752956a7811SThomas Huth         break;
753956a7811SThomas Huth     case NEXT_ENTX_I:
754956a7811SThomas Huth         shift = 10;
755956a7811SThomas Huth         break;
756956a7811SThomas Huth     case NEXT_SCSI_I:
757956a7811SThomas Huth         shift = 12;
758956a7811SThomas Huth         break;
759956a7811SThomas Huth     case NEXT_CLK_I:
760956a7811SThomas Huth         shift = 5;
761956a7811SThomas Huth         break;
762956a7811SThomas Huth 
763956a7811SThomas Huth     /* level 5 - scc (serial) */
764956a7811SThomas Huth     case NEXT_SCC_I:
765956a7811SThomas Huth         shift = 17;
766956a7811SThomas Huth         break;
767956a7811SThomas Huth 
768956a7811SThomas Huth     /* level 6 - audio etherrx/tx dma */
769956a7811SThomas Huth     case NEXT_ENTX_DMA_I:
770956a7811SThomas Huth         shift = 28;
771956a7811SThomas Huth         break;
772956a7811SThomas Huth     case NEXT_ENRX_DMA_I:
773956a7811SThomas Huth         shift = 27;
774956a7811SThomas Huth         break;
775956a7811SThomas Huth     case NEXT_SCSI_DMA_I:
776956a7811SThomas Huth         shift = 26;
777956a7811SThomas Huth         break;
778956a7811SThomas Huth     case NEXT_SND_I:
779956a7811SThomas Huth         shift = 23;
780956a7811SThomas Huth         break;
781956a7811SThomas Huth     case NEXT_SCC_DMA_I:
782956a7811SThomas Huth         shift = 21;
783956a7811SThomas Huth         break;
784956a7811SThomas Huth 
785956a7811SThomas Huth     }
786956a7811SThomas Huth     /*
787956a7811SThomas Huth      * this HAS to be wrong, the interrupt handlers in mach and together
788956a7811SThomas Huth      * int_status and int_mask and return if there is a hit
789956a7811SThomas Huth      */
790ac99317bSPeter Maydell     if (s->int_mask & (1 << shift)) {
791956a7811SThomas Huth         DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc);
792956a7811SThomas Huth         /* return; */
793956a7811SThomas Huth     }
794956a7811SThomas Huth 
795956a7811SThomas Huth     /* second switch triggers the correct interrupt */
796956a7811SThomas Huth     if (level) {
797ac99317bSPeter Maydell         s->int_status |= 1 << shift;
798956a7811SThomas Huth 
799956a7811SThomas Huth         switch (number) {
800956a7811SThomas Huth         /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
801956a7811SThomas Huth         case NEXT_FD_I:
802956a7811SThomas Huth         case NEXT_KBD_I:
803956a7811SThomas Huth         case NEXT_PWR_I:
804956a7811SThomas Huth         case NEXT_ENRX_I:
805956a7811SThomas Huth         case NEXT_ENTX_I:
806956a7811SThomas Huth         case NEXT_SCSI_I:
807956a7811SThomas Huth         case NEXT_CLK_I:
808956a7811SThomas Huth             m68k_set_irq_level(cpu, 3, 27);
809956a7811SThomas Huth             break;
810956a7811SThomas Huth 
811956a7811SThomas Huth         /* level 5 - scc (serial) */
812956a7811SThomas Huth         case NEXT_SCC_I:
813956a7811SThomas Huth             m68k_set_irq_level(cpu, 5, 29);
814956a7811SThomas Huth             break;
815956a7811SThomas Huth 
816956a7811SThomas Huth         /* level 6 - audio etherrx/tx dma */
817956a7811SThomas Huth         case NEXT_ENTX_DMA_I:
818956a7811SThomas Huth         case NEXT_ENRX_DMA_I:
819956a7811SThomas Huth         case NEXT_SCSI_DMA_I:
820956a7811SThomas Huth         case NEXT_SND_I:
821956a7811SThomas Huth         case NEXT_SCC_DMA_I:
822956a7811SThomas Huth             m68k_set_irq_level(cpu, 6, 30);
823956a7811SThomas Huth             break;
824956a7811SThomas Huth         }
825956a7811SThomas Huth     } else {
826ac99317bSPeter Maydell         s->int_status &= ~(1 << shift);
827956a7811SThomas Huth         cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
828956a7811SThomas Huth     }
829956a7811SThomas Huth }
830956a7811SThomas Huth 
831b497f4a1SPeter Maydell static void next_escc_init(DeviceState *pcdev)
832b17bed5bSThomas Huth {
833b17bed5bSThomas Huth     DeviceState *dev;
834b17bed5bSThomas Huth     SysBusDevice *s;
835b17bed5bSThomas Huth 
8363e80f690SMarkus Armbruster     dev = qdev_new(TYPE_ESCC);
837b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "disabled", 0);
838b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "frequency", 9600 * 384);
839b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "it_shift", 0);
840b17bed5bSThomas Huth     qdev_prop_set_bit(dev, "bit_swap", true);
841b17bed5bSThomas Huth     qdev_prop_set_chr(dev, "chrB", serial_hd(1));
842b17bed5bSThomas Huth     qdev_prop_set_chr(dev, "chrA", serial_hd(0));
843b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
844b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
845b17bed5bSThomas Huth 
846b17bed5bSThomas Huth     s = SYS_BUS_DEVICE(dev);
8473c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
848d9cd4039SPeter Maydell     sysbus_connect_irq(s, 0, qdev_get_gpio_in(pcdev, NEXT_SCC_I));
849d9cd4039SPeter Maydell     sysbus_connect_irq(s, 1, qdev_get_gpio_in(pcdev, NEXT_SCC_DMA_I));
850b17bed5bSThomas Huth     sysbus_mmio_map(s, 0, 0x2118000);
851b17bed5bSThomas Huth }
852b17bed5bSThomas Huth 
853660bef33SPeter Maydell static void next_pc_reset(DeviceState *dev)
854660bef33SPeter Maydell {
85540831636SPeter Maydell     NeXTPC *s = NEXT_PC(dev);
85640831636SPeter Maydell 
85740831636SPeter Maydell     /* Set internal registers to initial values */
85840831636SPeter Maydell     /*     0x0000XX00 << vital bits */
85940831636SPeter Maydell     s->scr1 = 0x00011102;
86040831636SPeter Maydell     s->scr2 = 0x00ff0c80;
8616f0face7SPeter Maydell 
8626f0face7SPeter Maydell     s->rtc.status = 0x90;
8636f0face7SPeter Maydell 
8646f0face7SPeter Maydell     /* Load RTC RAM - TODO: provide possibility to load contents from file */
8656f0face7SPeter Maydell     memcpy(s->rtc.ram, rtc_ram2, 32);
866660bef33SPeter Maydell }
867660bef33SPeter Maydell 
868660bef33SPeter Maydell static void next_pc_realize(DeviceState *dev, Error **errp)
869660bef33SPeter Maydell {
87040831636SPeter Maydell     NeXTPC *s = NEXT_PC(dev);
87140831636SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
87240831636SPeter Maydell 
873d9cd4039SPeter Maydell     qdev_init_gpio_in(dev, next_irq, NEXT_NUM_IRQS);
874d9cd4039SPeter Maydell 
87540831636SPeter Maydell     memory_region_init_io(&s->mmiomem, OBJECT(s), &mmio_ops, s,
87640831636SPeter Maydell                           "next.mmio", 0xD0000);
8771dc7aeaeSPeter Maydell     memory_region_init_io(&s->scrmem, OBJECT(s), &scr_ops, s,
8781dc7aeaeSPeter Maydell                           "next.scr", 0x20000);
87940831636SPeter Maydell     sysbus_init_mmio(sbd, &s->mmiomem);
8801dc7aeaeSPeter Maydell     sysbus_init_mmio(sbd, &s->scrmem);
881660bef33SPeter Maydell }
882660bef33SPeter Maydell 
883b497f4a1SPeter Maydell /*
884b497f4a1SPeter Maydell  * If the m68k CPU implemented its inbound irq lines as GPIO lines
885b497f4a1SPeter Maydell  * rather than via the m68k_set_irq_level() function we would not need
886b497f4a1SPeter Maydell  * this cpu link property and could instead provide outbound IRQ lines
887b497f4a1SPeter Maydell  * that the board could wire up to the CPU.
888b497f4a1SPeter Maydell  */
889b497f4a1SPeter Maydell static Property next_pc_properties[] = {
890b497f4a1SPeter Maydell     DEFINE_PROP_LINK("cpu", NeXTPC, cpu, TYPE_M68K_CPU, M68kCPU *),
891b497f4a1SPeter Maydell     DEFINE_PROP_END_OF_LIST(),
892b497f4a1SPeter Maydell };
893b497f4a1SPeter Maydell 
89475ca77ecSPeter Maydell static const VMStateDescription next_rtc_vmstate = {
89575ca77ecSPeter Maydell     .name = "next-rtc",
89675ca77ecSPeter Maydell     .version_id = 1,
89775ca77ecSPeter Maydell     .minimum_version_id = 1,
89875ca77ecSPeter Maydell     .fields = (VMStateField[]) {
89975ca77ecSPeter Maydell         VMSTATE_UINT8_ARRAY(ram, NextRtc, 32),
90075ca77ecSPeter Maydell         VMSTATE_UINT8(command, NextRtc),
90175ca77ecSPeter Maydell         VMSTATE_UINT8(value, NextRtc),
90275ca77ecSPeter Maydell         VMSTATE_UINT8(status, NextRtc),
90375ca77ecSPeter Maydell         VMSTATE_UINT8(control, NextRtc),
90475ca77ecSPeter Maydell         VMSTATE_UINT8(retval, NextRtc),
90575ca77ecSPeter Maydell         VMSTATE_END_OF_LIST()
90675ca77ecSPeter Maydell     },
90775ca77ecSPeter Maydell };
90875ca77ecSPeter Maydell 
90975ca77ecSPeter Maydell static const VMStateDescription next_pc_vmstate = {
91075ca77ecSPeter Maydell     .name = "next-pc",
91175ca77ecSPeter Maydell     .version_id = 1,
91275ca77ecSPeter Maydell     .minimum_version_id = 1,
91375ca77ecSPeter Maydell     .fields = (VMStateField[]) {
91475ca77ecSPeter Maydell         VMSTATE_UINT32(scr1, NeXTPC),
91575ca77ecSPeter Maydell         VMSTATE_UINT32(scr2, NeXTPC),
91675ca77ecSPeter Maydell         VMSTATE_UINT32(int_mask, NeXTPC),
91775ca77ecSPeter Maydell         VMSTATE_UINT32(int_status, NeXTPC),
91875ca77ecSPeter Maydell         VMSTATE_UINT8(scsi_csr_1, NeXTPC),
91975ca77ecSPeter Maydell         VMSTATE_UINT8(scsi_csr_2, NeXTPC),
92075ca77ecSPeter Maydell         VMSTATE_STRUCT(rtc, NeXTPC, 0, next_rtc_vmstate, NextRtc),
92175ca77ecSPeter Maydell         VMSTATE_END_OF_LIST()
92275ca77ecSPeter Maydell     },
92375ca77ecSPeter Maydell };
92475ca77ecSPeter Maydell 
925660bef33SPeter Maydell static void next_pc_class_init(ObjectClass *klass, void *data)
926660bef33SPeter Maydell {
927660bef33SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
928660bef33SPeter Maydell 
929660bef33SPeter Maydell     dc->desc = "NeXT Peripheral Controller";
930660bef33SPeter Maydell     dc->realize = next_pc_realize;
931660bef33SPeter Maydell     dc->reset = next_pc_reset;
932b497f4a1SPeter Maydell     device_class_set_props(dc, next_pc_properties);
93375ca77ecSPeter Maydell     dc->vmsd = &next_pc_vmstate;
934660bef33SPeter Maydell }
935660bef33SPeter Maydell 
936660bef33SPeter Maydell static const TypeInfo next_pc_info = {
937660bef33SPeter Maydell     .name = TYPE_NEXT_PC,
938660bef33SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
939660bef33SPeter Maydell     .instance_size = sizeof(NeXTPC),
940660bef33SPeter Maydell     .class_init = next_pc_class_init,
941660bef33SPeter Maydell };
942660bef33SPeter Maydell 
943956a7811SThomas Huth static void next_cube_init(MachineState *machine)
944956a7811SThomas Huth {
945956a7811SThomas Huth     M68kCPU *cpu;
946956a7811SThomas Huth     CPUM68KState *env;
947956a7811SThomas Huth     MemoryRegion *rom = g_new(MemoryRegion, 1);
948956a7811SThomas Huth     MemoryRegion *dmamem = g_new(MemoryRegion, 1);
949956a7811SThomas Huth     MemoryRegion *bmapm1 = g_new(MemoryRegion, 1);
950956a7811SThomas Huth     MemoryRegion *bmapm2 = g_new(MemoryRegion, 1);
951956a7811SThomas Huth     MemoryRegion *sysmem = get_system_memory();
9521684273cSPaolo Bonzini     const char *bios_name = machine->firmware ?: ROM_FILE;
953660bef33SPeter Maydell     DeviceState *pcdev;
954956a7811SThomas Huth 
955956a7811SThomas Huth     /* Initialize the cpu core */
956956a7811SThomas Huth     cpu = M68K_CPU(cpu_create(machine->cpu_type));
957956a7811SThomas Huth     if (!cpu) {
958956a7811SThomas Huth         error_report("Unable to find m68k CPU definition");
959956a7811SThomas Huth         exit(1);
960956a7811SThomas Huth     }
961956a7811SThomas Huth     env = &cpu->env;
962956a7811SThomas Huth 
963956a7811SThomas Huth     /* Initialize CPU registers.  */
964956a7811SThomas Huth     env->vbr = 0;
965956a7811SThomas Huth     env->sr  = 0x2700;
966956a7811SThomas Huth 
967660bef33SPeter Maydell     /* Peripheral Controller */
968660bef33SPeter Maydell     pcdev = qdev_new(TYPE_NEXT_PC);
969b497f4a1SPeter Maydell     object_property_set_link(OBJECT(pcdev), "cpu", OBJECT(cpu), &error_abort);
970660bef33SPeter Maydell     sysbus_realize_and_unref(SYS_BUS_DEVICE(pcdev), &error_fatal);
971956a7811SThomas Huth 
972956a7811SThomas Huth     /* 64MB RAM starting at 0x04000000  */
97349b64ba9SIgor Mammedov     memory_region_add_subregion(sysmem, 0x04000000, machine->ram);
974956a7811SThomas Huth 
975956a7811SThomas Huth     /* Framebuffer */
976b2897f7eSPhilippe Mathieu-Daudé     sysbus_create_simple(TYPE_NEXTFB, 0x0B000000, NULL);
977956a7811SThomas Huth 
978956a7811SThomas Huth     /* MMIO */
97940831636SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000);
980956a7811SThomas Huth 
9811dc7aeaeSPeter Maydell     /* BMAP IO - acts as a catch-all for now */
9821dc7aeaeSPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000);
9831dc7aeaeSPeter Maydell 
984956a7811SThomas Huth     /* BMAP memory */
9857f863cbaSDavid Hildenbrand     memory_region_init_ram_flags_nomigrate(bmapm1, NULL, "next.bmapmem", 64,
9867f863cbaSDavid Hildenbrand                                            RAM_SHARED, &error_fatal);
987956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x020c0000, bmapm1);
988956a7811SThomas Huth     /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */
989956a7811SThomas Huth     memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64);
990956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x820c0000, bmapm2);
991956a7811SThomas Huth 
992956a7811SThomas Huth     /* KBD */
993b2897f7eSPhilippe Mathieu-Daudé     sysbus_create_simple(TYPE_NEXTKBD, 0x0200e000, NULL);
994956a7811SThomas Huth 
995956a7811SThomas Huth     /* Load ROM here */
996956a7811SThomas Huth     /* still not sure if the rom should also be mapped at 0x0*/
997956a7811SThomas Huth     memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal);
998956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x01000000, rom);
999956a7811SThomas Huth     if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) {
1000956a7811SThomas Huth         if (!qtest_enabled()) {
1001956a7811SThomas Huth             error_report("Failed to load firmware '%s'.", bios_name);
1002956a7811SThomas Huth         }
1003956a7811SThomas Huth     } else {
1004956a7811SThomas Huth         uint8_t *ptr;
1005956a7811SThomas Huth         /* Initial PC is always at offset 4 in firmware binaries */
1006956a7811SThomas Huth         ptr = rom_ptr(0x01000004, 4);
1007956a7811SThomas Huth         g_assert(ptr != NULL);
1008956a7811SThomas Huth         env->pc = ldl_p(ptr);
1009956a7811SThomas Huth         if (env->pc >= 0x01020000) {
1010956a7811SThomas Huth             error_report("'%s' does not seem to be a valid firmware image.",
1011956a7811SThomas Huth                          bios_name);
1012956a7811SThomas Huth             exit(1);
1013956a7811SThomas Huth         }
1014956a7811SThomas Huth     }
1015956a7811SThomas Huth 
1016956a7811SThomas Huth     /* Serial */
1017b497f4a1SPeter Maydell     next_escc_init(pcdev);
1018b17bed5bSThomas Huth 
1019b17bed5bSThomas Huth     /* TODO: */
1020956a7811SThomas Huth     /* Network */
1021956a7811SThomas Huth     /* SCSI */
1022956a7811SThomas Huth 
1023956a7811SThomas Huth     /* DMA */
1024956a7811SThomas Huth     memory_region_init_io(dmamem, NULL, &dma_ops, machine, "next.dma", 0x5000);
1025956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x02000000, dmamem);
1026956a7811SThomas Huth }
1027956a7811SThomas Huth 
1028956a7811SThomas Huth static void next_machine_class_init(ObjectClass *oc, void *data)
1029956a7811SThomas Huth {
1030956a7811SThomas Huth     MachineClass *mc = MACHINE_CLASS(oc);
1031956a7811SThomas Huth 
1032956a7811SThomas Huth     mc->desc = "NeXT Cube";
1033956a7811SThomas Huth     mc->init = next_cube_init;
1034956a7811SThomas Huth     mc->default_ram_size = RAM_SIZE;
103549b64ba9SIgor Mammedov     mc->default_ram_id = "next.ram";
1036956a7811SThomas Huth     mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
1037956a7811SThomas Huth }
1038956a7811SThomas Huth 
1039956a7811SThomas Huth static const TypeInfo next_typeinfo = {
1040956a7811SThomas Huth     .name = TYPE_NEXT_MACHINE,
1041956a7811SThomas Huth     .parent = TYPE_MACHINE,
1042956a7811SThomas Huth     .class_init = next_machine_class_init,
1043956a7811SThomas Huth     .instance_size = sizeof(NeXTState),
1044956a7811SThomas Huth };
1045956a7811SThomas Huth 
1046956a7811SThomas Huth static void next_register_type(void)
1047956a7811SThomas Huth {
1048956a7811SThomas Huth     type_register_static(&next_typeinfo);
1049660bef33SPeter Maydell     type_register_static(&next_pc_info);
1050956a7811SThomas Huth }
1051956a7811SThomas Huth 
1052956a7811SThomas Huth type_init(next_register_type)
1053