xref: /qemu/hw/m68k/next-cube.c (revision ac99317b)
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"
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];
77956a7811SThomas Huth     qemu_irq *scsi_irq;
78956a7811SThomas Huth     qemu_irq scsi_dma;
79956a7811SThomas Huth     qemu_irq scsi_reset;
80956a7811SThomas Huth     qemu_irq *fd_irq;
81956a7811SThomas Huth 
82cd4fc142SThomas Huth     NextRtc rtc;
83db1015e9SEduardo Habkost };
84956a7811SThomas Huth 
85660bef33SPeter Maydell #define TYPE_NEXT_PC "next-pc"
86660bef33SPeter Maydell OBJECT_DECLARE_SIMPLE_TYPE(NeXTPC, NEXT_PC)
87660bef33SPeter Maydell 
88660bef33SPeter Maydell /* NeXT Peripheral Controller */
89660bef33SPeter Maydell struct NeXTPC {
90660bef33SPeter Maydell     SysBusDevice parent_obj;
91660bef33SPeter Maydell 
92660bef33SPeter Maydell     /* Temporary until all functionality has been moved into this device */
93660bef33SPeter Maydell     NeXTState *ns;
9440831636SPeter Maydell 
95b497f4a1SPeter Maydell     M68kCPU *cpu;
96b497f4a1SPeter Maydell 
9740831636SPeter Maydell     MemoryRegion mmiomem;
981dc7aeaeSPeter Maydell     MemoryRegion scrmem;
9940831636SPeter Maydell 
10040831636SPeter Maydell     uint32_t scr1;
10140831636SPeter Maydell     uint32_t scr2;
1021dc7aeaeSPeter Maydell     uint8_t scsi_csr_1;
1031dc7aeaeSPeter Maydell     uint8_t scsi_csr_2;
104*ac99317bSPeter Maydell     uint32_t int_mask;
105*ac99317bSPeter Maydell     uint32_t int_status;
106660bef33SPeter Maydell };
107660bef33SPeter Maydell 
108956a7811SThomas Huth /* Thanks to NeXT forums for this */
109956a7811SThomas Huth /*
110956a7811SThomas Huth static const uint8_t rtc_ram3[32] = {
111956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
112956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00,
113956a7811SThomas Huth     0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00,
114956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13
115956a7811SThomas Huth };
116956a7811SThomas Huth */
117956a7811SThomas Huth static const uint8_t rtc_ram2[32] = {
118956a7811SThomas Huth     0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00,
119956a7811SThomas Huth     0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00,
120956a7811SThomas Huth     0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
121956a7811SThomas Huth     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e,
122956a7811SThomas Huth };
123956a7811SThomas Huth 
124956a7811SThomas Huth #define SCR2_RTCLK 0x2
125956a7811SThomas Huth #define SCR2_RTDATA 0x4
126956a7811SThomas Huth #define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10))
127956a7811SThomas Huth 
12840831636SPeter Maydell static void nextscr2_write(NeXTPC *s, uint32_t val, int size)
129956a7811SThomas Huth {
130956a7811SThomas Huth     static int led;
131956a7811SThomas Huth     static int phase;
132956a7811SThomas Huth     static uint8_t old_scr2;
133956a7811SThomas Huth     uint8_t scr2_2;
13440831636SPeter Maydell     NextRtc *rtc = &s->ns->rtc;
135956a7811SThomas Huth 
136956a7811SThomas Huth     if (size == 4) {
137956a7811SThomas Huth         scr2_2 = (val >> 8) & 0xFF;
138956a7811SThomas Huth     } else {
139956a7811SThomas Huth         scr2_2 = val & 0xFF;
140956a7811SThomas Huth     }
141956a7811SThomas Huth 
142956a7811SThomas Huth     if (val & 0x1) {
143956a7811SThomas Huth         DPRINTF("fault!\n");
144956a7811SThomas Huth         led++;
145956a7811SThomas Huth         if (led == 10) {
146956a7811SThomas Huth             DPRINTF("LED flashing, possible fault!\n");
147956a7811SThomas Huth             led = 0;
148956a7811SThomas Huth         }
149956a7811SThomas Huth     }
150956a7811SThomas Huth 
151956a7811SThomas Huth     if (scr2_2 & 0x1) {
152956a7811SThomas Huth         /* DPRINTF("RTC %x phase %i\n", scr2_2, phase); */
153956a7811SThomas Huth         if (phase == -1) {
154956a7811SThomas Huth             phase = 0;
155956a7811SThomas Huth         }
156956a7811SThomas Huth         /* If we are in going down clock... do something */
157956a7811SThomas Huth         if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) &&
158956a7811SThomas Huth                 ((scr2_2 & SCR2_RTCLK) == 0)) {
159956a7811SThomas Huth             if (phase < 8) {
160cd4fc142SThomas Huth                 rtc->command = (rtc->command << 1) |
161956a7811SThomas Huth                                ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
162956a7811SThomas Huth             }
163956a7811SThomas Huth             if (phase >= 8 && phase < 16) {
164cd4fc142SThomas Huth                 rtc->value = (rtc->value << 1) |
165cd4fc142SThomas Huth                              ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
166956a7811SThomas Huth 
167956a7811SThomas Huth                 /* if we read RAM register, output RT_DATA bit */
168cd4fc142SThomas Huth                 if (rtc->command <= 0x1F) {
169956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
170cd4fc142SThomas Huth                     if (rtc->ram[rtc->command] & (0x80 >> (phase - 8))) {
171956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
172956a7811SThomas Huth                     }
173956a7811SThomas Huth 
174cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
175956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
176956a7811SThomas Huth                 }
177956a7811SThomas Huth                 /* read the status 0x30 */
178cd4fc142SThomas Huth                 if (rtc->command == 0x30) {
179956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
180956a7811SThomas Huth                     /* for now status = 0x98 (new rtc + FTU) */
181cd4fc142SThomas Huth                     if (rtc->status & (0x80 >> (phase - 8))) {
182956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
183956a7811SThomas Huth                     }
184956a7811SThomas Huth 
185cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
186956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
187956a7811SThomas Huth                 }
188956a7811SThomas Huth                 /* read the status 0x31 */
189cd4fc142SThomas Huth                 if (rtc->command == 0x31) {
190956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
191cd4fc142SThomas Huth                     if (rtc->control & (0x80 >> (phase - 8))) {
192956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
193956a7811SThomas Huth                     }
194cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
195956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
196956a7811SThomas Huth                 }
197956a7811SThomas Huth 
198cd4fc142SThomas Huth                 if ((rtc->command >= 0x20) && (rtc->command <= 0x2F)) {
199956a7811SThomas Huth                     scr2_2 = scr2_2 & (~SCR2_RTDATA);
200956a7811SThomas Huth                     /* for now 0x00 */
201956a7811SThomas Huth                     time_t time_h = time(NULL);
202956a7811SThomas Huth                     struct tm *info = localtime(&time_h);
203956a7811SThomas Huth                     int ret = 0;
204956a7811SThomas Huth 
205cd4fc142SThomas Huth                     switch (rtc->command) {
206956a7811SThomas Huth                     case 0x20:
207956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_sec);
208956a7811SThomas Huth                         break;
209956a7811SThomas Huth                     case 0x21:
210956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_min);
211956a7811SThomas Huth                         break;
212956a7811SThomas Huth                     case 0x22:
213956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_hour);
214956a7811SThomas Huth                         break;
215956a7811SThomas Huth                     case 0x24:
216956a7811SThomas Huth                         ret = SCR2_TOBCD(info->tm_mday);
217956a7811SThomas Huth                         break;
218956a7811SThomas Huth                     case 0x25:
219956a7811SThomas Huth                         ret = SCR2_TOBCD((info->tm_mon + 1));
220956a7811SThomas Huth                         break;
221956a7811SThomas Huth                     case 0x26:
222956a7811SThomas Huth                         ret = SCR2_TOBCD((info->tm_year - 100));
223956a7811SThomas Huth                         break;
224956a7811SThomas Huth 
225956a7811SThomas Huth                     }
226956a7811SThomas Huth 
227956a7811SThomas Huth                     if (ret & (0x80 >> (phase - 8))) {
228956a7811SThomas Huth                         scr2_2 |= SCR2_RTDATA;
229956a7811SThomas Huth                     }
230cd4fc142SThomas Huth                     rtc->retval = (rtc->retval << 1) |
231956a7811SThomas Huth                                   ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
232956a7811SThomas Huth                 }
233956a7811SThomas Huth 
234956a7811SThomas Huth             }
235956a7811SThomas Huth 
236956a7811SThomas Huth             phase++;
237956a7811SThomas Huth             if (phase == 16) {
238cd4fc142SThomas Huth                 if (rtc->command >= 0x80 && rtc->command <= 0x9F) {
239cd4fc142SThomas Huth                     rtc->ram[rtc->command - 0x80] = rtc->value;
240956a7811SThomas Huth                 }
241956a7811SThomas Huth                 /* write to x30 register */
242cd4fc142SThomas Huth                 if (rtc->command == 0xB1) {
243956a7811SThomas Huth                     /* clear FTU */
244cd4fc142SThomas Huth                     if (rtc->value & 0x04) {
245cd4fc142SThomas Huth                         rtc->status = rtc->status & (~0x18);
246*ac99317bSPeter Maydell                         s->int_status = s->int_status & (~0x04);
247956a7811SThomas Huth                     }
248956a7811SThomas Huth                 }
249956a7811SThomas Huth             }
250956a7811SThomas Huth         }
251956a7811SThomas Huth     } else {
252956a7811SThomas Huth         /* else end or abort */
253956a7811SThomas Huth         phase = -1;
254cd4fc142SThomas Huth         rtc->command = 0;
255cd4fc142SThomas Huth         rtc->value = 0;
256956a7811SThomas Huth     }
257956a7811SThomas Huth     s->scr2 = val & 0xFFFF00FF;
258956a7811SThomas Huth     s->scr2 |= scr2_2 << 8;
259956a7811SThomas Huth     old_scr2 = scr2_2;
260956a7811SThomas Huth }
261956a7811SThomas Huth 
26240831636SPeter Maydell static uint32_t mmio_readb(NeXTPC *s, hwaddr addr)
263956a7811SThomas Huth {
264956a7811SThomas Huth     switch (addr) {
265956a7811SThomas Huth     case 0xc000:
266956a7811SThomas Huth         return (s->scr1 >> 24) & 0xFF;
267956a7811SThomas Huth     case 0xc001:
268956a7811SThomas Huth         return (s->scr1 >> 16) & 0xFF;
269956a7811SThomas Huth     case 0xc002:
270956a7811SThomas Huth         return (s->scr1 >> 8)  & 0xFF;
271956a7811SThomas Huth     case 0xc003:
272956a7811SThomas Huth         return (s->scr1 >> 0)  & 0xFF;
273956a7811SThomas Huth 
274956a7811SThomas Huth     case 0xd000:
275956a7811SThomas Huth         return (s->scr2 >> 24) & 0xFF;
276956a7811SThomas Huth     case 0xd001:
277956a7811SThomas Huth         return (s->scr2 >> 16) & 0xFF;
278956a7811SThomas Huth     case 0xd002:
279956a7811SThomas Huth         return (s->scr2 >> 8)  & 0xFF;
280956a7811SThomas Huth     case 0xd003:
281956a7811SThomas Huth         return (s->scr2 >> 0)  & 0xFF;
282956a7811SThomas Huth     case 0x14020:
283956a7811SThomas Huth         DPRINTF("MMIO Read 0x4020\n");
284956a7811SThomas Huth         return 0x7f;
285956a7811SThomas Huth 
286956a7811SThomas Huth     default:
287956a7811SThomas Huth         DPRINTF("MMIO Read B @ %"HWADDR_PRIx"\n", addr);
288956a7811SThomas Huth         return 0x0;
289956a7811SThomas Huth     }
290956a7811SThomas Huth }
291956a7811SThomas Huth 
29240831636SPeter Maydell static uint32_t mmio_readw(NeXTPC *s, hwaddr addr)
293956a7811SThomas Huth {
294956a7811SThomas Huth     switch (addr) {
295956a7811SThomas Huth     default:
296956a7811SThomas Huth         DPRINTF("MMIO Read W @ %"HWADDR_PRIx"\n", addr);
297956a7811SThomas Huth         return 0x0;
298956a7811SThomas Huth     }
299956a7811SThomas Huth }
300956a7811SThomas Huth 
30140831636SPeter Maydell static uint32_t mmio_readl(NeXTPC *s, hwaddr addr)
302956a7811SThomas Huth {
303956a7811SThomas Huth     switch (addr) {
304956a7811SThomas Huth     case 0x7000:
305*ac99317bSPeter Maydell         /* DPRINTF("Read INT status: %x\n", s->int_status); */
306*ac99317bSPeter Maydell         return s->int_status;
307956a7811SThomas Huth 
308956a7811SThomas Huth     case 0x7800:
309*ac99317bSPeter Maydell         DPRINTF("MMIO Read INT mask: %x\n", s->int_mask);
310*ac99317bSPeter Maydell         return s->int_mask;
311956a7811SThomas Huth 
312956a7811SThomas Huth     case 0xc000:
313956a7811SThomas Huth         return s->scr1;
314956a7811SThomas Huth 
315956a7811SThomas Huth     case 0xd000:
316956a7811SThomas Huth         return s->scr2;
317956a7811SThomas Huth 
318956a7811SThomas Huth     default:
319956a7811SThomas Huth         DPRINTF("MMIO Read L @ %"HWADDR_PRIx"\n", addr);
320956a7811SThomas Huth         return 0x0;
321956a7811SThomas Huth     }
322956a7811SThomas Huth }
323956a7811SThomas Huth 
32440831636SPeter Maydell static void mmio_writeb(NeXTPC *s, hwaddr addr, uint32_t val)
325956a7811SThomas Huth {
326956a7811SThomas Huth     switch (addr) {
327956a7811SThomas Huth     case 0xd003:
328956a7811SThomas Huth         nextscr2_write(s, val, 1);
329956a7811SThomas Huth         break;
330956a7811SThomas Huth     default:
331956a7811SThomas Huth         DPRINTF("MMIO Write B @ %x with %x\n", (unsigned int)addr, val);
332956a7811SThomas Huth     }
333956a7811SThomas Huth 
334956a7811SThomas Huth }
335956a7811SThomas Huth 
33640831636SPeter Maydell static void mmio_writew(NeXTPC *s, hwaddr addr, uint32_t val)
337956a7811SThomas Huth {
338956a7811SThomas Huth     DPRINTF("MMIO Write W\n");
339956a7811SThomas Huth }
340956a7811SThomas Huth 
34140831636SPeter Maydell static void mmio_writel(NeXTPC *s, hwaddr addr, uint32_t val)
342956a7811SThomas Huth {
343956a7811SThomas Huth     switch (addr) {
344956a7811SThomas Huth     case 0x7000:
345*ac99317bSPeter Maydell         DPRINTF("INT Status old: %x new: %x\n", s->int_status, val);
346*ac99317bSPeter Maydell         s->int_status = val;
347956a7811SThomas Huth         break;
348956a7811SThomas Huth     case 0x7800:
349*ac99317bSPeter Maydell         DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, val);
350*ac99317bSPeter Maydell         s->int_mask  = val;
351956a7811SThomas Huth         break;
352956a7811SThomas Huth     case 0xc000:
353956a7811SThomas Huth         DPRINTF("SCR1 Write: %x\n", val);
354956a7811SThomas Huth         break;
355956a7811SThomas Huth     case 0xd000:
356956a7811SThomas Huth         nextscr2_write(s, val, 4);
357956a7811SThomas Huth         break;
358956a7811SThomas Huth 
359956a7811SThomas Huth     default:
360956a7811SThomas Huth         DPRINTF("MMIO Write l @ %x with %x\n", (unsigned int)addr, val);
361956a7811SThomas Huth     }
362956a7811SThomas Huth }
363956a7811SThomas Huth 
364956a7811SThomas Huth static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size)
365956a7811SThomas Huth {
36640831636SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
367956a7811SThomas Huth 
368956a7811SThomas Huth     switch (size) {
369956a7811SThomas Huth     case 1:
37040831636SPeter Maydell         return mmio_readb(s, addr);
371956a7811SThomas Huth     case 2:
37240831636SPeter Maydell         return mmio_readw(s, addr);
373956a7811SThomas Huth     case 4:
37440831636SPeter Maydell         return mmio_readl(s, addr);
375956a7811SThomas Huth     default:
376956a7811SThomas Huth         g_assert_not_reached();
377956a7811SThomas Huth     }
378956a7811SThomas Huth }
379956a7811SThomas Huth 
380956a7811SThomas Huth static void mmio_writefn(void *opaque, hwaddr addr, uint64_t value,
381956a7811SThomas Huth                          unsigned size)
382956a7811SThomas Huth {
38340831636SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
384956a7811SThomas Huth 
385956a7811SThomas Huth     switch (size) {
386956a7811SThomas Huth     case 1:
38740831636SPeter Maydell         mmio_writeb(s, addr, value);
388956a7811SThomas Huth         break;
389956a7811SThomas Huth     case 2:
39040831636SPeter Maydell         mmio_writew(s, addr, value);
391956a7811SThomas Huth         break;
392956a7811SThomas Huth     case 4:
39340831636SPeter Maydell         mmio_writel(s, addr, value);
394956a7811SThomas Huth         break;
395956a7811SThomas Huth     default:
396956a7811SThomas Huth         g_assert_not_reached();
397956a7811SThomas Huth     }
398956a7811SThomas Huth }
399956a7811SThomas Huth 
400956a7811SThomas Huth static const MemoryRegionOps mmio_ops = {
401956a7811SThomas Huth     .read = mmio_readfn,
402956a7811SThomas Huth     .write = mmio_writefn,
403956a7811SThomas Huth     .valid.min_access_size = 1,
404956a7811SThomas Huth     .valid.max_access_size = 4,
405956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
406956a7811SThomas Huth };
407956a7811SThomas Huth 
4081dc7aeaeSPeter Maydell static uint32_t scr_readb(NeXTPC *s, hwaddr addr)
409956a7811SThomas Huth {
410956a7811SThomas Huth     switch (addr) {
411956a7811SThomas Huth     case 0x14108:
412956a7811SThomas Huth         DPRINTF("FD read @ %x\n", (unsigned int)addr);
413956a7811SThomas Huth         return 0x40 | 0x04 | 0x2 | 0x1;
414956a7811SThomas Huth     case 0x14020:
415956a7811SThomas Huth         DPRINTF("SCSI 4020  STATUS READ %X\n", s->scsi_csr_1);
416956a7811SThomas Huth         return s->scsi_csr_1;
417956a7811SThomas Huth 
418956a7811SThomas Huth     case 0x14021:
419956a7811SThomas Huth         DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2);
420956a7811SThomas Huth         return 0x40;
421956a7811SThomas Huth 
422956a7811SThomas Huth     /*
423956a7811SThomas Huth      * These 4 registers are the hardware timer, not sure which register
424956a7811SThomas Huth      * is the latch instead of data, but no problems so far
425956a7811SThomas Huth      */
426956a7811SThomas Huth     case 0x1a000:
427956a7811SThomas Huth         return 0xff & (clock() >> 24);
428956a7811SThomas Huth     case 0x1a001:
429956a7811SThomas Huth         return 0xff & (clock() >> 16);
430956a7811SThomas Huth     case 0x1a002:
431956a7811SThomas Huth         return 0xff & (clock() >> 8);
432956a7811SThomas Huth     case 0x1a003:
433956a7811SThomas Huth         /* Hack: We need to have this change consistently to make it work */
434956a7811SThomas Huth         return 0xFF & clock();
435956a7811SThomas Huth 
436956a7811SThomas Huth     default:
437956a7811SThomas Huth         DPRINTF("BMAP Read B @ %x\n", (unsigned int)addr);
438956a7811SThomas Huth         return 0;
439956a7811SThomas Huth     }
440956a7811SThomas Huth }
441956a7811SThomas Huth 
4421dc7aeaeSPeter Maydell static uint32_t scr_readw(NeXTPC *s, hwaddr addr)
443956a7811SThomas Huth {
444956a7811SThomas Huth     DPRINTF("BMAP Read W @ %x\n", (unsigned int)addr);
445956a7811SThomas Huth     return 0;
446956a7811SThomas Huth }
447956a7811SThomas Huth 
4481dc7aeaeSPeter Maydell static uint32_t scr_readl(NeXTPC *s, hwaddr addr)
449956a7811SThomas Huth {
450956a7811SThomas Huth     DPRINTF("BMAP Read L @ %x\n", (unsigned int)addr);
451956a7811SThomas Huth     return 0;
452956a7811SThomas Huth }
453956a7811SThomas Huth 
454956a7811SThomas Huth #define SCSICSR_ENABLE  0x01
455956a7811SThomas Huth #define SCSICSR_RESET   0x02  /* reset scsi dma */
456956a7811SThomas Huth #define SCSICSR_FIFOFL  0x04
457956a7811SThomas Huth #define SCSICSR_DMADIR  0x08  /* if set, scsi to mem */
458956a7811SThomas Huth #define SCSICSR_CPUDMA  0x10  /* if set, dma enabled */
459956a7811SThomas Huth #define SCSICSR_INTMASK 0x20  /* if set, interrupt enabled */
460956a7811SThomas Huth 
4611dc7aeaeSPeter Maydell static void scr_writeb(NeXTPC *s, hwaddr addr, uint32_t value)
462956a7811SThomas Huth {
463956a7811SThomas Huth     switch (addr) {
464956a7811SThomas Huth     case 0x14108:
465956a7811SThomas Huth         DPRINTF("FDCSR Write: %x\n", value);
466956a7811SThomas Huth 
467956a7811SThomas Huth         if (value == 0x0) {
468956a7811SThomas Huth             /* qemu_irq_raise(s->fd_irq[0]); */
469956a7811SThomas Huth         }
470956a7811SThomas Huth         break;
471956a7811SThomas Huth     case 0x14020: /* SCSI Control Register */
472956a7811SThomas Huth         if (value & SCSICSR_FIFOFL) {
473956a7811SThomas Huth             DPRINTF("SCSICSR FIFO Flush\n");
474956a7811SThomas Huth             /* will have to add another irq to the esp if this is needed */
475956a7811SThomas Huth             /* esp_puflush_fifo(esp_g); */
476956a7811SThomas Huth             /* qemu_irq_pulse(s->scsi_dma); */
477956a7811SThomas Huth         }
478956a7811SThomas Huth 
479956a7811SThomas Huth         if (value & SCSICSR_ENABLE) {
480956a7811SThomas Huth             DPRINTF("SCSICSR Enable\n");
481956a7811SThomas Huth             /*
482956a7811SThomas Huth              * qemu_irq_raise(s->scsi_dma);
483956a7811SThomas Huth              * s->scsi_csr_1 = 0xc0;
484956a7811SThomas Huth              * s->scsi_csr_1 |= 0x1;
485956a7811SThomas Huth              * qemu_irq_pulse(s->scsi_dma);
486956a7811SThomas Huth              */
487956a7811SThomas Huth         }
488956a7811SThomas Huth         /*
489956a7811SThomas Huth          * else
490956a7811SThomas Huth          *     s->scsi_csr_1 &= ~SCSICSR_ENABLE;
491956a7811SThomas Huth          */
492956a7811SThomas Huth 
493956a7811SThomas Huth         if (value & SCSICSR_RESET) {
494956a7811SThomas Huth             DPRINTF("SCSICSR Reset\n");
495956a7811SThomas Huth             /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */
496956a7811SThomas Huth             /* qemu_irq_raise(s->scsi_reset); */
497956a7811SThomas Huth             /* s->scsi_csr_1 &= ~(SCSICSR_INTMASK |0x80|0x1); */
498956a7811SThomas Huth 
499956a7811SThomas Huth         }
500956a7811SThomas Huth         if (value & SCSICSR_DMADIR) {
501956a7811SThomas Huth             DPRINTF("SCSICSR DMAdir\n");
502956a7811SThomas Huth         }
503956a7811SThomas Huth         if (value & SCSICSR_CPUDMA) {
504956a7811SThomas Huth             DPRINTF("SCSICSR CPUDMA\n");
505956a7811SThomas Huth             /* qemu_irq_raise(s->scsi_dma); */
506956a7811SThomas Huth 
507*ac99317bSPeter Maydell             s->int_status |= 0x4000000;
508956a7811SThomas Huth         } else {
509*ac99317bSPeter Maydell             s->int_status &= ~(0x4000000);
510956a7811SThomas Huth         }
511956a7811SThomas Huth         if (value & SCSICSR_INTMASK) {
512956a7811SThomas Huth             DPRINTF("SCSICSR INTMASK\n");
513956a7811SThomas Huth             /*
514956a7811SThomas Huth              * int_mask &= ~0x1000;
515956a7811SThomas Huth              * s->scsi_csr_1 |= value;
516956a7811SThomas Huth              * s->scsi_csr_1 &= ~SCSICSR_INTMASK;
517956a7811SThomas Huth              * if (s->scsi_queued) {
518956a7811SThomas Huth              *     s->scsi_queued = 0;
519956a7811SThomas Huth              *     next_irq(s, NEXT_SCSI_I, level);
520956a7811SThomas Huth              * }
521956a7811SThomas Huth              */
522956a7811SThomas Huth         } else {
523956a7811SThomas Huth             /* int_mask |= 0x1000; */
524956a7811SThomas Huth         }
525956a7811SThomas Huth         if (value & 0x80) {
526956a7811SThomas Huth             /* int_mask |= 0x1000; */
527956a7811SThomas Huth             /* s->scsi_csr_1 |= 0x80; */
528956a7811SThomas Huth         }
529956a7811SThomas Huth         DPRINTF("SCSICSR Write: %x\n", value);
530956a7811SThomas Huth         /* s->scsi_csr_1 = value; */
531956a7811SThomas Huth         return;
532956a7811SThomas Huth     /* Hardware timer latch - not implemented yet */
533956a7811SThomas Huth     case 0x1a000:
534956a7811SThomas Huth     default:
535956a7811SThomas Huth         DPRINTF("BMAP Write B @ %x with %x\n", (unsigned int)addr, value);
536956a7811SThomas Huth     }
537956a7811SThomas Huth }
538956a7811SThomas Huth 
5391dc7aeaeSPeter Maydell static void scr_writew(NeXTPC *s, hwaddr addr, uint32_t value)
540956a7811SThomas Huth {
541956a7811SThomas Huth     DPRINTF("BMAP Write W @ %x with %x\n", (unsigned int)addr, value);
542956a7811SThomas Huth }
543956a7811SThomas Huth 
5441dc7aeaeSPeter Maydell static void scr_writel(NeXTPC *s, hwaddr addr, uint32_t value)
545956a7811SThomas Huth {
546956a7811SThomas Huth     DPRINTF("BMAP Write L @ %x with %x\n", (unsigned int)addr, value);
547956a7811SThomas Huth }
548956a7811SThomas Huth 
549956a7811SThomas Huth static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size)
550956a7811SThomas Huth {
5511dc7aeaeSPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
552956a7811SThomas Huth 
553956a7811SThomas Huth     switch (size) {
554956a7811SThomas Huth     case 1:
5551dc7aeaeSPeter Maydell         return scr_readb(s, addr);
556956a7811SThomas Huth     case 2:
5571dc7aeaeSPeter Maydell         return scr_readw(s, addr);
558956a7811SThomas Huth     case 4:
5591dc7aeaeSPeter Maydell         return scr_readl(s, addr);
560956a7811SThomas Huth     default:
561956a7811SThomas Huth         g_assert_not_reached();
562956a7811SThomas Huth     }
563956a7811SThomas Huth }
564956a7811SThomas Huth 
565956a7811SThomas Huth static void scr_writefn(void *opaque, hwaddr addr, uint64_t value,
566956a7811SThomas Huth                         unsigned size)
567956a7811SThomas Huth {
5681dc7aeaeSPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
569956a7811SThomas Huth 
570956a7811SThomas Huth     switch (size) {
571956a7811SThomas Huth     case 1:
5721dc7aeaeSPeter Maydell         scr_writeb(s, addr, value);
573956a7811SThomas Huth         break;
574956a7811SThomas Huth     case 2:
5751dc7aeaeSPeter Maydell         scr_writew(s, addr, value);
576956a7811SThomas Huth         break;
577956a7811SThomas Huth     case 4:
5781dc7aeaeSPeter Maydell         scr_writel(s, addr, value);
579956a7811SThomas Huth         break;
580956a7811SThomas Huth     default:
581956a7811SThomas Huth         g_assert_not_reached();
582956a7811SThomas Huth     }
583956a7811SThomas Huth }
584956a7811SThomas Huth 
585956a7811SThomas Huth static const MemoryRegionOps scr_ops = {
586956a7811SThomas Huth     .read = scr_readfn,
587956a7811SThomas Huth     .write = scr_writefn,
588956a7811SThomas Huth     .valid.min_access_size = 1,
589956a7811SThomas Huth     .valid.max_access_size = 4,
590956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
591956a7811SThomas Huth };
592956a7811SThomas Huth 
593956a7811SThomas Huth #define NEXTDMA_SCSI(x)      (0x10 + x)
594956a7811SThomas Huth #define NEXTDMA_FD(x)        (0x10 + x)
595956a7811SThomas Huth #define NEXTDMA_ENTX(x)      (0x110 + x)
596956a7811SThomas Huth #define NEXTDMA_ENRX(x)      (0x150 + x)
597956a7811SThomas Huth #define NEXTDMA_CSR          0x0
598956a7811SThomas Huth #define NEXTDMA_NEXT         0x4000
599956a7811SThomas Huth #define NEXTDMA_LIMIT        0x4004
600956a7811SThomas Huth #define NEXTDMA_START        0x4008
601956a7811SThomas Huth #define NEXTDMA_STOP         0x400c
602956a7811SThomas Huth #define NEXTDMA_NEXT_INIT    0x4200
603956a7811SThomas Huth #define NEXTDMA_SIZE         0x4204
604956a7811SThomas Huth 
605956a7811SThomas Huth static void dma_writel(void *opaque, hwaddr addr, uint64_t value,
606956a7811SThomas Huth                        unsigned int size)
607956a7811SThomas Huth {
608956a7811SThomas Huth     NeXTState *next_state = NEXT_MACHINE(opaque);
609956a7811SThomas Huth 
610956a7811SThomas Huth     switch (addr) {
611956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_CSR):
612956a7811SThomas Huth         if (value & DMA_DEV2M) {
613956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M;
614956a7811SThomas Huth         }
615956a7811SThomas Huth 
616956a7811SThomas Huth         if (value & DMA_SETENABLE) {
617956a7811SThomas Huth             /* DPRINTF("SCSI DMA ENABLE\n"); */
618956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE;
619956a7811SThomas Huth         }
620956a7811SThomas Huth         if (value & DMA_SETSUPDATE) {
621956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE;
622956a7811SThomas Huth         }
623956a7811SThomas Huth         if (value & DMA_CLRCOMPLETE) {
624956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE;
625956a7811SThomas Huth         }
626956a7811SThomas Huth 
627956a7811SThomas Huth         if (value & DMA_RESET) {
628956a7811SThomas Huth             next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
629956a7811SThomas Huth                                                   DMA_ENABLE | DMA_DEV2M);
630956a7811SThomas Huth         }
631956a7811SThomas Huth         /* DPRINTF("RXCSR \tWrite: %x\n",value); */
632956a7811SThomas Huth         break;
633956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
634956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].next_initbuf = value;
635956a7811SThomas Huth         break;
636956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
637956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].next = value;
638956a7811SThomas Huth         break;
639956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
640956a7811SThomas Huth         next_state->dma[NEXTDMA_ENRX].limit = value;
641956a7811SThomas Huth         break;
642956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_CSR):
643956a7811SThomas Huth         if (value & DMA_DEV2M) {
644956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M;
645956a7811SThomas Huth         }
646956a7811SThomas Huth         if (value & DMA_SETENABLE) {
647956a7811SThomas Huth             /* DPRINTF("SCSI DMA ENABLE\n"); */
648956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE;
649956a7811SThomas Huth         }
650956a7811SThomas Huth         if (value & DMA_SETSUPDATE) {
651956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE;
652956a7811SThomas Huth         }
653956a7811SThomas Huth         if (value & DMA_CLRCOMPLETE) {
654956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE;
655956a7811SThomas Huth         }
656956a7811SThomas Huth 
657956a7811SThomas Huth         if (value & DMA_RESET) {
658956a7811SThomas Huth             next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
659956a7811SThomas Huth                                                   DMA_ENABLE | DMA_DEV2M);
660956a7811SThomas Huth             /* DPRINTF("SCSI DMA RESET\n"); */
661956a7811SThomas Huth         }
662956a7811SThomas Huth         /* DPRINTF("RXCSR \tWrite: %x\n",value); */
663956a7811SThomas Huth         break;
664956a7811SThomas Huth 
665956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT):
666956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].next = value;
667956a7811SThomas Huth         break;
668956a7811SThomas Huth 
669956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
670956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].limit = value;
671956a7811SThomas Huth         break;
672956a7811SThomas Huth 
673956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
674956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].start = value;
675956a7811SThomas Huth         break;
676956a7811SThomas Huth 
677956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
678956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].stop = value;
679956a7811SThomas Huth         break;
680956a7811SThomas Huth 
681956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
682956a7811SThomas Huth         next_state->dma[NEXTDMA_SCSI].next_initbuf = value;
683956a7811SThomas Huth         break;
684956a7811SThomas Huth 
685956a7811SThomas Huth     default:
686956a7811SThomas Huth         DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value);
687956a7811SThomas Huth     }
688956a7811SThomas Huth }
689956a7811SThomas Huth 
690956a7811SThomas Huth static uint64_t dma_readl(void *opaque, hwaddr addr, unsigned int size)
691956a7811SThomas Huth {
692956a7811SThomas Huth     NeXTState *next_state = NEXT_MACHINE(opaque);
693956a7811SThomas Huth 
694956a7811SThomas Huth     switch (addr) {
695956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_CSR):
696956a7811SThomas Huth         DPRINTF("SCSI DMA CSR READ\n");
697956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].csr;
698956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_CSR):
699956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].csr;
700956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
701956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].next_initbuf;
702956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_NEXT):
703956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].next;
704956a7811SThomas Huth     case NEXTDMA_ENRX(NEXTDMA_LIMIT):
705956a7811SThomas Huth         return next_state->dma[NEXTDMA_ENRX].limit;
706956a7811SThomas Huth 
707956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT):
708956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].next;
709956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
710956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].next_initbuf;
711956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_LIMIT):
712956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].limit;
713956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_START):
714956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].start;
715956a7811SThomas Huth     case NEXTDMA_SCSI(NEXTDMA_STOP):
716956a7811SThomas Huth         return next_state->dma[NEXTDMA_SCSI].stop;
717956a7811SThomas Huth 
718956a7811SThomas Huth     default:
719956a7811SThomas Huth         DPRINTF("DMA read @ %x\n", (unsigned int)addr);
720956a7811SThomas Huth         return 0;
721956a7811SThomas Huth     }
722956a7811SThomas Huth 
723956a7811SThomas Huth     /*
724956a7811SThomas Huth      * once the csr's are done, subtract 0x3FEC from the addr, and that will
725956a7811SThomas Huth      * normalize the upper registers
726956a7811SThomas Huth      */
727956a7811SThomas Huth }
728956a7811SThomas Huth 
729956a7811SThomas Huth static const MemoryRegionOps dma_ops = {
730956a7811SThomas Huth     .read = dma_readl,
731956a7811SThomas Huth     .write = dma_writel,
732956a7811SThomas Huth     .impl.min_access_size = 4,
733956a7811SThomas Huth     .valid.min_access_size = 4,
734956a7811SThomas Huth     .valid.max_access_size = 4,
735956a7811SThomas Huth     .endianness = DEVICE_NATIVE_ENDIAN,
736956a7811SThomas Huth };
737956a7811SThomas Huth 
738956a7811SThomas Huth /*
739956a7811SThomas Huth  * TODO: set the shift numbers as values in the enum, so the first switch
740956a7811SThomas Huth  * will not be needed
741956a7811SThomas Huth  */
742c8abcc87SPeter Maydell static void next_irq(void *opaque, int number, int level)
743956a7811SThomas Huth {
744b497f4a1SPeter Maydell     NeXTPC *s = NEXT_PC(opaque);
745b497f4a1SPeter Maydell     M68kCPU *cpu = s->cpu;
746956a7811SThomas Huth     int shift = 0;
747956a7811SThomas Huth 
748956a7811SThomas Huth     /* first switch sets interupt status */
749956a7811SThomas Huth     /* DPRINTF("IRQ %i\n",number); */
750956a7811SThomas Huth     switch (number) {
751956a7811SThomas Huth     /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
752956a7811SThomas Huth     case NEXT_FD_I:
7535012a894SPhilippe Mathieu-Daudé         shift = 7;
754956a7811SThomas Huth         break;
755956a7811SThomas Huth     case NEXT_KBD_I:
756956a7811SThomas Huth         shift = 3;
757956a7811SThomas Huth         break;
758956a7811SThomas Huth     case NEXT_PWR_I:
759956a7811SThomas Huth         shift = 2;
760956a7811SThomas Huth         break;
761956a7811SThomas Huth     case NEXT_ENRX_I:
762956a7811SThomas Huth         shift = 9;
763956a7811SThomas Huth         break;
764956a7811SThomas Huth     case NEXT_ENTX_I:
765956a7811SThomas Huth         shift = 10;
766956a7811SThomas Huth         break;
767956a7811SThomas Huth     case NEXT_SCSI_I:
768956a7811SThomas Huth         shift = 12;
769956a7811SThomas Huth         break;
770956a7811SThomas Huth     case NEXT_CLK_I:
771956a7811SThomas Huth         shift = 5;
772956a7811SThomas Huth         break;
773956a7811SThomas Huth 
774956a7811SThomas Huth     /* level 5 - scc (serial) */
775956a7811SThomas Huth     case NEXT_SCC_I:
776956a7811SThomas Huth         shift = 17;
777956a7811SThomas Huth         break;
778956a7811SThomas Huth 
779956a7811SThomas Huth     /* level 6 - audio etherrx/tx dma */
780956a7811SThomas Huth     case NEXT_ENTX_DMA_I:
781956a7811SThomas Huth         shift = 28;
782956a7811SThomas Huth         break;
783956a7811SThomas Huth     case NEXT_ENRX_DMA_I:
784956a7811SThomas Huth         shift = 27;
785956a7811SThomas Huth         break;
786956a7811SThomas Huth     case NEXT_SCSI_DMA_I:
787956a7811SThomas Huth         shift = 26;
788956a7811SThomas Huth         break;
789956a7811SThomas Huth     case NEXT_SND_I:
790956a7811SThomas Huth         shift = 23;
791956a7811SThomas Huth         break;
792956a7811SThomas Huth     case NEXT_SCC_DMA_I:
793956a7811SThomas Huth         shift = 21;
794956a7811SThomas Huth         break;
795956a7811SThomas Huth 
796956a7811SThomas Huth     }
797956a7811SThomas Huth     /*
798956a7811SThomas Huth      * this HAS to be wrong, the interrupt handlers in mach and together
799956a7811SThomas Huth      * int_status and int_mask and return if there is a hit
800956a7811SThomas Huth      */
801*ac99317bSPeter Maydell     if (s->int_mask & (1 << shift)) {
802956a7811SThomas Huth         DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc);
803956a7811SThomas Huth         /* return; */
804956a7811SThomas Huth     }
805956a7811SThomas Huth 
806956a7811SThomas Huth     /* second switch triggers the correct interrupt */
807956a7811SThomas Huth     if (level) {
808*ac99317bSPeter Maydell         s->int_status |= 1 << shift;
809956a7811SThomas Huth 
810956a7811SThomas Huth         switch (number) {
811956a7811SThomas Huth         /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
812956a7811SThomas Huth         case NEXT_FD_I:
813956a7811SThomas Huth         case NEXT_KBD_I:
814956a7811SThomas Huth         case NEXT_PWR_I:
815956a7811SThomas Huth         case NEXT_ENRX_I:
816956a7811SThomas Huth         case NEXT_ENTX_I:
817956a7811SThomas Huth         case NEXT_SCSI_I:
818956a7811SThomas Huth         case NEXT_CLK_I:
819956a7811SThomas Huth             m68k_set_irq_level(cpu, 3, 27);
820956a7811SThomas Huth             break;
821956a7811SThomas Huth 
822956a7811SThomas Huth         /* level 5 - scc (serial) */
823956a7811SThomas Huth         case NEXT_SCC_I:
824956a7811SThomas Huth             m68k_set_irq_level(cpu, 5, 29);
825956a7811SThomas Huth             break;
826956a7811SThomas Huth 
827956a7811SThomas Huth         /* level 6 - audio etherrx/tx dma */
828956a7811SThomas Huth         case NEXT_ENTX_DMA_I:
829956a7811SThomas Huth         case NEXT_ENRX_DMA_I:
830956a7811SThomas Huth         case NEXT_SCSI_DMA_I:
831956a7811SThomas Huth         case NEXT_SND_I:
832956a7811SThomas Huth         case NEXT_SCC_DMA_I:
833956a7811SThomas Huth             m68k_set_irq_level(cpu, 6, 30);
834956a7811SThomas Huth             break;
835956a7811SThomas Huth         }
836956a7811SThomas Huth     } else {
837*ac99317bSPeter Maydell         s->int_status &= ~(1 << shift);
838956a7811SThomas Huth         cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
839956a7811SThomas Huth     }
840956a7811SThomas Huth }
841956a7811SThomas Huth 
842b17bed5bSThomas Huth static void next_serial_irq(void *opaque, int n, int level)
843b17bed5bSThomas Huth {
844b17bed5bSThomas Huth     /* DPRINTF("SCC IRQ NUM %i\n",n); */
845b17bed5bSThomas Huth     if (n) {
846b17bed5bSThomas Huth         next_irq(opaque, NEXT_SCC_DMA_I, level);
847b17bed5bSThomas Huth     } else {
848b17bed5bSThomas Huth         next_irq(opaque, NEXT_SCC_I, level);
849b17bed5bSThomas Huth     }
850b17bed5bSThomas Huth }
851b17bed5bSThomas Huth 
852b497f4a1SPeter Maydell static void next_escc_init(DeviceState *pcdev)
853b17bed5bSThomas Huth {
854b497f4a1SPeter Maydell     qemu_irq *ser_irq = qemu_allocate_irqs(next_serial_irq, pcdev, 2);
855b17bed5bSThomas Huth     DeviceState *dev;
856b17bed5bSThomas Huth     SysBusDevice *s;
857b17bed5bSThomas Huth 
8583e80f690SMarkus Armbruster     dev = qdev_new(TYPE_ESCC);
859b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "disabled", 0);
860b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "frequency", 9600 * 384);
861b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "it_shift", 0);
862b17bed5bSThomas Huth     qdev_prop_set_bit(dev, "bit_swap", true);
863b17bed5bSThomas Huth     qdev_prop_set_chr(dev, "chrB", serial_hd(1));
864b17bed5bSThomas Huth     qdev_prop_set_chr(dev, "chrA", serial_hd(0));
865b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
866b17bed5bSThomas Huth     qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
867b17bed5bSThomas Huth 
868b17bed5bSThomas Huth     s = SYS_BUS_DEVICE(dev);
8693c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
870b17bed5bSThomas Huth     sysbus_connect_irq(s, 0, ser_irq[0]);
871b17bed5bSThomas Huth     sysbus_connect_irq(s, 1,  ser_irq[1]);
872b17bed5bSThomas Huth     sysbus_mmio_map(s, 0, 0x2118000);
873b17bed5bSThomas Huth }
874b17bed5bSThomas Huth 
875660bef33SPeter Maydell static void next_pc_reset(DeviceState *dev)
876660bef33SPeter Maydell {
87740831636SPeter Maydell     NeXTPC *s = NEXT_PC(dev);
87840831636SPeter Maydell 
87940831636SPeter Maydell     /* Set internal registers to initial values */
88040831636SPeter Maydell     /*     0x0000XX00 << vital bits */
88140831636SPeter Maydell     s->scr1 = 0x00011102;
88240831636SPeter Maydell     s->scr2 = 0x00ff0c80;
883660bef33SPeter Maydell }
884660bef33SPeter Maydell 
885660bef33SPeter Maydell static void next_pc_realize(DeviceState *dev, Error **errp)
886660bef33SPeter Maydell {
88740831636SPeter Maydell     NeXTPC *s = NEXT_PC(dev);
88840831636SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
88940831636SPeter Maydell 
89040831636SPeter Maydell     memory_region_init_io(&s->mmiomem, OBJECT(s), &mmio_ops, s,
89140831636SPeter Maydell                           "next.mmio", 0xD0000);
8921dc7aeaeSPeter Maydell     memory_region_init_io(&s->scrmem, OBJECT(s), &scr_ops, s,
8931dc7aeaeSPeter Maydell                           "next.scr", 0x20000);
89440831636SPeter Maydell     sysbus_init_mmio(sbd, &s->mmiomem);
8951dc7aeaeSPeter Maydell     sysbus_init_mmio(sbd, &s->scrmem);
896660bef33SPeter Maydell }
897660bef33SPeter Maydell 
898b497f4a1SPeter Maydell /*
899b497f4a1SPeter Maydell  * If the m68k CPU implemented its inbound irq lines as GPIO lines
900b497f4a1SPeter Maydell  * rather than via the m68k_set_irq_level() function we would not need
901b497f4a1SPeter Maydell  * this cpu link property and could instead provide outbound IRQ lines
902b497f4a1SPeter Maydell  * that the board could wire up to the CPU.
903b497f4a1SPeter Maydell  */
904b497f4a1SPeter Maydell static Property next_pc_properties[] = {
905b497f4a1SPeter Maydell     DEFINE_PROP_LINK("cpu", NeXTPC, cpu, TYPE_M68K_CPU, M68kCPU *),
906b497f4a1SPeter Maydell     DEFINE_PROP_END_OF_LIST(),
907b497f4a1SPeter Maydell };
908b497f4a1SPeter Maydell 
909660bef33SPeter Maydell static void next_pc_class_init(ObjectClass *klass, void *data)
910660bef33SPeter Maydell {
911660bef33SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
912660bef33SPeter Maydell 
913660bef33SPeter Maydell     dc->desc = "NeXT Peripheral Controller";
914660bef33SPeter Maydell     dc->realize = next_pc_realize;
915660bef33SPeter Maydell     dc->reset = next_pc_reset;
916b497f4a1SPeter Maydell     device_class_set_props(dc, next_pc_properties);
917660bef33SPeter Maydell     /* We will add the VMState in a later commit */
918660bef33SPeter Maydell }
919660bef33SPeter Maydell 
920660bef33SPeter Maydell static const TypeInfo next_pc_info = {
921660bef33SPeter Maydell     .name = TYPE_NEXT_PC,
922660bef33SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
923660bef33SPeter Maydell     .instance_size = sizeof(NeXTPC),
924660bef33SPeter Maydell     .class_init = next_pc_class_init,
925660bef33SPeter Maydell };
926660bef33SPeter Maydell 
927956a7811SThomas Huth static void next_cube_init(MachineState *machine)
928956a7811SThomas Huth {
929956a7811SThomas Huth     M68kCPU *cpu;
930956a7811SThomas Huth     CPUM68KState *env;
931956a7811SThomas Huth     MemoryRegion *rom = g_new(MemoryRegion, 1);
932956a7811SThomas Huth     MemoryRegion *dmamem = g_new(MemoryRegion, 1);
933956a7811SThomas Huth     MemoryRegion *bmapm1 = g_new(MemoryRegion, 1);
934956a7811SThomas Huth     MemoryRegion *bmapm2 = g_new(MemoryRegion, 1);
935956a7811SThomas Huth     MemoryRegion *sysmem = get_system_memory();
9361684273cSPaolo Bonzini     const char *bios_name = machine->firmware ?: ROM_FILE;
937956a7811SThomas Huth     NeXTState *ns = NEXT_MACHINE(machine);
938956a7811SThomas Huth     DeviceState *dev;
939660bef33SPeter Maydell     DeviceState *pcdev;
940956a7811SThomas Huth 
941956a7811SThomas Huth     /* Initialize the cpu core */
942956a7811SThomas Huth     cpu = M68K_CPU(cpu_create(machine->cpu_type));
943956a7811SThomas Huth     if (!cpu) {
944956a7811SThomas Huth         error_report("Unable to find m68k CPU definition");
945956a7811SThomas Huth         exit(1);
946956a7811SThomas Huth     }
947956a7811SThomas Huth     env = &cpu->env;
948956a7811SThomas Huth 
949956a7811SThomas Huth     /* Initialize CPU registers.  */
950956a7811SThomas Huth     env->vbr = 0;
951956a7811SThomas Huth     env->sr  = 0x2700;
952956a7811SThomas Huth 
953660bef33SPeter Maydell     /* Peripheral Controller */
954660bef33SPeter Maydell     pcdev = qdev_new(TYPE_NEXT_PC);
955b497f4a1SPeter Maydell     object_property_set_link(OBJECT(pcdev), "cpu", OBJECT(cpu), &error_abort);
956660bef33SPeter Maydell     sysbus_realize_and_unref(SYS_BUS_DEVICE(pcdev), &error_fatal);
957660bef33SPeter Maydell     /* Temporary while we refactor this code */
958660bef33SPeter Maydell     NEXT_PC(pcdev)->ns = ns;
959660bef33SPeter Maydell 
960cd4fc142SThomas Huth     ns->rtc.status = 0x90;
961956a7811SThomas Huth 
962956a7811SThomas Huth     /* Load RTC RAM - TODO: provide possibility to load contents from file */
963cd4fc142SThomas Huth     memcpy(ns->rtc.ram, rtc_ram2, 32);
964956a7811SThomas Huth 
965956a7811SThomas Huth     /* 64MB RAM starting at 0x04000000  */
96649b64ba9SIgor Mammedov     memory_region_add_subregion(sysmem, 0x04000000, machine->ram);
967956a7811SThomas Huth 
968956a7811SThomas Huth     /* Framebuffer */
9693e80f690SMarkus Armbruster     dev = qdev_new(TYPE_NEXTFB);
9703c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
971956a7811SThomas Huth     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000);
972956a7811SThomas Huth 
973956a7811SThomas Huth     /* MMIO */
97440831636SPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000);
975956a7811SThomas Huth 
9761dc7aeaeSPeter Maydell     /* BMAP IO - acts as a catch-all for now */
9771dc7aeaeSPeter Maydell     sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000);
9781dc7aeaeSPeter Maydell 
979956a7811SThomas Huth     /* BMAP memory */
980956a7811SThomas Huth     memory_region_init_ram_shared_nomigrate(bmapm1, NULL, "next.bmapmem", 64,
981956a7811SThomas Huth                                             true, &error_fatal);
982956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x020c0000, bmapm1);
983956a7811SThomas Huth     /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */
984956a7811SThomas Huth     memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64);
985956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x820c0000, bmapm2);
986956a7811SThomas Huth 
987956a7811SThomas Huth     /* KBD */
9883e80f690SMarkus Armbruster     dev = qdev_new(TYPE_NEXTKBD);
9893c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
990956a7811SThomas Huth     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0200e000);
991956a7811SThomas Huth 
992956a7811SThomas Huth     /* Load ROM here */
993956a7811SThomas Huth     /* still not sure if the rom should also be mapped at 0x0*/
994956a7811SThomas Huth     memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal);
995956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x01000000, rom);
996956a7811SThomas Huth     if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) {
997956a7811SThomas Huth         if (!qtest_enabled()) {
998956a7811SThomas Huth             error_report("Failed to load firmware '%s'.", bios_name);
999956a7811SThomas Huth         }
1000956a7811SThomas Huth     } else {
1001956a7811SThomas Huth         uint8_t *ptr;
1002956a7811SThomas Huth         /* Initial PC is always at offset 4 in firmware binaries */
1003956a7811SThomas Huth         ptr = rom_ptr(0x01000004, 4);
1004956a7811SThomas Huth         g_assert(ptr != NULL);
1005956a7811SThomas Huth         env->pc = ldl_p(ptr);
1006956a7811SThomas Huth         if (env->pc >= 0x01020000) {
1007956a7811SThomas Huth             error_report("'%s' does not seem to be a valid firmware image.",
1008956a7811SThomas Huth                          bios_name);
1009956a7811SThomas Huth             exit(1);
1010956a7811SThomas Huth         }
1011956a7811SThomas Huth     }
1012956a7811SThomas Huth 
1013956a7811SThomas Huth     /* Serial */
1014b497f4a1SPeter Maydell     next_escc_init(pcdev);
1015b17bed5bSThomas Huth 
1016b17bed5bSThomas Huth     /* TODO: */
1017956a7811SThomas Huth     /* Network */
1018956a7811SThomas Huth     /* SCSI */
1019956a7811SThomas Huth 
1020956a7811SThomas Huth     /* DMA */
1021956a7811SThomas Huth     memory_region_init_io(dmamem, NULL, &dma_ops, machine, "next.dma", 0x5000);
1022956a7811SThomas Huth     memory_region_add_subregion(sysmem, 0x02000000, dmamem);
1023956a7811SThomas Huth }
1024956a7811SThomas Huth 
1025956a7811SThomas Huth static void next_machine_class_init(ObjectClass *oc, void *data)
1026956a7811SThomas Huth {
1027956a7811SThomas Huth     MachineClass *mc = MACHINE_CLASS(oc);
1028956a7811SThomas Huth 
1029956a7811SThomas Huth     mc->desc = "NeXT Cube";
1030956a7811SThomas Huth     mc->init = next_cube_init;
1031956a7811SThomas Huth     mc->default_ram_size = RAM_SIZE;
103249b64ba9SIgor Mammedov     mc->default_ram_id = "next.ram";
1033956a7811SThomas Huth     mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
1034956a7811SThomas Huth }
1035956a7811SThomas Huth 
1036956a7811SThomas Huth static const TypeInfo next_typeinfo = {
1037956a7811SThomas Huth     .name = TYPE_NEXT_MACHINE,
1038956a7811SThomas Huth     .parent = TYPE_MACHINE,
1039956a7811SThomas Huth     .class_init = next_machine_class_init,
1040956a7811SThomas Huth     .instance_size = sizeof(NeXTState),
1041956a7811SThomas Huth };
1042956a7811SThomas Huth 
1043956a7811SThomas Huth static void next_register_type(void)
1044956a7811SThomas Huth {
1045956a7811SThomas Huth     type_register_static(&next_typeinfo);
1046660bef33SPeter Maydell     type_register_static(&next_pc_info);
1047956a7811SThomas Huth }
1048956a7811SThomas Huth 
1049956a7811SThomas Huth type_init(next_register_type)
1050