1 /*
2 * Copyright (C) 2003-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: DECsystem 58x0 devices
29 *
30 * Emulation of devices found in a DECsystem 58x0, where x is the number
31 * of CPUs in the system. (The CPU board is called KN5800 by Ultrix.)
32 *
33 * o) timers and misc stuff
34 * o) BI (Backplane Interconnect)
35 * o) CCA (Console Communication Area)
36 * o) XMI (Extended Memory Interconnect)
37 *
38 * TODO: This hardware is not very easy to find docs about.
39 * Perhaps VAX 6000/300 docs?
40 */
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "console.h"
47 #include "cpu.h"
48 #include "device.h"
49 #include "devices.h"
50 #include "interrupt.h"
51 #include "machine.h"
52 #include "memory.h"
53 #include "misc.h"
54
55
56 #define DEV_DEC5800_LENGTH 0x1000 /* TODO */
57
58 struct dec5800_data {
59 uint32_t csr;
60 struct interrupt cpu_irq;
61
62 uint32_t vector_0x50;
63
64 struct interrupt timer_irq;
65 };
66
67
dec5800_interrupt_assert(struct interrupt * interrupt)68 void dec5800_interrupt_assert(struct interrupt *interrupt)
69 {
70 struct dec5800_data *d = (struct dec5800_data *) interrupt->extra;
71 d->csr |= (1 << interrupt->line);
72 if (d->csr & 0x10000000)
73 INTERRUPT_ASSERT(d->cpu_irq);
74 }
dec5800_interrupt_deassert(struct interrupt * interrupt)75 void dec5800_interrupt_deassert(struct interrupt *interrupt)
76 {
77 struct dec5800_data *d = (struct dec5800_data *) interrupt->extra;
78 d->csr &= ~(1 << interrupt->line);
79 if (!(d->csr & 0x10000000))
80 INTERRUPT_DEASSERT(d->cpu_irq);
81 }
82
83
DEVICE_TICK(dec5800)84 DEVICE_TICK(dec5800)
85 {
86 struct dec5800_data *d = (struct dec5800_data *) extra;
87
88 /* Timer interrupts? */
89 if (d->csr & 0x8000) {
90 debug("[ dec5800: timer interrupt! ]\n");
91
92 /* Set timer interrupt pending bit: */
93 d->csr |= 0x20000000;
94
95 INTERRUPT_ASSERT(d->timer_irq);
96 }
97 }
98
99
DEVICE_ACCESS(dec5800_vectors)100 DEVICE_ACCESS(dec5800_vectors)
101 {
102 uint64_t idata = 0, odata = 0;
103 struct dec5800_data *d = (struct dec5800_data *) extra;
104
105 if (writeflag == MEM_WRITE)
106 idata = memory_readmax64(cpu, data, len);
107
108 if (writeflag == MEM_READ) {
109 /* TODO */
110 /* 0xfc = transmit interrupt, 0xf8 = receive interrupt,
111 0x80 = IPI */
112 odata = d->vector_0x50;
113 /* odata = 0xfc; */
114 debug("[ dec5800_vectors: read from 0x%02x: 0x%02x ]\n",
115 (int)relative_addr, (int)odata);
116 } else {
117 d->vector_0x50 = idata;
118 debug("[ dec5800_vectors: write to 0x%02x: 0x%02x ]\n",
119 (int)relative_addr, (int)idata);
120 }
121
122 if (writeflag == MEM_READ)
123 memory_writemax64(cpu, data, len, odata);
124
125 return 1;
126 }
127
128
DEVICE_ACCESS(dec5800)129 DEVICE_ACCESS(dec5800)
130 {
131 uint64_t idata = 0, odata = 0;
132 struct dec5800_data *d = (struct dec5800_data *) extra;
133
134 if (writeflag == MEM_WRITE)
135 idata = memory_readmax64(cpu, data, len);
136
137 /* Lowest 4 bits of csr contain cpu id: */
138 d->csr = (d->csr & ~0xf) | (cpu->cpu_id & 0xf);
139
140 switch (relative_addr) {
141 case 0x0000: /* csr */
142 if (writeflag == MEM_READ) {
143 odata = d->csr;
144 odata ^= random() & 0x10000;
145 debug("[ dec5800: read from csr: 0x%08x ]\n",
146 (int)odata);
147 } else {
148 d->csr = idata;
149
150 /* Ack. timer interrupts: */
151 d->csr &= ~0x20000000;
152 INTERRUPT_DEASSERT(d->timer_irq);
153
154 debug("[ dec5800: write to csr: 0x%08x ]\n",
155 (int)idata);
156 }
157 break;
158 default:
159 if (writeflag==MEM_READ) {
160 debug("[ dec5800: read from 0x%08lx ]\n",
161 (long)relative_addr);
162 } else {
163 debug("[ dec5800: write to 0x%08lx: 0x%08x ]\n",
164 (long)relative_addr, (int)idata);
165 }
166 }
167
168 if (writeflag == MEM_READ)
169 memory_writemax64(cpu, data, len, odata);
170
171 return 1;
172 }
173
174
DEVINIT(dec5800)175 DEVINIT(dec5800)
176 {
177 struct dec5800_data *d;
178 char tmpstr[200];
179 int i;
180
181 CHECK_ALLOCATION(d = (struct dec5800_data *) malloc(sizeof(struct dec5800_data)));
182 memset(d, 0, sizeof(struct dec5800_data));
183
184 snprintf(tmpstr, sizeof(tmpstr), "%s.2", devinit->interrupt_path);
185 INTERRUPT_CONNECT(tmpstr, d->cpu_irq);
186
187 snprintf(tmpstr, sizeof(tmpstr), "%s.3", devinit->interrupt_path);
188 INTERRUPT_CONNECT(tmpstr, d->timer_irq);
189
190 /* Register 32 CSR interrupts, corresponding to bits in the CSR: */
191 for (i=0; i<32; i++) {
192 char n[200];
193 struct interrupt templ;
194 snprintf(n, sizeof(n), "%s.dec5800.%i",
195 devinit->interrupt_path, i);
196 memset(&templ, 0, sizeof(templ));
197 templ.line = i;
198 templ.name = n;
199 templ.extra = d;
200 templ.interrupt_assert = dec5800_interrupt_assert;
201 templ.interrupt_deassert = dec5800_interrupt_deassert;
202 interrupt_handler_register(&templ);
203 }
204
205 memory_device_register(devinit->machine->memory, "dec5800",
206 devinit->addr, DEV_DEC5800_LENGTH, dev_dec5800_access,
207 d, DM_DEFAULT, NULL);
208 memory_device_register(devinit->machine->memory, "dec5800_vectors",
209 devinit->addr + 0x30000000, 0x100, dev_dec5800_vectors_access,
210 d, DM_DEFAULT, NULL);
211 machine_add_tickfunction(devinit->machine, dev_dec5800_tick,
212 d, 14);
213
214 return 1;
215 }
216
217
218 /*****************************************************************************/
219
220
221 #include "thirdparty/bireg.h"
222
223 /* 16 slots, 0x2000 bytes each */
224 #define DEV_DECBI_LENGTH 0x20000
225
226 struct decbi_data {
227 int csr[NNODEBI];
228 };
229
230
DEVICE_ACCESS(decbi)231 DEVICE_ACCESS(decbi)
232 {
233 uint64_t idata = 0, odata = 0;
234 int node_nr;
235 struct decbi_data *d = (struct decbi_data *) extra;
236
237 if (writeflag == MEM_WRITE)
238 idata = memory_readmax64(cpu, data, len);
239
240 relative_addr += BI_NODESIZE; /* HACK */
241
242 node_nr = relative_addr / BI_NODESIZE;
243 relative_addr &= (BI_NODESIZE - 1);
244
245 /* TODO: This "1" here is the max node number in actual use. */
246 if (node_nr > 1 || node_nr >= NNODEBI)
247 return 0;
248
249 switch (relative_addr) {
250 case BIREG_DTYPE:
251 if (writeflag==MEM_READ) {
252 /*
253 * This is a list of the devices in our BI slots:
254 */
255 switch (node_nr) {
256 case 1: odata = BIDT_KDB50; break; /* Disk */
257 /* case 2: odata = BIDT_DEBNA; break; */
258 /* BIDT_DEBNA = Ethernet */
259 /* case 3: odata = BIDT_MS820; break; */
260 /* BIDT_MS820 = Memory */
261 default:
262 /* No device. */
263 odata = 0;
264 }
265
266 debug("[ decbi: (node %i) read from BIREG_DTYPE:"
267 " 0x%x ]\n", node_nr, (int)odata);
268 } else {
269 debug("[ decbi: (node %i) attempt to write to "
270 "BIREG_DTYPE: 0x%08x ]\n", node_nr, (int)idata);
271 }
272 break;
273 case BIREG_VAXBICSR:
274 if (writeflag==MEM_READ) {
275 odata = (d->csr[node_nr] & ~BICSR_NODEMASK) | node_nr;
276 debug("[ decbi: (node %i) read from BIREG_"
277 "VAXBICSR: 0x%x ]\n", node_nr, (int)odata);
278 } else {
279 d->csr[node_nr] = idata;
280 debug("[ decbi: (node %i) attempt to write to "
281 "BIREG_VAXBICSR: 0x%08x ]\n", node_nr, (int)idata);
282 }
283 break;
284 case 0xf4:
285 if (writeflag==MEM_READ) {
286 odata = 0xffff; /* ? */
287 debug("[ decbi: (node %i) read from 0xf4: "
288 "0x%x ]\n", node_nr, (int)odata);
289 } else {
290 debug("[ decbi: (node %i) attempt to write "
291 "to 0xf4: 0x%08x ]\n", node_nr, (int)idata);
292 }
293 break;
294 default:
295 if (writeflag==MEM_READ) {
296 debug("[ decbi: (node %i) read from unimplemented "
297 "0x%08lx ]\n", node_nr, (long)relative_addr,
298 (int)odata);
299 } else {
300 debug("[ decbi: (node %i) write to unimplemented "
301 "0x%08lx: 0x%08x ]\n", node_nr,
302 (long)relative_addr, (int)idata);
303 }
304 }
305
306 if (writeflag == MEM_READ)
307 memory_writemax64(cpu, data, len, odata);
308
309 return 1;
310 }
311
312
DEVINIT(decbi)313 DEVINIT(decbi)
314 {
315 struct decbi_data *d;
316
317 CHECK_ALLOCATION(d = (struct decbi_data *) malloc(sizeof(struct decbi_data)));
318 memset(d, 0, sizeof(struct decbi_data));
319
320 memory_device_register(devinit->machine->memory, "decbi",
321 devinit->addr + 0x2000, DEV_DECBI_LENGTH - 0x2000,
322 dev_decbi_access, d, DM_DEFAULT, NULL);
323
324 return 1;
325 }
326
327
328 /*****************************************************************************/
329
330
331 /*
332 * CCA, "Console Communication Area" for a DEC 5800 SMP system.
333 */
334
335 struct deccca_data {
336 int dummy;
337 };
338
339
DEVICE_ACCESS(deccca)340 DEVICE_ACCESS(deccca)
341 {
342 uint64_t idata = 0, odata = 0;
343 /* struct deccca_data *d = extra; */
344
345 if (writeflag == MEM_WRITE)
346 idata = memory_readmax64(cpu, data, len);
347
348 switch (relative_addr) {
349 case 6:
350 case 7:
351 /* CCA "ID" bytes? These must be here, or Ultrix complains. */
352 if (writeflag == MEM_READ)
353 odata = 67;
354 break;
355 case 8:
356 if (writeflag == MEM_READ)
357 odata = cpu->machine->ncpus;
358 break;
359 case 20:
360 if (writeflag == MEM_READ)
361 odata = (1 << cpu->machine->ncpus) - 1;
362 /* one bit for each cpu */
363 break;
364 case 28:
365 if (writeflag == MEM_READ)
366 odata = (1 << cpu->machine->ncpus) - 1;
367 /* one bit for each enabled(?) cpu */
368 break;
369 default:
370 if (writeflag==MEM_READ) {
371 debug("[ deccca: read from 0x%08lx ]\n",
372 (long)relative_addr);
373 } else {
374 debug("[ deccca: write to 0x%08lx: 0x%08x ]\n",
375 (long)relative_addr, (int)idata);
376 }
377 }
378
379 if (writeflag == MEM_READ)
380 memory_writemax64(cpu, data, len, odata);
381
382 return 1;
383 }
384
385
386 /*
387 * dev_deccca_init():
388 */
dev_deccca_init(struct memory * mem,uint64_t baseaddr)389 void dev_deccca_init(struct memory *mem, uint64_t baseaddr)
390 {
391 struct deccca_data *d;
392
393 CHECK_ALLOCATION(d = (struct deccca_data *) malloc(sizeof(struct deccca_data)));
394 memset(d, 0, sizeof(struct deccca_data));
395
396 memory_device_register(mem, "deccca", baseaddr, DEV_DECCCA_LENGTH,
397 dev_deccca_access, d, DM_DEFAULT, NULL);
398 }
399
400
401 /*****************************************************************************/
402
403
404 /*
405 * DEC 5800 XMI (this has to do with SMP...)
406 */
407
408 #include "thirdparty/xmireg.h"
409
410 struct decxmi_data {
411 uint32_t reg_0xc[NNODEXMI];
412 };
413
414
415 /*
416 * dev_decxmi_access():
417 */
DEVICE_ACCESS(decxmi)418 DEVICE_ACCESS(decxmi)
419 {
420 uint64_t idata = 0, odata = 0;
421 int node_nr;
422 struct decxmi_data *d = (struct decxmi_data *) extra;
423
424 if (writeflag == MEM_WRITE)
425 idata = memory_readmax64(cpu, data, len);
426
427 node_nr = relative_addr / XMI_NODESIZE;
428 relative_addr &= (XMI_NODESIZE - 1);
429
430 if (node_nr >= cpu->machine->ncpus + 1 || node_nr >= NNODEXMI)
431 return 0;
432
433 switch (relative_addr) {
434 case XMI_TYPE:
435 if (writeflag == MEM_READ) {
436 /*
437 * The first node is an XMI->BI adapter node, and then
438 * there are n CPU nodes.
439 */
440 odata = XMIDT_ISIS;
441 if (node_nr == 0)
442 odata = XMIDT_DWMBA;
443
444 debug("[ decxmi: (node %i) read from XMI_TYPE: "
445 "0x%08x ]\n", node_nr, (int)odata);
446 } else
447 debug("[ decxmi: (node %i) write to XMI_TYPE: "
448 "0x%08x ]\n", node_nr, (int)idata);
449 break;
450 case XMI_BUSERR:
451 if (writeflag == MEM_READ) {
452 odata = 0;
453 debug("[ decxmi: (node %i) read from XMI_BUSERR: "
454 "0x%08x ]\n", node_nr, (int)odata);
455 } else
456 debug("[ decxmi: (node %i) write to XMI_BUSERR: "
457 "0x%08x ]\n", node_nr, (int)idata);
458 break;
459 case XMI_FAIL:
460 if (writeflag == MEM_READ) {
461 odata = 0;
462 debug("[ decxmi: (node %i) read from XMI_FAIL: "
463 "0x%08x ]\n", node_nr, (int)odata);
464 } else
465 debug("[ decxmi: (node %i) write to XMI_FAIL: "
466 "0x%08x ]\n", node_nr, (int)idata);
467 break;
468 case 0xc:
469 if (writeflag == MEM_READ) {
470 odata = d->reg_0xc[node_nr];
471 debug("[ decxmi: (node %i) read from REG 0xC: "
472 "0x%08x ]\n", node_nr, (int)odata);
473 } else {
474 d->reg_0xc[node_nr] = idata;
475 debug("[ decxmi: (node %i) write to REG 0xC: "
476 "0x%08x ]\n", node_nr, (int)idata);
477 }
478 break;
479 default:
480 if (writeflag==MEM_READ) {
481 debug("[ decxmi: (node %i) read from unimplemented "
482 "0x%08lx ]\n", node_nr, (long)relative_addr,
483 (int)odata);
484 } else {
485 debug("[ decxmi: (node %i) write to unimplemented "
486 "0x%08lx: 0x%08x ]\n", node_nr,
487 (long)relative_addr, (int)idata);
488 }
489 }
490
491 if (writeflag == MEM_READ)
492 memory_writemax64(cpu, data, len, odata);
493
494 return 1;
495 }
496
497
498 /*
499 * dev_decxmi_init():
500 */
dev_decxmi_init(struct memory * mem,uint64_t baseaddr)501 void dev_decxmi_init(struct memory *mem, uint64_t baseaddr)
502 {
503 struct decxmi_data *d;
504
505 CHECK_ALLOCATION(d = (struct decxmi_data *) malloc(sizeof(struct decxmi_data)));
506 memset(d, 0, sizeof(struct decxmi_data));
507
508 memory_device_register(mem, "decxmi", baseaddr, DEV_DECXMI_LENGTH,
509 dev_decxmi_access, d, DM_DEFAULT, NULL);
510 }
511
512