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