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