1 /* id_io.c: Interdata CPU-independent I/O routines
2
3 Copyright (c) 2001-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 30-Mar-06 RMS Fixed bug, GO preserves EXA and SSTA (Davis Johnson)
27 21-Jun-03 RMS Changed subroutine argument for ARM compiler conflict
28
29 Interdata I/O devices are defined by a device information block:
30
31 dno base device number
32 sch selector channel, -1 if none
33 irq interrupt request flag
34 tplte device number template, NULL if one device number
35 iot I/O processing routine
36 ini initialization routine
37
38 Interdata I/O uses the following interconnected tables:
39
40 dev_tab[dev] Indexed by device number, points to the I/O instruction
41 processing routine for the device.
42
43 sch_tab[dev] Indexed by device number, if non-zero, the number + 1
44 of the selector channel used by the device.
45
46 int_req[level] Indexed by interrupt level, device interrupt flags.
47
48 int_enb[level] Indexed by interrupt level, device interrupt enable flags.
49
50 int_tab[idx] Indexed by ((interrupt level * 32) + interrupt number),
51 maps bit positions in int_req to device numbers.
52 */
53
54 #include "id_defs.h"
55
56 /* Selector channel */
57
58 #define SCHC_EXA 0x40 /* read ext addr */
59 #define SCHC_RD 0x20 /* read */
60 #define SCHC_GO 0x10 /* go */
61 #define SCHC_STOP 0x08 /* stop */
62 #define SCHC_SSTA 0x04 /* sel ch status */
63 #define SCHC_EXM 0x03 /* ext mem */
64
65 extern uint32 int_req[INTSZ], int_enb[INTSZ];
66 extern uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout);
67 extern uint32 pawidth;
68 extern UNIT cpu_unit;
69 extern FILE *sim_log;
70 extern DEVICE *sim_devices[];
71
72 uint32 sch_max = 2; /* sch count */
73 uint32 sch_sa[SCH_NUMCH] = { 0 }; /* start addr */
74 uint32 sch_ea[SCH_NUMCH] = { 0 }; /* end addr */
75 uint8 sch_sdv[SCH_NUMCH] = { 0 }; /* device */
76 uint8 sch_cmd[SCH_NUMCH] = { 0 }; /* command */
77 uint8 sch_rdp[SCH_NUMCH] = { 0 }; /* read ptr */
78 uint8 sch_wdc[SCH_NUMCH] = { 0 }; /* write ctr */
79 uint32 sch_tab[DEVNO] = { 0 }; /* dev to sch map */
80 uint32 int_tab[INTSZ * 32] = { 0 }; /* int to dev map */
81 uint8 sch_tplte[SCH_NUMCH + 1]; /* dnum template */
82
83 uint32 sch (uint32 dev, uint32 op, uint32 dat);
84 void sch_ini (t_bool dtpl);
85 t_stat sch_reset (DEVICE *dptr);
86 t_stat sch_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc);
87 t_stat sch_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc);
88 t_stat sch_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc);
89
90 /* Selector channel data structures
91
92 sch_dev channel device descriptor
93 sch_unit channel unit descriptor
94 sch_mod channel modifiers list
95 sch_reg channel register list
96 */
97
98 DIB sch_dib = { d_SCH, -1, v_SCH, sch_tplte, &sch, &sch_ini };
99
100 UNIT sch_unit = { UDATA (NULL, 0, 0) };
101
102 REG sch_reg[] = {
103 { HRDATA (CHAN, sch_max, 3), REG_HRO },
104 { BRDATA (SA, sch_sa, 16, 20, SCH_NUMCH) },
105 { BRDATA (EA, sch_ea, 16, 20, SCH_NUMCH) },
106 { BRDATA (CMD, sch_cmd, 16, 8, SCH_NUMCH) },
107 { BRDATA (DEV, sch_sdv, 16, 8, SCH_NUMCH) },
108 { BRDATA (RDP, sch_rdp, 16, 2, SCH_NUMCH) },
109 { BRDATA (WDC, sch_wdc, 16, 3, SCH_NUMCH) },
110 { GRDATA (IREQ, int_req[l_SCH], 16, SCH_NUMCH, i_SCH) },
111 { GRDATA (IENB, int_enb[l_SCH], 16, SCH_NUMCH, i_SCH) },
112 { HRDATA (DEVNO, sch_dib.dno, 8), REG_HRO },
113 { NULL }
114 };
115
116 MTAB sch_mod[] = {
117 { MTAB_XTD|MTAB_VDV, 0, "channels", "CHANNELS",
118 &sch_set_nchan, &sch_show_nchan, NULL },
119 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "0", NULL,
120 NULL, &sch_show_reg, NULL },
121 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "1", NULL,
122 NULL, &sch_show_reg, NULL },
123 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 2, "2", NULL,
124 NULL, &sch_show_reg, NULL },
125 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 3, "3", NULL,
126 NULL, &sch_show_reg, NULL },
127 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
128 &set_dev, &show_dev, &sch_dib },
129 { 0 }
130 };
131
132 DEVICE sch_dev = {
133 "SELCH", &sch_unit, sch_reg, sch_mod,
134 1, 16, 8, 1, 16, 8,
135 NULL, NULL, &sch_reset,
136 NULL, NULL, NULL,
137 &sch_dib, 0
138 };
139
140 /* (Extended) selector channel
141
142 There are really three different selector channels:
143 - 16b selector channel (max 4B of data)
144 - 18b selector channel (max 4B of data)
145 - 20b selector channel (max 6B of data)
146 The algorithm for loading the start and end addresses is taken
147 from the maintenance manual for the Extended Selector Channel.
148 */
149
150 #define SCH_EXR(ch) ((sch_cmd[ch] & SCHC_EXA) && (pawidth == PAWIDTH32))
151
sch(uint32 dev,uint32 op,uint32 dat)152 uint32 sch (uint32 dev, uint32 op, uint32 dat)
153 {
154 uint32 t, bank, sdv, ch = dev - sch_dib.dno;
155
156 switch (op) { /* case IO op */
157
158 case IO_ADR: /* select */
159 return BY; /* byte only */
160
161 case IO_RD: /* read data */
162 t = (sch_sa[ch] >> (sch_rdp[ch] * 8)) & DMASK8; /* get sa byte */
163 if (sch_rdp[ch] == 0) sch_rdp[ch] = /* wrap? */
164 SCH_EXR (ch)? 2: 1;
165 else sch_rdp[ch] = sch_rdp[ch] - 1; /* dec byte ptr */
166 return t;
167
168 case IO_WD: /* write data */
169 if (pawidth != PAWIDTH32) { /* 16b? max 4 */
170 if (sch_wdc[ch] >= 4) /* stop at 4 */
171 break;
172 sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea to sa */
173 (sch_ea[ch] >> 8)) & DMASK16;
174 sch_ea[ch] = ((sch_ea[ch] << 8) | /* ripple ea low */
175 dat) & DMASK16; /* insert byte */
176 }
177 else { /* 32b? max 6 */
178 if (sch_wdc[ch] >= 6) /* stop at 6 */
179 break;
180 if (sch_wdc[ch] != 5) { /* if not last */
181 sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea<15:8> to sa */
182 ((sch_ea[ch] >> 8) & DMASK8)) & PAMASK32;
183 sch_ea[ch] = /* ripple ea<7:0> */
184 (((sch_ea[ch] & DMASK8) << 8) | dat) & PAMASK32;
185 }
186 else sch_ea[ch] = ((sch_ea[ch] << 8) | dat) & PAMASK32;
187 }
188 sch_wdc[ch] = sch_wdc[ch] + 1; /* adv sequencer */
189 break;
190
191 case IO_SS: /* status */
192 if (sch_cmd[ch] & SCHC_GO) /* test busy */
193 return STA_BSY;
194 if (sch_cmd[ch] & SCHC_SSTA) /* test sch sta */
195 return 0;
196 else {
197 sdv = sch_sdv[ch]; /* get dev */
198 if (dev_tab[sdv] == 0) /* not there? */
199 return CC_V;
200 dev_tab[sdv] (sdv, IO_ADR, 0); /* select dev */
201 t = dev_tab[sdv] (sdv, IO_SS, 0); /* get status */
202 return t & ~STA_BSY; /* clr busy */
203 }
204
205 case IO_OC: /* command */
206 bank = 0; /* assume no bank */
207 if (pawidth != PAWIDTH32) { /* 16b/18b proc? */
208 dat = dat & ~(SCHC_EXA | SCHC_SSTA); /* clr ext func */
209 if (pawidth == PAWIDTH16E) /* 18b proc? */
210 bank = (dat & SCHC_EXM) << 16;
211 }
212 if (dat & SCHC_STOP) { /* stop? */
213 sch_cmd[ch] = dat & (SCHC_EXA | SCHC_SSTA); /* clr go */
214 CLR_INT (v_SCH + ch); /* clr intr */
215 sch_rdp[ch] = SCH_EXR (ch)? 2: 1; /* init sequencers */
216 sch_wdc[ch] = 0;
217 }
218 else if (dat & SCHC_GO) { /* go? */
219 sch_cmd[ch] = dat & (SCHC_EXA | SCHC_SSTA| SCHC_GO | SCHC_RD);
220 if (sch_wdc[ch] <= 4) { /* 4 bytes? */
221 sch_sa[ch] = (sch_sa[ch] & PAMASK16) | bank; /* 16b addr */
222 sch_ea[ch] = (sch_ea[ch] & PAMASK16) | bank;
223 }
224 sch_sa[ch] = sch_sa[ch] & ~1;
225 if (sch_ea[ch] <= sch_sa[ch]) /* wrap? */
226 sch_ea[ch] = sch_ea[ch] | /* modify end addr */
227 ((pawidth == PAWIDTH32)? PAMASK32: PAMASK16);
228 }
229 break;
230 }
231
232 return 0;
233 }
234
235 /* CPU call to test if channel blocks access to device */
236
sch_blk(uint32 dev)237 t_bool sch_blk (uint32 dev)
238 {
239 uint32 ch = sch_tab[dev] - 1;
240
241 if ((ch < sch_max) && (sch_cmd[ch] & SCHC_GO))
242 return TRUE;
243 return FALSE;
244 }
245
246 /* Device call to 'remember' last dev on channel */
247
sch_adr(uint32 ch,uint32 dev)248 void sch_adr (uint32 ch, uint32 dev)
249 {
250 if (ch < sch_max)
251 sch_sdv[ch] = dev;
252 return;
253 }
254
255 /* Device call to see if selector channel is active for device */
256
sch_actv(uint32 ch,uint32 dev)257 t_bool sch_actv (uint32 ch, uint32 dev)
258 {
259 if ((ch < sch_max) && /* chan valid, */
260 (sch_cmd[ch] & SCHC_GO) && /* on, and */
261 (sch_sdv[ch] == dev)) /* set for dev? */
262 return TRUE;
263 return FALSE; /* no */
264 }
265
266 /* Device call to read a block of memory */
267
sch_rdmem(uint32 ch,uint8 * buf,uint32 cnt)268 uint32 sch_rdmem (uint32 ch, uint8 *buf, uint32 cnt)
269 {
270 uint32 addr, end, xfr, inc;
271
272 if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0))
273 return 0;
274 addr = sch_sa[ch]; /* start */
275 end = sch_ea[ch]; /* end */
276 xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */
277 inc = IOReadBlk (addr, xfr, buf); /* read mem */
278 if ((addr + inc) > end) { /* end? */
279 SET_INT (v_SCH + ch); /* interrupt */
280 sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */
281 sch_sa[ch] = sch_sa[ch] + inc - 1; /* end addr */
282 }
283 else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */
284 return inc;
285 }
286
287 /* Device call to write a block of memory */
288
sch_wrmem(uint32 ch,uint8 * buf,uint32 cnt)289 uint32 sch_wrmem (uint32 ch, uint8 *buf, uint32 cnt)
290 {
291 uint32 addr, end, xfr, inc;
292
293 if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0))
294 return 0;
295 addr = sch_sa[ch]; /* start */
296 end = sch_ea[ch]; /* end */
297 xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */
298 inc = IOWriteBlk (addr, xfr, buf); /* write mem */
299 if ((addr + inc) > end) { /* end? */
300 SET_INT (v_SCH + ch); /* interrupt */
301 sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */
302 sch_sa[ch] = sch_sa[ch] + inc - 1; /* end addr */
303 }
304 else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */
305 return inc;
306 }
307
308 /* Device call to stop a selector channel */
309
sch_stop(uint32 ch)310 void sch_stop (uint32 ch)
311 {
312 if (ch < sch_max) {
313 SET_INT (v_SCH + ch); /* interrupt */
314 sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */
315 }
316 return;
317 }
318
319 /* Reset */
320
sch_reset_ch(uint32 rst_lim)321 void sch_reset_ch (uint32 rst_lim)
322 {
323 uint32 ch;
324
325 for (ch = 0; ch < SCH_NUMCH; ch++) {
326 if (ch >= rst_lim) {
327 CLR_INT (v_SCH + ch);
328 SET_ENB (v_SCH + ch);
329 sch_sa[ch] = sch_ea[ch] = 0;
330 sch_cmd[ch] = sch_sdv[ch] = 0;
331 sch_wdc[ch] = 0;
332 sch_rdp[ch] = 1;
333 }
334 }
335 return;
336 }
337
sch_reset(DEVICE * dptr)338 t_stat sch_reset (DEVICE *dptr)
339 {
340 sch_reset_ch (0); /* reset all chan */
341 return SCPE_OK;
342 }
343
344 /* Set number of channels */
345
sch_set_nchan(UNIT * uptr,int32 val,char * cptr,void * desc)346 t_stat sch_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc)
347 {
348 DEVICE *dptr;
349 DIB *dibp;
350 uint32 i, newmax;
351 t_stat r;
352
353 if (cptr == NULL)
354 return SCPE_ARG;
355 newmax = get_uint (cptr, 10, SCH_NUMCH, &r); /* get new max */
356 if ((r != SCPE_OK) || (newmax == sch_max)) /* err or no chg? */
357 return r;
358 if (newmax == 0) /* must be > 0 */
359 return SCPE_ARG;
360 if (newmax < sch_max) { /* reducing? */
361 for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru dev */
362 dibp = (DIB *) dptr->ctxt; /* get DIB */
363 if (dibp && (dibp->sch >= (int32) newmax)) { /* dev using chan? */
364 printf ("Device %02X uses channel %d\n",
365 dibp->dno, dibp->sch);
366 if (sim_log)
367 fprintf (sim_log, "Device %02X uses channel %d\n",
368 dibp->dno, dibp->sch);
369 return SCPE_OK;
370 }
371 }
372 }
373 sch_max = newmax; /* set new max */
374 sch_reset_ch (sch_max); /* reset chan */
375 return SCPE_OK;
376 }
377
378 /* Show number of channels */
379
sch_show_nchan(FILE * st,UNIT * uptr,int32 val,void * desc)380 t_stat sch_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc)
381 {
382 fprintf (st, "channels=%d", sch_max);
383 return SCPE_OK;
384 }
385
386 /* Show channel registers */
387
sch_show_reg(FILE * st,UNIT * uptr,int32 val,void * desc)388 t_stat sch_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc)
389 {
390 if (val < 0)
391 return SCPE_IERR;
392 if (val >= (int32) sch_max)
393 fprintf (st, "Channel %d disabled\n", val);
394 else {
395 fprintf (st, "SA: %05X\n", sch_sa[val]);
396 fprintf (st, "EA: %05X\n", sch_ea[val]);
397 fprintf (st, "CMD: %02X\n", sch_cmd[val]);
398 fprintf (st, "DEV: %02X\n", sch_sdv[val]);
399 fprintf (st, "RDP: %X\n", sch_rdp[val]);
400 fprintf (st, "WDC: %X\n", sch_wdc[val]);
401 }
402 return SCPE_OK;
403 }
404
405 /* Initialize template */
406
sch_ini(t_bool dtpl)407 void sch_ini (t_bool dtpl)
408 {
409 uint32 i;
410
411 for (i = 0; i < sch_max; i++)
412 sch_tplte[i] = i;
413 sch_tplte[sch_max] = TPL_END;
414 return;
415 }
416
417 /* Evaluate interrupt */
418
int_eval(void)419 void int_eval (void)
420 {
421 int i;
422 extern uint32 qevent;
423
424 for (i = 0; i < INTSZ; i++) {
425 if (int_req[i] & int_enb[i]) {
426 qevent = qevent | EV_INT;
427 return;
428 }
429 }
430 qevent = qevent & ~EV_INT;
431 return;
432 }
433
434 /* Return interrupting device */
435
int_getdev(void)436 uint32 int_getdev (void)
437 {
438 int32 i, j, t;
439 uint32 r;
440
441 for (i = t = 0; i < INTSZ; i++) { /* loop thru array */
442 if ((r = int_req[i] & int_enb[i])) { /* find nz int wd */
443 for (j = 0; j < 32; t++, j++) {
444 if (r & (1u << j)) {
445 int_req[i] = int_req[i] & ~(1u << j); /* clr request */
446 return int_tab[t];
447 }
448 }
449 }
450 else t = t + 32;
451 }
452 return 0;
453 }
454
455 /* Update device interrupt status */
456
int_chg(uint32 irq,int32 dat,int32 armdis)457 int32 int_chg (uint32 irq, int32 dat, int32 armdis)
458 {
459 int32 t = CMD_GETINT (dat); /* get int ctrl */
460
461 if (t == CMD_IENB) { /* enable? */
462 SET_ENB (irq);
463 return 1;
464 }
465 else if (t == CMD_IDIS) { /* disable? */
466 CLR_ENB (irq);
467 return 1;
468 }
469 if (t == CMD_IDSA) { /* disarm? */
470 CLR_ENB (irq);
471 CLR_INT (irq);
472 return 0;
473 }
474 return armdis;
475 }
476
477 /* Process a 2b field and return unchanged, set, clear, complement */
478
io_2b(int32 val,int32 pos,int32 old)479 int32 io_2b (int32 val, int32 pos, int32 old)
480 {
481 int32 t = (val >> pos) & 3;
482 if (t == 0)
483 return old;
484 if (t == 1)
485 return 1;
486 if (t == 2)
487 return 0;
488 return old ^1;
489 }
490
491 /* Block transfer routines */
492
IOReadBlk(uint32 loc,uint32 cnt,uint8 * buf)493 uint32 IOReadBlk (uint32 loc, uint32 cnt, uint8 *buf)
494 {
495 uint32 i;
496
497 if (!MEM_ADDR_OK (loc) || (cnt == 0))
498 return 0;
499 if (!MEM_ADDR_OK (loc + cnt - 1))
500 cnt = MEMSIZE - loc;
501 for (i = 0; i < cnt; i++)
502 buf[i] = IOReadB (loc + i);
503 return cnt;
504 }
505
IOWriteBlk(uint32 loc,uint32 cnt,uint8 * buf)506 uint32 IOWriteBlk (uint32 loc, uint32 cnt, uint8 *buf)
507 {
508 uint32 i;
509
510 if (!MEM_ADDR_OK (loc) || (cnt == 0))
511 return 0;
512 if (!MEM_ADDR_OK (loc + cnt - 1))
513 cnt = MEMSIZE - loc;
514 for (i = 0; i < cnt; i++)
515 IOWriteB (loc + i, buf[i]);
516 return cnt;
517 }
518
519 /* Change selector channel for a device */
520
set_sch(UNIT * uptr,int32 val,char * cptr,void * desc)521 t_stat set_sch (UNIT *uptr, int32 val, char *cptr, void *desc)
522 {
523 DEVICE *dptr;
524 DIB *dibp;
525 uint32 newch;
526 t_stat r;
527
528 if (cptr == NULL)
529 return SCPE_ARG;
530 if (uptr == NULL)
531 return SCPE_IERR;
532 dptr = find_dev_from_unit (uptr);
533 if (dptr == NULL)
534 return SCPE_IERR;
535 dibp = (DIB *) dptr->ctxt;
536 if ((dibp == NULL) || (dibp->sch < 0))
537 return SCPE_IERR;
538 newch = get_uint (cptr, 16, sch_max - 1, &r); /* get new */
539 if (r != SCPE_OK)
540 return r;
541 dibp->sch = newch; /* store */
542 return SCPE_OK;
543 }
544
545 /* Show selector channel for a device */
546
show_sch(FILE * st,UNIT * uptr,int32 val,void * desc)547 t_stat show_sch (FILE *st, UNIT *uptr, int32 val, void *desc)
548 {
549 DEVICE *dptr;
550 DIB *dibp;
551
552 if (uptr == NULL)
553 return SCPE_IERR;
554 dptr = find_dev_from_unit (uptr);
555 if (dptr == NULL)
556 return SCPE_IERR;
557 dibp = (DIB *) dptr->ctxt;
558 if ((dibp == NULL) || (dibp->sch < 0))
559 return SCPE_IERR;
560 fprintf (st, "selch=%X", dibp->sch);
561 return SCPE_OK;
562 }
563
564 /* Change device number for a device */
565
set_dev(UNIT * uptr,int32 val,char * cptr,void * desc)566 t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc)
567 {
568 DEVICE *dptr;
569 DIB *dibp;
570 uint32 newdev;
571 t_stat r;
572
573 if (cptr == NULL)
574 return SCPE_ARG;
575 if (uptr == NULL)
576 return SCPE_IERR;
577 dptr = find_dev_from_unit (uptr);
578 if (dptr == NULL)
579 return SCPE_IERR;
580 dibp = (DIB *) dptr->ctxt;
581 if (dibp == NULL)
582 return SCPE_IERR;
583 newdev = get_uint (cptr, 16, DEV_MAX, &r); /* get new */
584 if ((r != SCPE_OK) || (newdev == dibp->dno))
585 return r;
586 if (newdev == 0) /* must be > 0 */
587 return SCPE_ARG;
588 dibp->dno = newdev; /* store */
589 return SCPE_OK;
590 }
591
592 /* Show device number for a device */
593
show_dev(FILE * st,UNIT * uptr,int32 val,void * desc)594 t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc)
595 {
596 DEVICE *dptr;
597 DIB *dibp;
598
599 if (uptr == NULL)
600 return SCPE_IERR;
601 dptr = find_dev_from_unit (uptr);
602 if (dptr == NULL)
603 return SCPE_IERR;
604 dibp = (DIB *) dptr->ctxt;
605 if ((dibp == NULL) || (dibp->dno == 0))
606 return SCPE_IERR;
607 fprintf (st, "devno=%02X", dibp->dno);
608 return SCPE_OK;
609 }
610
611 /* Init device tables */
612
devtab_init(void)613 t_bool devtab_init (void)
614 {
615 DEVICE *dptr;
616 DIB *dibp;
617 uint32 i, j, dno, dmsk, doff, t, dmap[DEVNO / 32];
618 uint8 *tplte, dflt_tplte[] = { 0, TPL_END };
619
620 /* Clear tables, device map */
621
622 for (i = 0; i < DEVNO; i++) {
623 dev_tab[i] = NULL;
624 sch_tab[i] = 0;
625 }
626 for (i = 0; i < (INTSZ * 32); i++)
627 int_tab[i] = 0;
628 for (i = 0; i < (DEVNO / 32); i++)
629 dmap[i] = 0;
630
631 /* Test each device for conflict; add to map; init tables */
632
633 for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */
634 dibp = (DIB *) dptr->ctxt; /* get DIB */
635 if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */
636 continue;
637 dno = dibp->dno; /* get device num */
638 if (dibp->ini) /* gen dno template */
639 dibp->ini (TRUE);
640 tplte = dibp->tplte; /* get template */
641 if (tplte == NULL) /* none? use default */
642 tplte = dflt_tplte;
643 for ( ; *tplte != TPL_END; tplte++) { /* loop thru template */
644 t = (dno + *tplte) & DEV_MAX; /* loop thru template */
645 dmsk = 1u << (t & 0x1F); /* bit to test */
646 doff = t / 32; /* word to test */
647 if (dmap[doff] & dmsk) { /* in use? */
648 printf ("Device number conflict, devno = %02X\n", t);
649 if (sim_log)
650 fprintf (sim_log, "Device number conflict, devno = %02X\n", t);
651 return TRUE;
652 }
653 dmap[doff] = dmap[doff] | dmsk;
654 if (dibp->sch >= 0)
655 sch_tab[t] = dibp->sch + 1;
656 dev_tab[t] = dibp->iot;
657 }
658 if (dibp->ini) /* gen int template */
659 dibp->ini (FALSE);
660 tplte = dibp->tplte; /* get template */
661 if (tplte == NULL) /* none? use default */
662 tplte = dflt_tplte;
663 for (j = dibp->irq; *tplte != TPL_END; j++, tplte++)
664 int_tab[j] = (dno + *tplte) & DEV_MAX;
665 } /* end for i */
666 return FALSE;
667 }
668