First Commit of my working state
[simh.git] / VAX / vax780_sbi.c
1 /* vax780_sbi.c: VAX 11/780 SBI
2
3 Copyright (c) 2004-2008, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 This module contains the VAX 11/780 system-specific registers and devices.
27
28 sbi bus controller
29
30 31-May-2008 RMS Fixed machine_check calling sequence (found by Peter Schorn)
31 03-May-2006 RMS Fixed writes to ACCS
32 28-May-08 RMS Inlined physical memory routines
33 */
34
35 #include "vax_defs.h"
36
37 /* 11/780 specific IPRs */
38
39 /* Writeable control store */
40
41 #define WCSA_RW 0xFFFF /* writeable */
42 #define WCSA_ADDR 0x1FFF /* addr */
43 #define WCSA_CTR 0x6000 /* counter */
44 #define WCSA_CTR_INC 0x2000 /* increment */
45 #define WCSA_CTR_MAX 0x6000 /* max value */
46 #define WCSD_RD_VAL 0xFF /* fixed read val */
47 #define WCSD_WR 0xFFFFFFFF /* write */
48 #define MBRK_RW 0x1FFF /* microbreak */
49
50 /* System registers */
51
52 #define SBIFS_RD (0x031F0000|SBI_FAULTS) /* SBI faults */
53 #define SBIFS_WR 0x03140000
54 #define SBIFS_W1C 0x00080000
55
56 #define SBISC_RD 0xFFFF0000 /* SBI silo comp */
57 #define SBISC_WR 0x7FFF0000
58 #define SBISC_LOCK 0x80000000 /* lock */
59
60 #define SBIMT_RD 0xFFFFFF00 /* SBI maint */
61 #define SBIMT_WR 0xFFFFF900
62
63 #define SBIER_CRDIE 0x00008000 /* SBI error, CRD IE */
64 #define SBIER_CRD 0x00004000 /* CRD */
65 #define SBIER_RDS 0x00002000 /* RDS */
66 #define SBIER_TMO 0x00001000 /* timeout */
67 #define SBIER_STA 0x00000C00 /* timeout status (0) */
68 #define SBIER_CNF 0x00000100 /* error confirm */
69 #define SBIER_IBRDS 0x00000080
70 #define SBIER_IBTMO 0x00000040
71 #define SBIER_IBSTA 0x00000030
72 #define SBIER_IBCNF 0x00000008
73 #define SBIER_MULT 0x00000004 /* multiple errors */
74 #define SBIER_FREE 0x00000002 /* SBI free */
75 #define SBIER_RD 0x0000FDFE
76 #define SBIER_WR 0x00008000
77 #define SBIER_W1C 0x000070C0
78 #define SBIER_TMOW1C (SBIER_TMO|SBIER_STA|SBIER_CNF|SBIER_MULT)
79 #define SBIER_IBTW1C (SBIER_IBTMO|SBIER_STA|SBIER_IBCNF)
80
81 #define SBITMO_V_MODE 30 /* mode */
82 #define SBITMO_VIRT 0x20000000 /* physical */
83
84 #define SBIQC_MBZ 0xC0000007 /* MBZ */
85
86 /* VAX-11/780 boot device definitions */
87
88 struct boot_dev {
89 char *name;
90 int32 code;
91 int32 let;
92 };
93
94 uint32 wcs_addr = 0;
95 uint32 wcs_data = 0;
96 uint32 wcs_mbrk = 0;
97 uint32 nexus_req[NEXUS_HLVL]; /* nexus int req */
98 uint32 sbi_fs = 0; /* SBI fault status */
99 uint32 sbi_sc = 0; /* SBI silo comparator */
100 uint32 sbi_mt = 0; /* SBI maintenance */
101 uint32 sbi_er = 0; /* SBI error status */
102 uint32 sbi_tmo = 0; /* SBI timeout addr */
103
104 static t_stat (*nexusR[NEXUS_NUM])(int32 *dat, int32 ad, int32 md);
105 static t_stat (*nexusW[NEXUS_NUM])(int32 dat, int32 ad, int32 md);
106
107 static struct boot_dev boot_tab[] = {
108 { "RP", BOOT_MB, 0 },
109 { "HK", BOOT_HK, 0 },
110 { "RL", BOOT_RL, 0 },
111 { "RQ", BOOT_UDA, 1 << 24 },
112 { "TQ", BOOT_TK, 1 << 24 },
113 { NULL }
114 };
115
116 extern int32 R[16];
117 extern int32 PSL;
118 extern int32 ASTLVL, SISR;
119 extern int32 mapen, pme, trpirq;
120 extern int32 in_ie;
121 extern int32 mchk_va, mchk_ref;
122 extern int32 crd_err, mem_err, hlt_pin;
123 extern int32 tmr_int, tti_int, tto_int;
124 extern jmp_buf save_env;
125 extern int32 p1;
126 extern int32 sim_switches;
127 extern DEVICE *sim_devices[];
128 extern FILE *sim_log;
129 extern CTAB *sim_vm_cmd;
130
131 t_stat sbi_reset (DEVICE *dptr);
132 void sbi_set_tmo (int32 pa);
133 void uba_eval_int (void);
134 t_stat vax780_boot (int32 flag, char *ptr);
135
136 extern t_stat vax780_fload (int flag, char *cptr);
137 extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei);
138 extern int32 iccs_rd (void);
139 extern int32 nicr_rd (void);
140 extern int32 icr_rd (t_bool interp);
141 extern int32 todr_rd (void);
142 extern int32 rxcs_rd (void);
143 extern int32 rxdb_rd (void);
144 extern int32 txcs_rd (void);
145 extern void iccs_wr (int32 dat);
146 extern void nicr_wr (int32 dat);
147 extern void todr_wr (int32 dat);
148 extern void rxcs_wr (int32 dat);
149 extern void txcs_wr (int32 dat);
150 extern void txdb_wr (int32 dat);
151 extern void init_mbus_tab (void);
152 extern void init_ubus_tab (void);
153 extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp);
154 extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp);
155
156 /* SBI data structures
157
158 sbi_dev SBI device descriptor
159 sbi_unit SBI unit
160 sbi_reg SBI register list
161 */
162
163 UNIT sbi_unit = { UDATA (NULL, 0, 0) };
164
165 REG sbi_reg[] = {
166 { HRDATA (NREQ14, nexus_req[0], 16) },
167 { HRDATA (NREQ15, nexus_req[1], 16) },
168 { HRDATA (NREQ16, nexus_req[2], 16) },
169 { HRDATA (NREQ17, nexus_req[3], 16) },
170 { HRDATA (WCSA, wcs_addr, 16) },
171 { HRDATA (WCSD, wcs_data, 32) },
172 { HRDATA (MBRK, wcs_mbrk, 13) },
173 { HRDATA (SBIFS, sbi_fs, 32) },
174 { HRDATA (SBISC, sbi_sc, 32) },
175 { HRDATA (SBIMT, sbi_mt, 32) },
176 { HRDATA (SBIER, sbi_er, 32) },
177 { HRDATA (SBITMO, sbi_tmo, 32) },
178 { NULL }
179 };
180
181 DEVICE sbi_dev = {
182 "SBI", &sbi_unit, sbi_reg, NULL,
183 1, 16, 16, 1, 16, 8,
184 NULL, NULL, &sbi_reset,
185 NULL, NULL, NULL,
186 NULL, 0
187 };
188
189 /* Special boot command, overrides regular boot */
190
191 CTAB vax780_cmd[] = {
192 { "BOOT", &vax780_boot, RU_BOOT,
193 "bo{ot} <device>{/R5:flg} boot device\n" },
194 { "FLOAD", &vax780_fload, 0,
195 "fl{oad} <file> {<start>} load file from console floppy\n" },
196 { NULL }
197 };
198
199 /* The VAX 11/780 has three sources of interrupts
200
201 - internal device interrupts (CPU, console, clock)
202 - nexus interupts (e.g., memory controller, MBA, UBA)
203 - external device interrupts (Unibus)
204
205 Internal devices vector to fixed SCB locations.
206
207 Nexus interrupts vector to an SCB location based on this
208 formula: SCB_NEXUS + ((IPL - 0x14) * 0x40) + (TR# * 0x4)
209
210 External device interrupts do not vector directly.
211 Instead, the interrupt handler for a given UBA IPL
212 reads a vector register that contains the Unibus vector
213 for that IPL.
214
215 /* Find highest priority vectorable interrupt */
216
217 int32 eval_int (void)
218 {
219 int32 ipl = PSL_GETIPL (PSL);
220 int32 i, t;
221
222 static const int32 sw_int_mask[IPL_SMAX] = {
223 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */
224 0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */
225 0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */
226 0xE000, 0xC000, 0x8000 /* C - E */
227 };
228
229 if (hlt_pin) return IPL_HLTPIN; /* hlt pin int */
230 if ((ipl < IPL_MEMERR) && mem_err) return IPL_MEMERR; /* mem err int */
231 if ((ipl < IPL_CRDERR) && crd_err) return IPL_CRDERR; /* crd err int */
232 if ((ipl < IPL_CLKINT) && tmr_int) return IPL_CLKINT; /* clock int */
233 uba_eval_int (); /* update UBA */
234 for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */
235 if (i <= ipl) return 0; /* at ipl? no int */
236 if (nexus_req[i - IPL_HMIN]) return i; /* req != 0? int */
237 }
238 if ((ipl < IPL_TTINT) && (tti_int || tto_int)) /* console int */
239 return IPL_TTINT;
240 if (ipl >= IPL_SMAX) return 0; /* ipl >= sw max? */
241 if ((t = SISR & sw_int_mask[ipl]) == 0) return 0; /* eligible req */
242 for (i = IPL_SMAX; i > ipl; i--) { /* check swre int */
243 if ((t >> i) & 1) return i; /* req != 0? int */
244 }
245 return 0;
246 }
247
248 /* Return vector for highest priority hardware interrupt at IPL lvl */
249
250 int32 get_vector (int32 lvl)
251 {
252 int32 i, l;
253
254 if (lvl == IPL_MEMERR) { /* mem error? */
255 mem_err = 0;
256 return SCB_MEMERR;
257 }
258 if (lvl == IPL_CRDERR) { /* CRD error? */
259 crd_err = 0;
260 return SCB_CRDERR;
261 }
262 if (lvl == IPL_CLKINT) { /* clock? */
263 tmr_int = 0; /* clear req */
264 return SCB_INTTIM; /* return vector */
265 }
266 if (lvl > IPL_HMAX) { /* error req lvl? */
267 ABORT (STOP_UIPL); /* unknown intr */
268 }
269 if ((lvl <= IPL_HMAX) && (lvl >= IPL_HMIN)) { /* nexus? */
270 l = lvl - IPL_HMIN;
271 for (i = 0; nexus_req[l] && (i < NEXUS_NUM); i++) {
272 if ((nexus_req[l] >> i) & 1) {
273 nexus_req[l] = nexus_req[l] & ~(1u << i);
274 return SCB_NEXUS + (l << 6) + (i << 2); /* return vector */
275 }
276 }
277 }
278 if (lvl == IPL_TTINT) { /* console? */
279 if (tti_int) { /* input? */
280 tti_int = 0; /* clear req */
281 return SCB_TTI; /* return vector */
282 }
283 if (tto_int) { /* output? */
284 tto_int = 0; /* clear req */
285 return SCB_TTO; /* return vector */
286 }
287 }
288 return 0;
289 }
290
291 /* Read 780-specific IPR's */
292
293 int32 ReadIPR (int32 rg)
294 {
295 int32 val;
296
297 switch (rg) {
298
299 case MT_ICCS: /* ICCS */
300 val = iccs_rd ();
301 break;
302
303 case MT_NICR: /* NICR */
304 val = nicr_rd ();
305 break;
306
307 case MT_ICR: /* ICR */
308 val = icr_rd (FALSE);
309 break;
310
311 case MT_TODR: /* TODR */
312 val = todr_rd ();
313 break;
314
315 case MT_ACCS: /* ACCS (not impl) */
316 val = 0;
317 break;
318
319 case MT_WCSA: /* WCSA */
320 val = wcs_addr & WCSA_RW;
321 break;
322
323 case MT_WCSD: /* WCSD */
324 val = WCSD_RD_VAL;
325 break;
326
327 case MT_RXCS: /* RXCS */
328 val = rxcs_rd ();
329 break;
330
331 case MT_RXDB: /* RXDB */
332 val = rxdb_rd ();
333 break;
334
335 case MT_TXCS: /* TXCS */
336 val = txcs_rd ();
337 break;
338
339 case MT_SBIFS: /* SBIFS */
340 val = sbi_fs & SBIFS_RD;
341 break;
342
343 case MT_SBIS: /* SBIS */
344 val = 0;
345 break;
346
347 case MT_SBISC: /* SBISC */
348 val = sbi_sc & SBISC_RD;
349 break;
350
351 case MT_SBIMT: /* SBIMT */
352 val = sbi_mt & SBIMT_RD;
353 break;
354
355 case MT_SBIER: /* SBIER */
356 val = sbi_er & SBIER_RD;
357 break;
358
359 case MT_SBITA: /* SBITA */
360 val = sbi_tmo;
361 break;
362
363 case MT_MBRK: /* MBRK */
364 val = wcs_mbrk & MBRK_RW;
365 break;
366
367 case MT_SID: /* SID */
368 val = VAX780_SID | VAX780_ECO | VAX780_PLANT | VAX780_SN;
369 break;
370
371 default:
372 RSVD_OPND_FAULT;
373 }
374
375 return val;
376 }
377
378 /* Write 780-specific IPR's */
379
380 void WriteIPR (int32 rg, int32 val)
381 {
382 switch (rg) {
383
384 case MT_ICCS: /* ICCS */
385 iccs_wr (val);
386 break;
387
388 case MT_NICR: /* NICR */
389 nicr_wr (val);
390 break;
391
392 case MT_TODR: /* TODR */
393 todr_wr (val);
394 break;
395
396 case MT_ACCS: /* ACCS (not impl) */
397 break;
398
399 case MT_WCSA: /* WCSA */
400 wcs_addr = val & WCSA_RW;
401 break;
402
403 case MT_WCSD: /* WCSD */
404 wcs_data = val & WCSD_WR;
405 wcs_addr = (wcs_addr & ~WCSA_CTR) |
406 ((wcs_addr + WCSA_CTR_INC) & WCSA_CTR);
407 if ((wcs_addr & WCSA_CTR) == WCSA_CTR_MAX)
408 wcs_addr = (wcs_addr & ~WCSA_ADDR) |
409 ((wcs_addr + 1) & WCSA_ADDR);
410 break;
411
412 case MT_RXCS: /* RXCS */
413 rxcs_wr (val);
414 break;
415
416 case MT_TXCS: /* TXCS */
417 txcs_wr (val);
418 break;
419
420 case MT_TXDB: /* TXDB */
421 txdb_wr (val);
422 break;
423
424 case MT_SBIFS: /* SBIFS */
425 sbi_fs = (sbi_fs & ~SBIFS_WR) | (val & SBIFS_WR);
426 sbi_fs = sbi_fs & ~(val & SBIFS_W1C);
427 break;
428
429 case MT_SBISC: /* SBISC */
430 sbi_sc = (sbi_sc & ~(SBISC_LOCK|SBISC_WR)) | (val & SBISC_WR);
431 break;
432
433 case MT_SBIMT: /* SBIMT */
434 sbi_mt = (sbi_mt & ~SBIMT_WR) | (val & SBIMT_WR);
435 break;
436
437 case MT_SBIER: /* SBIER */
438 sbi_er = (sbi_er & ~SBIER_WR) | (val & SBIER_WR);
439 sbi_er = sbi_er & ~(val & SBIER_W1C);
440 if (val & SBIER_TMO) sbi_er = sbi_er & ~SBIER_TMOW1C;
441 if (val & SBIER_IBTMO) sbi_er = sbi_er & ~SBIER_IBTW1C;
442 if ((sbi_er & SBIER_CRDIE) && (sbi_er & SBIER_CRD))
443 crd_err = 1;
444 else crd_err = 0;
445 break;
446
447 case MT_SBIQC: /* SBIQC */
448 if (val & SBIQC_MBZ) { RSVD_OPND_FAULT; }
449 WriteLP (val, 0);
450 WriteLP (val + 4, 0);
451 break;
452
453 case MT_MBRK: /* MBRK */
454 wcs_mbrk = val & MBRK_RW;
455 break;
456
457 default:
458 RSVD_OPND_FAULT;
459 }
460
461 return;
462 }
463
464 /* ReadReg - read register space
465
466 Inputs:
467 pa = physical address
468 lnt = length (BWLQ)
469 Output:
470 longword of data
471 */
472
473 int32 ReadReg (int32 pa, int32 lnt)
474 {
475 int32 nexus, val;
476
477 if (ADDR_IS_REG (pa)) { /* reg space? */
478 nexus = NEXUS_GETNEX (pa); /* get nexus */
479 if (nexusR[nexus] && /* valid? */
480 (nexusR[nexus] (&val, pa, lnt) == SCPE_OK)) {
481 SET_IRQL;
482 return val;
483 }
484 }
485 sbi_set_tmo (pa); /* timeout */
486 MACH_CHECK (MCHK_RD_F); /* machine check */
487 return 0;
488 }
489
490 /* WriteReg - write register space
491
492 Inputs:
493 pa = physical address
494 val = data to write, right justified in 32b longword
495 lnt = length (BWLQ)
496 Outputs:
497 none
498 */
499
500 void WriteReg (int32 pa, int32 val, int32 lnt)
501 {
502 int32 nexus;
503
504 if (ADDR_IS_REG (pa)) { /* reg space? */
505 nexus = NEXUS_GETNEX (pa); /* get nexus */
506 if (nexusW[nexus] && /* valid? */
507 (nexusW[nexus] (val, pa, lnt) == SCPE_OK)) {
508 SET_IRQL;
509 return;
510 }
511 }
512 sbi_set_tmo (pa); /* timeout */
513 mem_err = 1; /* interrupt */
514 eval_int ();
515 return;
516 }
517
518 /* Set SBI timeout - machine checks only on reads */
519
520 void sbi_set_tmo (int32 pa)
521 {
522 if ((sbi_er & SBIER_TMO) == 0) { /* not yet set? */
523 sbi_tmo = pa >> 2; /* save addr */
524 if (mchk_ref == REF_V) sbi_tmo |= SBITMO_VIRT | /* virt? add mode */
525 (PSL_GETCUR (PSL) << SBITMO_V_MODE);
526 sbi_er |= SBIER_TMO; /* set tmo flag */
527 }
528 else sbi_er |= SBIER_MULT; /* yes, multiple */
529 return;
530 }
531
532 /* Set SBI error confirmation - always machine checks */
533
534 void sbi_set_errcnf (void)
535 {
536 if (sbi_er & SBIER_CNF) sbi_er |= SBIER_MULT;
537 else sbi_er |= SBIER_CNF;
538 MACH_CHECK (MCHK_RD_F);
539 return;
540 }
541
542 /* Machine check
543
544 Error status word format
545 <2:0> = ASTLVL
546 <3> = PME
547 <6:4> = arith trap code
548 Rest will be zero
549 */
550
551 int32 machine_check (int32 p1, int32 opc, int32 cc, int32 delta)
552 {
553 int32 acc, err;
554
555 err = (GET_TRAP (trpirq) << 4) | (pme << 3) | ASTLVL; /* error word */
556 cc = intexc (SCB_MCHK, cc, 0, IE_SVE); /* take exception */
557 acc = ACC_MASK (KERN); /* in kernel mode */
558 in_ie = 1;
559 SP = SP - 44; /* push 11 words */
560 Write (SP, 40, L_LONG, WA); /* # bytes */
561 Write (SP + 4, p1, L_LONG, WA); /* mcheck type */
562 Write (SP + 8, err, L_LONG, WA); /* CPU error status */
563 Write (SP + 12, 0, L_LONG, WA); /* uPC */
564 Write (SP + 16, mchk_va, L_LONG, WA); /* VA */
565 Write (SP + 20, 0, L_LONG, WA); /* D register */
566 Write (SP + 24, mapen, L_LONG, WA); /* TB status 1 */
567 Write (SP + 28, 0, L_LONG, WA); /* TB status 2 */
568 Write (SP + 32, sbi_tmo, L_LONG, WA); /* SBI timeout addr */
569 Write (SP + 36, 0, L_LONG, WA); /* cache status */
570 Write (SP + 40, sbi_er, L_LONG, WA); /* SBI error */
571 in_ie = 0;
572 sbi_er = sbi_er & ~SBIER_TMOW1C; /* clr SBIER<tmo> etc */
573 return cc;
574 }
575
576 /* Console entry */
577
578 int32 con_halt (int32 code, int32 cc)
579 {
580 ABORT (STOP_HALT);
581 return cc;
582 }
583
584 /* Special boot command - linked into SCP by initial reset
585
586 Syntax: BOOT <device>{/R5:val}
587
588 Sets up R0-R5, calls SCP boot processor with effective BOOT CPU
589 */
590
591 t_stat vax780_boot (int32 flag, char *ptr)
592 {
593 char gbuf[CBUFSIZE];
594 char *slptr, *regptr;
595 int32 i, r5v, unitno;
596 DEVICE *dptr;
597 UNIT *uptr;
598 DIB *dibp;
599 t_stat r;
600
601 regptr = get_glyph (ptr, gbuf, 0); /* get glyph */
602 if (slptr = strchr (gbuf, '/')) { /* found slash? */
603 regptr = strchr (ptr, '/'); /* locate orig */
604 *slptr = 0; /* zero in string */
605 }
606 dptr = find_unit (gbuf, &uptr); /* find device */
607 if ((dptr == NULL) || (uptr == NULL)) return SCPE_ARG;
608 dibp = (DIB *) dptr->ctxt; /* get DIB */
609 if (dibp == NULL) return SCPE_ARG;
610 unitno = (int32) (uptr - dptr->units);
611 r5v = 0;
612 if ((strncmp (regptr, "/R5:", 4) == 0) ||
613 (strncmp (regptr, "/R5=", 4) == 0) ||
614 (strncmp (regptr, "/r5:", 4) == 0) ||
615 (strncmp (regptr, "/r5=", 4) == 0)) {
616 r5v = (int32) get_uint (regptr + 4, 16, LMASK, &r);
617 if (r != SCPE_OK) return r;
618 }
619 else if (*regptr != 0) return SCPE_ARG;
620 for (i = 0; boot_tab[i].name != NULL; i++) {
621 if (strcmp (dptr->name, boot_tab[i].name) == 0) {
622 R[0] = boot_tab[i].code;
623 if (dptr->flags & DEV_MBUS) {
624 R[1] = dibp->ba + TR_MBA0;
625 R[2] = unitno;
626 }
627 else {
628 R[1] = TR_UBA;
629 R[2] = boot_tab[i].let | (dibp->ba & UBADDRMASK);
630 }
631 R[3] = unitno;
632 R[4] = 0;
633 R[5] = r5v;
634 return run_cmd (flag, "CPU");
635 }
636 }
637 return SCPE_NOFNC;
638 }
639
640 /* Bootstrap - finish up bootstrap process */
641
642 t_stat cpu_boot (int32 unitno, DEVICE *dptr)
643 {
644 t_stat r;
645
646 printf ("Loading boot code from vmb.exe\n");
647 if (sim_log) fprintf (sim_log,
648 "Loading boot code from vmb.exe\n");
649 r = load_cmd (0, "-O vmb.exe 200");
650 if (r != SCPE_OK) return r;
651 SP = PC = 512;
652 return SCPE_OK;
653 }
654
655 /* SBI reset */
656
657 t_stat sbi_reset (DEVICE *dptr)
658 {
659 wcs_addr = 0;
660 wcs_data = 0;
661 wcs_mbrk = 0;
662 sbi_fs = 0;
663 sbi_sc = 0;
664 sbi_mt = 0;
665 sbi_er = 0;
666 sbi_tmo = 0;
667 sim_vm_cmd = vax780_cmd;
668 return SCPE_OK;
669 }
670
671 /* Show nexus */
672
673 t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc)
674 {
675 fprintf (st, "nexus=%d", val);
676 return SCPE_OK;
677 }
678
679 /* Init nexus tables */
680
681 void init_nexus_tab (void)
682 {
683 uint32 i;
684
685 for (i = 0; i < NEXUS_NUM; i++) {
686 nexusR[i] = NULL;
687 nexusW[i] = NULL;
688 }
689 return;
690 }
691
692 /* Build nexus tables
693
694 Inputs:
695 dptr = pointer to device
696 dibp = pointer to DIB
697 Outputs:
698 status
699 */
700
701
702 t_stat build_nexus_tab (DEVICE *dptr, DIB *dibp)
703 {
704 uint32 idx;
705
706 if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR;
707 idx = dibp->ba;
708 if (idx >= NEXUS_NUM) return SCPE_IERR;
709 if ((nexusR[idx] && dibp->rd && /* conflict? */
710 (nexusR[idx] != dibp->rd)) ||
711 (nexusW[idx] && dibp->wr &&
712 (nexusW[idx] != dibp->wr))) {
713 printf ("Nexus %s conflict at %d\n", sim_dname (dptr), dibp->ba);
714 if (sim_log) fprintf (sim_log,
715 "Nexus %s conflict at %d\n", sim_dname (dptr), dibp->ba);
716 return SCPE_STOP;
717 }
718 if (dibp->rd) nexusR[idx] = dibp->rd; /* set rd dispatch */
719 if (dibp->wr) nexusW[idx] = dibp->wr; /* set wr dispatch */
720 return SCPE_OK;
721 }
722
723 /* Build dib_tab from device list */
724
725 t_stat build_dib_tab (void)
726 {
727 uint32 i;
728 DEVICE *dptr;
729 DIB *dibp;
730 t_stat r;
731
732 init_nexus_tab ();
733 init_ubus_tab ();
734 init_mbus_tab ();
735 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
736 dibp = (DIB *) dptr->ctxt; /* get DIB */
737 if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */
738 if (dptr->flags & DEV_NEXUS) { /* Nexus? */
739 if (r = build_nexus_tab (dptr, dibp)) /* add to dispatch table */
740 return r;
741 }
742 else if (dptr->flags & DEV_MBUS) { /* Massbus? */
743 if (r = build_mbus_tab (dptr, dibp))
744 return r;
745 }
746 else { /* no, Unibus device */
747 if (r = build_ubus_tab (dptr, dibp)) /* add to dispatch tab */
748 return r;
749 } /* end else */
750 } /* end if enabled */
751 } /* end for */
752 return SCPE_OK;
753 }