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