First Commit of my working state
[simh.git] / PDP10 / pdp10_ksio.c
1 /* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator
2
3 Copyright (c) 1993-2005, 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 uba Unibus adapters
27
28 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
29 25-Jan-04 RMS Added stub floating address routine
30 12-Mar-03 RMS Added logical name support
31 10-Oct-02 RMS Revised for dynamic table generation
32 Added SHOW IOSPACE routine
33 29-Sep-02 RMS Added variable vector, central map support
34 25-Jan-02 RMS Revised for multiple DZ11's
35 06-Jan-02 RMS Revised enable/disable support
36 23-Sep-01 RMS New IO page address constants
37 07-Sep-01 RMS Revised device disable mechanism
38 25-Aug-01 RMS Enabled DZ11
39 21-Aug-01 RMS Updated DZ11 disable
40 01-Jun-01 RMS Updated DZ11 vectors
41 12-May-01 RMS Fixed typo
42
43 The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While
44 nominally four adapters are supported, in practice only 1 and 3
45 are implemented. The disks are placed on adapter 1, the rest of
46 the I/O devices on adapter 3.
47
48 In theory, we should maintain completely separate Unibuses, with
49 distinct PI systems. In practice, this simulator has so few devices
50 that we can get away with a single PI system, masking for which
51 devices are on adapter 1, and which on adapter 3. The Unibus
52 implementation is modeled on the Qbus in the PDP-11 simulator and
53 is described there.
54
55 The I/O subsystem is programmed by I/O instructions which create
56 Unibus operations (read, read pause, write, write byte). DMA is
57 the responsibility of the I/O device simulators, which also implement
58 Unibus to physical memory mapping.
59
60 The priority interrupt subsystem (and other privileged functions)
61 is programmed by I/O instructions with internal devices codes
62 (opcodes 700-702). These are dispatched here, although many are
63 handled in the memory management unit or elsewhere.
64
65 The ITS instructions are significantly different from the TOPS-10/20
66 instructions. They do not use the extended address calculation but
67 instead provide instruction variants (Q for Unibus adapter 1, I for
68 Unibus adapter 3) which insert the Unibus adapter number into the
69 effective address.
70 */
71
72 #include "pdp10_defs.h"
73 #include <setjmp.h>
74
75 #define XBA_MBZ 0400000 /* ba mbz */
76 #define eaRB (ea & ~1)
77 #define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377)
78 #define UBNXM_FAIL(pa,op) \
79 n = iocmap[GET_IOUBA (pa)]; \
80 if (n >= 0) ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \
81 pager_word = PF_HARD | PF_VIRT | PF_IO | \
82 ((op == WRITEB)? PF_BYTE: 0) | \
83 (TSTF (F_USR)? PF_USER: 0) | (pa); \
84 ABORT (PAGE_FAIL)
85
86 /* Unibus adapter data */
87
88 int32 ubcs[UBANUM] = { 0 }; /* status registers */
89 int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */
90 int32 int_req = 0; /* interrupt requests */
91
92 /* Map IO controller numbers to Unibus adapters: -1 = non-existent */
93
94 static int iocmap[IO_N_UBA] = { /* map I/O ext to UBA # */
95 -1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
96 };
97
98 static const int32 ubabr76[UBANUM] = {
99 INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6)
100 };
101 static const int32 ubabr54[UBANUM] = {
102 INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4)
103 };
104 static const int32 ubashf[4] = { 18, 26, 0, 8 };
105
106 extern d10 *M; /* main memory */
107 extern d10 *ac_cur;
108 extern d10 pager_word;
109 extern int32 flags;
110 extern const int32 pi_l2bit[8];
111 extern UNIT cpu_unit;
112 extern FILE *sim_log;
113 extern jmp_buf save_env;
114 extern DEVICE *sim_devices[];
115
116 extern int32 pi_eval (void);
117 extern int32 rp_inta (void);
118 extern int32 tu_inta (void);
119 extern int32 lp20_inta (void);
120 extern int32 dz_rxinta (void);
121 extern int32 dz_txinta (void);
122
123 t_stat ubmap_rd (int32 *data, int32 addr, int32 access);
124 t_stat ubmap_wr (int32 data, int32 addr, int32 access);
125 t_stat ubs_rd (int32 *data, int32 addr, int32 access);
126 t_stat ubs_wr (int32 data, int32 addr, int32 access);
127 t_stat rd_zro (int32 *data, int32 addr, int32 access);
128 t_stat wr_nop (int32 data, int32 addr, int32 access);
129 t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
130 t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
131 t_stat uba_reset (DEVICE *dptr);
132 d10 ReadIO (a10 ea);
133 void WriteIO (a10 ea, d10 val, int32 mode);
134
135 /* Unibus adapter data structures
136
137 uba_dev UBA device descriptor
138 uba_unit UBA units
139 uba_reg UBA register list
140 */
141
142 DIB ubmp1_dib = { IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr, 0 };
143 DIB ubmp3_dib = { IOBA_UBMAP3, IOLN_UBMAP3, &ubmap_rd, &ubmap_wr, 0 };
144 DIB ubcs1_dib = { IOBA_UBCS1, IOLN_UBCS1, &ubs_rd, &ubs_wr, 0 };
145 DIB ubcs3_dib = { IOBA_UBCS3, IOLN_UBCS3, &ubs_rd, &ubs_wr, 0 };
146 DIB ubmn1_dib = { IOBA_UBMNT1, IOLN_UBMNT1, &rd_zro, &wr_nop, 0 };
147 DIB ubmn3_dib = { IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop, 0 };
148 DIB msys_dib = { 00100000, 1, &rd_zro, &wr_nop, 0 };
149
150 UNIT uba_unit[] = {
151 { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) },
152 { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) }
153 };
154
155 REG uba_reg[] = {
156 { ORDATA (INTREQ, int_req, 32), REG_RO },
157 { ORDATA (UB1CS, ubcs[0], 18) },
158 { ORDATA (UB3CS, ubcs[1], 18) },
159 { NULL }
160 };
161
162 DEVICE uba_dev = {
163 "UBA", uba_unit, uba_reg, NULL,
164 UBANUM, 8, UMAP_ASIZE, 1, 8, 32,
165 &uba_ex, &uba_dep, &uba_reset,
166 NULL, NULL, NULL,
167 NULL, 0
168 };
169
170 /* PDP-11 I/O structures */
171
172 DIB *dib_tab[DIB_MAX]; /* run-time DIBs */
173
174 int32 (*int_ack[32])(void); /* int ack routines */
175
176 int32 int_vec[32]; /* int vectors */
177
178 DIB *std_dib[] = { /* standard DIBs */
179 &ubmp1_dib,
180 &ubmp3_dib,
181 &ubcs1_dib,
182 &ubcs3_dib,
183 &ubmn1_dib,
184 &ubmn3_dib,
185 &msys_dib,
186 NULL
187 };
188
189 /* IO 710 (DEC) TIOE - test I/O word, skip if zero
190 (ITS) IORDI - read word from Unibus 3
191 returns TRUE if skip, FALSE otherwise
192 */
193
194 t_bool io710 (int32 ac, a10 ea)
195 {
196 d10 val;
197
198 if (Q_ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */
199 else { /* TIOE */
200 val = ReadIO (ea); /* read word */
201 if ((AC(ac) & val) == 0) return TRUE;
202 }
203 return FALSE;
204 }
205
206 /* IO 711 (DEC) TION - test I/O word, skip if non-zero
207 (ITS) IORDQ - read word from Unibus 1
208 returns TRUE if skip, FALSE otherwise
209 */
210
211 t_bool io711 (int32 ac, a10 ea)
212 {
213 d10 val;
214
215 if (Q_ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */
216 else { /* TION */
217 val = ReadIO (ea); /* read word */
218 if ((AC(ac) & val) != 0) return TRUE;
219 }
220 return FALSE;
221 }
222
223 /* IO 712 (DEC) RDIO - read I/O word, addr in ea
224 (ITS) IORD - read I/O word, addr in M[ea]
225 */
226
227 d10 io712 (a10 ea)
228 {
229 return ReadIO (ea); /* RDIO, IORD */
230 }
231
232 /* IO 713 (DEC) WRIO - write I/O word, addr in ea
233 (ITS) IOWR - write I/O word, addr in M[ea]
234 */
235
236 void io713 (d10 val, a10 ea)
237 {
238 WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */
239 return;
240 }
241
242 /* IO 714 (DEC) BSIO - set bit in I/O address
243 (ITS) IOWRI - write word to Unibus 3
244 */
245
246 void io714 (d10 val, a10 ea)
247 {
248 d10 temp;
249
250 val = val & 0177777;
251 if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */
252 else {
253 temp = ReadIO (ea); /* BSIO */
254 temp = temp | val;
255 WriteIO (ea, temp, WRITE);
256 }
257 return;
258 }
259
260 /* IO 715 (DEC) BCIO - clear bit in I/O address
261 (ITS) IOWRQ - write word to Unibus 1
262 */
263
264 void io715 (d10 val, a10 ea)
265 {
266 d10 temp;
267
268 val = val & 0177777;
269 if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */
270 else {
271 temp = ReadIO (ea); /* BCIO */
272 temp = temp & ~val;
273 WriteIO (ea, temp, WRITE);
274 }
275 return;
276 }
277
278 /* IO 720 (DEC) TIOEB - test I/O byte, skip if zero
279 (ITS) IORDBI - read byte from Unibus 3
280 returns TRUE if skip, FALSE otherwise
281 */
282
283 t_bool io720 (int32 ac, a10 ea)
284 {
285 d10 val;
286
287 if (Q_ITS) { /* IORDBI */
288 val = ReadIO (IO_UBA3 | eaRB);
289 AC(ac) = GETBYTE (ea, val);
290 }
291 else { /* TIOEB */
292 val = ReadIO (eaRB);
293 val = GETBYTE (ea, val);
294 if ((AC(ac) & val) == 0) return TRUE;
295 }
296 return FALSE;
297 }
298
299 /* IO 721 (DEC) TIONB - test I/O word, skip if non-zero
300 (ITS) IORDBQ - read word from Unibus 1
301 returns TRUE if skip, FALSE otherwise
302 */
303
304 t_bool io721 (int32 ac, a10 ea)
305 {
306 d10 val;
307
308 if (Q_ITS) { /* IORDBQ */
309 val = ReadIO (IO_UBA1 | eaRB);
310 AC(ac) = GETBYTE (ea, val);
311 }
312 else { /* TIONB */
313 val = ReadIO (eaRB);
314 val = GETBYTE (ea, val);
315 if ((AC(ac) & val) != 0) return TRUE;
316 }
317 return FALSE;
318 }
319
320 /* IO 722 (DEC) RDIOB - read I/O byte, addr in ea
321 (ITS) IORDB - read I/O byte, addr in M[ea]
322 */
323
324 d10 io722 (a10 ea)
325 {
326 d10 val;
327
328 val = ReadIO (eaRB); /* RDIOB, IORDB */
329 return GETBYTE (ea, val);
330 }
331
332 /* IO 723 (DEC) WRIOB - write I/O byte, addr in ea
333 (ITS) IOWRB - write I/O byte, addr in M[ea]
334 */
335
336 void io723 (d10 val, a10 ea)
337 {
338 WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */
339 return;
340 }
341
342 /* IO 724 (DEC) BSIOB - set bit in I/O byte address
343 (ITS) IOWRBI - write byte to Unibus 3
344 */
345
346 void io724 (d10 val, a10 ea)
347 {
348 d10 temp;
349
350 val = val & 0377;
351 if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */
352 else {
353 temp = ReadIO (eaRB); /* BSIOB */
354 temp = GETBYTE (ea, temp);
355 temp = temp | val;
356 WriteIO (ea, temp, WRITEB);
357 }
358 return;
359 }
360
361 /* IO 725 (DEC) BCIOB - clear bit in I/O byte address
362 (ITS) IOWRBQ - write byte to Unibus 1
363 */
364
365 void io725 (d10 val, a10 ea)
366 {
367 d10 temp;
368
369 val = val & 0377;
370 if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */
371 else {
372 temp = ReadIO (eaRB); /* BCIOB */
373 temp = GETBYTE (ea, temp);
374 temp = temp & ~val;
375 WriteIO (ea, temp, WRITEB);
376 }
377 return;
378 }
379
380 /* Read and write I/O devices.
381 These routines are the linkage between the 64b world of the main
382 simulator and the 32b world of the device simulators.
383 */
384
385 d10 ReadIO (a10 ea)
386 {
387 uint32 pa = (uint32) ea;
388 int32 i, n, val;
389 DIB *dibp;
390
391 for (i = 0; dibp = dib_tab[i]; i++ ) {
392 if ((pa >= dibp->ba) &&
393 (pa < (dibp->ba + dibp->lnt))) {
394 dibp->rd (&val, pa, READ);
395 pi_eval ();
396 return ((d10) val);
397 }
398 }
399 UBNXM_FAIL (pa, READ);
400 }
401
402 void WriteIO (a10 ea, d10 val, int32 mode)
403 {
404 uint32 pa = (uint32) ea;
405 int32 i, n;
406 DIB *dibp;
407
408 for (i = 0; dibp = dib_tab[i]; i++ ) {
409 if ((pa >= dibp->ba) &&
410 (pa < (dibp->ba + dibp->lnt))) {
411 dibp->wr ((int32) val, pa, mode);
412 pi_eval ();
413 return;
414 }
415 }
416 UBNXM_FAIL (pa, mode);
417 }
418
419 /* Mapped read and write routines - used by standard Unibus devices on Unibus 1 */
420
421 a10 Map_Addr10 (a10 ba, int32 ub)
422 {
423 a10 pa10;
424 int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */
425
426 if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) ||
427 ((ubmap[ub][vpn] & UMAP_VLD) == 0)) return -1; /* invalid map? */
428 pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;
429 return pa10;
430 }
431
432 int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)
433 {
434 uint32 lim;
435 a10 pa10;
436
437 lim = ba + bc;
438 for ( ; ba < lim; ba++) { /* by bytes */
439 pa10 = Map_Addr10 (ba, 1); /* map addr */
440 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
441 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
442 return (lim - ba); /* return bc */
443 }
444 *buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);
445 }
446 return 0;
447 }
448
449 int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
450 {
451 uint32 lim;
452 a10 pa10;
453
454 ba = ba & ~01; /* align start */
455 lim = ba + (bc & ~01);
456 for ( ; ba < lim; ba = ba + 2) { /* by words */
457 pa10 = Map_Addr10 (ba, 1); /* map addr */
458 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
459 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
460 return (lim - ba); /* return bc */
461 }
462 *buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
463 }
464 return 0;
465 }
466
467 int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)
468 {
469 uint32 lim;
470 a10 pa10;
471 d10 mask;
472
473 lim = ba + bc;
474 for ( ; ba < lim; ba++) { /* by bytes */
475 pa10 = Map_Addr10 (ba, 1); /* map addr */
476 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
477 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
478 return (lim - ba); /* return bc */
479 }
480 mask = 0377;
481 M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) |
482 (((d10) *buf++) << ubashf[ba & 3]);
483 }
484 return 0;
485 }
486
487 int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)
488 {
489 uint32 lim;
490 a10 pa10;
491 d10 val;
492
493 ba = ba & ~01; /* align start */
494 lim = ba + (bc & ~01);
495 for ( ; ba < lim; ba++) { /* by bytes */
496 pa10 = Map_Addr10 (ba, 1); /* map addr */
497 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
498 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
499 return (lim - ba); /* return bc */
500 }
501 val = *buf++; /* get data */
502 if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val;
503 else M[pa10] = (M[pa10] & 0600000777777) | (val << 18);
504 }
505 return 0;
506 }
507
508 /* Evaluate Unibus priority interrupts */
509
510 int32 pi_ub_eval ()
511 {
512 int32 i, lvl;
513
514 for (i = lvl = 0; i < UBANUM; i++) {
515 if (int_req & ubabr76[i])
516 lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];
517 if (int_req & ubabr54[i])
518 lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])];
519 }
520 return lvl;
521 }
522
523 /* Return Unibus device vector
524
525 Takes as input the request level calculated by pi_eval
526 If there is an interrupting Unibus device at that level, return its vector,
527 otherwise, returns 0
528 */
529
530 int32 pi_ub_vec (int32 rlvl, int32 *uba)
531 {
532 int32 i, masked_irq;
533
534 for (i = masked_irq = 0; i < UBANUM; i++) {
535 if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */
536 (masked_irq = int_req & ubabr76[i])) break;
537 if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */
538 (masked_irq = int_req & ubabr54[i])) break;
539 }
540 *uba = (i << 1) + 1; /* store uba # */
541 for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */
542 if ((masked_irq >> i) & 1) {
543 int_req = int_req & ~(1u << i); /* clear req */
544 if (int_ack[i]) return int_ack[i]();
545 return int_vec[i]; /* return vector */
546 }
547 }
548 return 0;
549 }
550
551 /* Unibus adapter map routines */
552
553 t_stat ubmap_rd (int32 *val, int32 pa, int32 mode)
554 {
555 int32 n = iocmap[GET_IOUBA (pa)];
556
557 if (n < 0) ABORT (STOP_ILLIOC);
558 *val = ubmap[n][pa & UMAP_AMASK];
559 return SCPE_OK;
560 }
561
562 t_stat ubmap_wr (int32 val, int32 pa, int32 mode)
563 {
564 int32 n = iocmap[GET_IOUBA (pa)];
565
566 if (n < 0) ABORT (STOP_ILLIOC);
567 ubmap[n][pa & UMAP_AMASK] = UMAP_POSFL (val) | UMAP_POSPN (val);
568 return SCPE_OK;
569 }
570
571 /* Unibus adapter control/status routines */
572
573 t_stat ubs_rd (int32 *val, int32 pa, int32 mode)
574 {
575 int32 n = iocmap[GET_IOUBA (pa)];
576
577 if (n < 0) ABORT (STOP_ILLIOC);
578 if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;
579 if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;
580 *val = ubcs[n] = ubcs[n] & ~UBCS_RDZ;
581 return SCPE_OK;
582 }
583
584 t_stat ubs_wr (int32 val, int32 pa, int32 mode)
585 {
586 int32 n = iocmap[GET_IOUBA (pa)];
587
588 if (n < 0) ABORT (STOP_ILLIOC);
589 if (val & UBCS_INI) {
590 reset_all (5); /* start after UBA */
591 ubcs[n] = val & UBCS_DXF;
592 }
593 else ubcs[n] = val & UBCS_RDW;
594 if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;
595 if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;
596 return SCPE_OK;
597 }
598
599 /* Unibus adapter read zero/write ignore routines */
600
601 t_stat rd_zro (int32 *val, int32 pa, int32 mode)
602 {
603 *val = 0;
604 return SCPE_OK;
605 }
606
607 t_stat wr_nop (int32 val, int32 pa, int32 mode)
608 {
609 return SCPE_OK;
610 }
611
612 /* Simulator interface routines */
613
614 t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
615 {
616 int32 uba = uptr - uba_unit;
617
618 if (addr >= UMAP_MEMSIZE) return SCPE_NXM;
619 *vptr = ubmap[uba][addr];
620 return SCPE_OK;
621 }
622
623 t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
624 {
625 int32 uba = uptr - uba_unit;
626
627 if (addr >= UMAP_MEMSIZE) return SCPE_NXM;
628 ubmap[uba][addr] = (int32) val & UMAP_MASK;
629 return SCPE_OK;
630 }
631
632 t_stat uba_reset (DEVICE *dptr)
633 {
634 int32 i, uba;
635
636 int_req = 0;
637 for (uba = 0; uba < UBANUM; uba++) {
638 ubcs[uba] = 0;
639 for (i = 0; i < UMAP_MEMSIZE; i++) ubmap[uba][i] = 0;
640 }
641 pi_eval ();
642 return SCPE_OK;
643 }
644
645 /* Change device address */
646
647 t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)
648 {
649 DEVICE *dptr;
650 DIB *dibp;
651 uint32 newba;
652 t_stat r;
653
654 if (cptr == NULL) return SCPE_ARG;
655 if ((val == 0) || (uptr == NULL)) return SCPE_IERR;
656 dptr = find_dev_from_unit (uptr);
657 if (dptr == NULL) return SCPE_IERR;
658 dibp = (DIB *) dptr->ctxt;
659 if (dibp == NULL) return SCPE_IERR;
660 newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */
661 if ((r != SCPE_OK) || (newba == dibp->ba)) return r;
662 if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;
663 if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */
664 if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;
665 dibp->ba = newba; /* store */
666 return SCPE_OK;
667 }
668
669 /* Show device address */
670
671 t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc)
672 {
673 DEVICE *dptr;
674 DIB *dibp;
675
676 if (uptr == NULL) return SCPE_IERR;
677 dptr = find_dev_from_unit (uptr);
678 if (dptr == NULL) return SCPE_IERR;
679 dibp = (DIB *) dptr->ctxt;
680 if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;
681 fprintf (st, "address=%07o", dibp->ba);
682 if (dibp->lnt > 1)
683 fprintf (st, "-%07o", dibp->ba + dibp->lnt - 1);
684 return SCPE_OK;
685 }
686
687 /* Change device vector */
688
689 t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc)
690 {
691 DEVICE *dptr;
692 DIB *dibp;
693 uint32 newvec;
694 t_stat r;
695
696 if (cptr == NULL) return SCPE_ARG;
697 if (uptr == NULL) return SCPE_IERR;
698 dptr = find_dev_from_unit (uptr);
699 if (dptr == NULL) return SCPE_IERR;
700 dibp = (DIB *) dptr->ctxt;
701 if (dibp == NULL) return SCPE_IERR;
702 newvec = (uint32) get_uint (cptr, 8, VEC_Q + 01000, &r);
703 if ((r != SCPE_OK) || (newvec == VEC_Q) ||
704 ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) ||
705 (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG;
706 dibp->vec = newvec;
707 return SCPE_OK;
708 }
709
710 /* Show device vector */
711
712 t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc)
713 {
714 DEVICE *dptr;
715 DIB *dibp;
716 uint32 vec, numvec;
717
718 if (uptr == NULL) return SCPE_IERR;
719 dptr = find_dev_from_unit (uptr);
720 if (dptr == NULL) return SCPE_IERR;
721 dibp = (DIB *) dptr->ctxt;
722 if (dibp == NULL) return SCPE_IERR;
723 vec = dibp->vec;
724 if (arg) numvec = arg;
725 else numvec = dibp->vnum;
726 if (vec == 0) fprintf (st, "no vector");
727 else {
728 fprintf (st, "vector=%o", vec);
729 if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1)));
730 }
731 return SCPE_OK;
732 }
733
734 /* Test for conflict in device addresses */
735
736 t_bool dev_conflict (DIB *curr)
737 {
738 uint32 i, end;
739 DEVICE *dptr;
740 DIB *dibp;
741
742 end = curr->ba + curr->lnt - 1; /* get end */
743 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
744 dibp = (DIB *) dptr->ctxt; /* get DIB */
745 if ((dibp == NULL) || (dibp == curr) ||
746 (dptr->flags & DEV_DIS)) continue;
747 if (((curr->ba >= dibp->ba) && /* overlap start? */
748 (curr->ba < (dibp->ba + dibp->lnt))) ||
749 ((end >= dibp->ba) && /* overlap end? */
750 (end < (dibp->ba + dibp->lnt)))) {
751 printf ("Device %s address conflict at %08o\n",
752 sim_dname (dptr), dibp->ba);
753 if (sim_log) fprintf (sim_log,
754 "Device %s address conflict at %08o\n",
755 sim_dname (dptr), dibp->ba);
756 return TRUE;
757 }
758 }
759 return FALSE;
760 }
761
762 /* Build interrupt tables */
763
764 void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) )
765 {
766 if (iack != NULL) int_ack[vloc] = iack;
767 else int_vec[vloc] = ivec;
768 return;
769 }
770
771 /* Build dib_tab from device list */
772
773 t_bool build_dib_tab (void)
774 {
775 int32 i, j, k;
776 DEVICE *dptr;
777 DIB *dibp;
778
779 for (i = 0; i < 32; i++) { /* clear intr tables */
780 int_vec[i] = 0;
781 int_ack[i] = NULL;
782 }
783 for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
784 dibp = (DIB *) dptr->ctxt; /* get DIB */
785 if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */
786 if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;
787 for (k = 0; k < dibp->vnum; k++) /* loop thru vec */
788 build_int_vec (dibp->vloc + k, /* add vector */
789 dibp->vec + (k * 4), dibp->ack[k]);
790 if (dibp->lnt != 0) { /* I/O addresses? */
791 dib_tab[j++] = dibp; /* add DIB to dib_tab */
792 if (j >= DIB_MAX) return SCPE_IERR; /* too many? */
793 }
794 } /* end if enabled */
795 } /* end for */
796 for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */
797 dib_tab[j++] = dibp; /* add to dib_tab */
798 if (j >= DIB_MAX) return SCPE_IERR; /* too many? */
799 }
800 dib_tab[j] = NULL; /* end with NULL */
801 for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */
802 if (dev_conflict (dibp)) return SCPE_STOP; /* for conflicts */
803 }
804 return SCPE_OK;
805 }
806
807 /* Show dib_tab */
808
809 t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc)
810 {
811 int32 i, j, done = 0;
812 DEVICE *dptr;
813 DIB *dibt;
814
815 build_dib_tab (); /* build table */
816 while (done == 0) { /* sort ascending */
817 done = 1; /* assume done */
818 for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */
819 if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */
820 dibt = dib_tab[i]; /* interchange */
821 dib_tab[i] = dib_tab[i + 1];
822 dib_tab[i + 1] = dibt;
823 done = 0; /* not done */
824 }
825 }
826 } /* end while */
827 for (i = 0; dib_tab[i] != NULL; i++) { /* print table */
828 for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
829 if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) {
830 dptr = sim_devices[j];
831 break;
832 }
833 }
834 fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba,
835 dib_tab[i]->ba + dib_tab[i]->lnt - 1,
836 dptr? sim_dname (dptr): "CPU");
837 }
838 return SCPE_OK;
839 }
840
841 /* Stub auto-configure */
842
843 t_stat auto_config (char *name, int32 num)
844 {
845 return SCPE_OK;
846 }
847
848 /* Stub floating address */
849
850 t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc)
851 {
852 return SCPE_OK;
853 }