First Commit of my working state
[simh.git] / PDP11 / pdp11_io.c
CommitLineData
196ba1fc
PH
1/* pdp11_io.c: PDP-11 I/O simulator\r
2\r
3 Copyright (c) 1993-2008, 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 16-May-08 RMS Added multiple DC11 support\r
27 Renamed DL11 in autoconfigure\r
28 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas)\r
29 06-Jul-06 RMS Added multiple KL11/DL11 support\r
30 15-Oct-05 RMS Fixed bug in autoconfiguration (missing XU)\r
31 25-Jul-05 RMS Revised autoconfiguration algorithm and interface\r
32 30-Sep-04 RMS Revised Unibus interface\r
33 28-May-04 RMS Revised I/O dispatching (from John Dundas)\r
34 25-Jan-04 RMS Removed local debug logging support\r
35 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls\r
36 21-Nov-03 RMS Added check for interrupt slot conflict (found by Dave Hittner)\r
37 12-Mar-03 RMS Added logical name support\r
38 08-Oct-02 RMS Trimmed I/O bus addresses\r
39 Added support for dynamic tables\r
40 Added show I/O space, autoconfigure routines\r
41 12-Sep-02 RMS Added support for TMSCP, KW11P, RX211\r
42 26-Jan-02 RMS Revised for multiple DZ's\r
43 06-Jan-02 RMS Revised I/O access, enable/disable support\r
44 11-Dec-01 RMS Moved interrupt debug code\r
45 08-Nov-01 RMS Cloned from cpu sources\r
46*/\r
47\r
48#include "pdp11_defs.h"\r
49\r
50extern uint16 *M;\r
51extern int32 int_req[IPL_HLVL];\r
52extern int32 ub_map[UBM_LNT_LW];\r
53extern int32 cpu_opt, cpu_bme;\r
54extern int32 trap_req, ipl;\r
55extern int32 cpu_log;\r
56extern int32 autcon_enb;\r
57extern int32 uba_last;\r
58extern FILE *sim_log;\r
59extern DEVICE *sim_devices[], cpu_dev;\r
60extern t_addr cpu_memsize;\r
61\r
62int32 calc_ints (int32 nipl, int32 trq);\r
63\r
64extern t_stat cpu_build_dib (void);\r
65extern void init_mbus_tab (void);\r
66extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp);\r
67\r
68/* I/O data structures */\r
69\r
70static t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);\r
71static t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);\r
72static DIB *iodibp[IOPAGESIZE >> 1];\r
73\r
74int32 int_vec[IPL_HLVL][32]; /* int req to vector */\r
75\r
76int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */\r
77\r
78static const int32 pirq_bit[7] = {\r
79 INT_V_PIR1, INT_V_PIR2, INT_V_PIR3, INT_V_PIR4,\r
80 INT_V_PIR5, INT_V_PIR6, INT_V_PIR7\r
81 };\r
82\r
83/* I/O page lookup and linkage routines\r
84\r
85 Inputs:\r
86 *data = pointer to data to read, if READ\r
87 data = data to store, if WRITE or WRITEB\r
88 pa = address\r
89 access = READ, WRITE, or WRITEB\r
90 Outputs:\r
91 status = SCPE_OK or SCPE_NXM\r
92*/\r
93\r
94t_stat iopageR (int32 *data, uint32 pa, int32 access)\r
95{\r
96int32 idx;\r
97t_stat stat;\r
98\r
99idx = (pa & IOPAGEMASK) >> 1;\r
100if (iodispR[idx]) {\r
101 stat = iodispR[idx] (data, pa, access);\r
102 trap_req = calc_ints (ipl, trap_req);\r
103 return stat;\r
104 }\r
105return SCPE_NXM;\r
106}\r
107\r
108t_stat iopageW (int32 data, uint32 pa, int32 access)\r
109{\r
110int32 idx;\r
111t_stat stat;\r
112\r
113idx = (pa & IOPAGEMASK) >> 1;\r
114if (iodispW[idx]) {\r
115 stat = iodispW[idx] (data, pa, access);\r
116 trap_req = calc_ints (ipl, trap_req);\r
117 return stat;\r
118 }\r
119return SCPE_NXM;\r
120}\r
121\r
122/* Calculate interrupt outstanding */\r
123\r
124int32 calc_ints (int32 nipl, int32 trq)\r
125{\r
126int32 i;\r
127\r
128for (i = IPL_HLVL - 1; i > nipl; i--) {\r
129 if (int_req[i]) return (trq | TRAP_INT);\r
130 }\r
131return (trq & ~TRAP_INT);\r
132}\r
133\r
134/* Find vector for highest priority interrupt */\r
135\r
136int32 get_vector (int32 nipl)\r
137{\r
138int32 i, j, t, vec;\r
139\r
140for (i = IPL_HLVL - 1; i > nipl; i--) { /* loop thru lvls */\r
141 t = int_req[i]; /* get level */\r
142 for (j = 0; t && (j < 32); j++) { /* srch level */\r
143 if ((t >> j) & 1) { /* irq found? */\r
144 int_req[i] = int_req[i] & ~(1u << j); /* clr irq */\r
145 if (int_ack[i][j]) vec = int_ack[i][j]();\r
146 else vec = int_vec[i][j];\r
147 return vec; /* return vector */\r
148 } /* end if t */\r
149 } /* end for j */\r
150 } /* end for i */\r
151return 0;\r
152}\r
153\r
154/* Read and write Unibus map registers\r
155\r
156 In any even/odd pair\r
157 even = low 16b, bit <0> clear\r
158 odd = high 6b\r
159\r
160 The Unibus map is stored as an array of longwords.\r
161 These routines are only reachable if a Unibus map is configured.\r
162*/\r
163\r
164t_stat ubm_rd (int32 *data, int32 addr, int32 access)\r
165{\r
166int32 pg = (addr >> 2) & UBM_M_PN;\r
167\r
168*data = (addr & 2)? ((ub_map[pg] >> 16) & 077):\r
169 (ub_map[pg] & 0177776);\r
170return SCPE_OK;\r
171}\r
172\r
173t_stat ubm_wr (int32 data, int32 addr, int32 access)\r
174{\r
175int32 sc, pg = (addr >> 2) & UBM_M_PN;\r
176\r
177if (access == WRITEB) {\r
178 sc = (addr & 3) << 3;\r
179 ub_map[pg] = (ub_map[pg] & ~(0377 << sc)) |\r
180 ((data & 0377) << sc);\r
181 }\r
182else {\r
183 sc = (addr & 2) << 3;\r
184 ub_map[pg] = (ub_map[pg] & ~(0177777 << sc)) |\r
185 ((data & 0177777) << sc);\r
186 }\r
187ub_map[pg] = ub_map[pg] & 017777776;\r
188return SCPE_OK;\r
189}\r
190\r
191/* Mapped memory access routines for DMA devices */\r
192\r
193#define BUSMASK ((UNIBUS)? UNIMASK: PAMASK)\r
194\r
195/* Map I/O address to memory address - caller checks cpu_bme */\r
196\r
197uint32 Map_Addr (uint32 ba)\r
198{\r
199int32 pg = UBM_GETPN (ba); /* map entry */\r
200int32 off = UBM_GETOFF (ba); /* offset */\r
201\r
202if (pg != UBM_M_PN) /* last page? */\r
203 uba_last = (ub_map[pg] + off) & PAMASK; /* no, use map */\r
204else uba_last = (IOPAGEBASE + off) & PAMASK; /* yes, use fixed */\r
205return uba_last;\r
206}\r
207\r
208/* I/O buffer routines, aligned access\r
209\r
210 Map_ReadB - fetch byte buffer from memory\r
211 Map_ReadW - fetch word buffer from memory\r
212 Map_WriteB - store byte buffer into memory\r
213 Map_WriteW - store word buffer into memory\r
214\r
215 These routines are used only for Unibus and Qbus devices.\r
216 Massbus devices have their own IO routines. As a result,\r
217 the historic 'map' parameter is no longer needed.\r
218\r
219 - In a U18 configuration, the map is always disabled.\r
220 Device addresses are trimmed to 18b.\r
221 - In a U22 configuration, the map is always configured\r
222 (although it may be disabled). Device addresses are\r
223 trimmed to 18b.\r
224 - In a Qbus configuration, the map is always disabled.\r
225 Device addresses are trimmed to 22b.\r
226*/\r
227\r
228int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)\r
229{\r
230uint32 alim, lim, ma;\r
231\r
232ba = ba & BUSMASK; /* trim address */\r
233lim = ba + bc;\r
234if (cpu_bme) { /* map enabled? */\r
235 for ( ; ba < lim; ba++) { /* by bytes */\r
236 ma = Map_Addr (ba); /* map addr */\r
237 if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */\r
238 if (ma & 1) *buf++ = (M[ma >> 1] >> 8) & 0377; /* get byte */\r
239 else *buf++ = M[ma >> 1] & 0377;\r
240 }\r
241 return 0;\r
242 }\r
243else { /* physical */\r
244 if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */\r
245 else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */\r
246 else return bc; /* no, err */\r
247 for ( ; ba < alim; ba++) { /* by bytes */\r
248 if (ba & 1) *buf++ = (M[ba >> 1] >> 8) & 0377; /* get byte */\r
249 else *buf++ = M[ba >> 1] & 0377;\r
250 }\r
251 return (lim - alim);\r
252 }\r
253}\r
254\r
255int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)\r
256{\r
257uint32 alim, lim, ma;\r
258\r
259ba = (ba & BUSMASK) & ~01; /* trim, align addr */\r
260lim = ba + (bc & ~01);\r
261if (cpu_bme) { /* map enabled? */\r
262 for (; ba < lim; ba = ba + 2) { /* by words */\r
263 ma = Map_Addr (ba); /* map addr */\r
264 if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */\r
265 *buf++ = M[ma >> 1];\r
266 }\r
267 return 0;\r
268 }\r
269else { /* physical */\r
270 if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */\r
271 else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */\r
272 else return bc; /* no, err */\r
273 for ( ; ba < alim; ba = ba + 2) { /* by words */\r
274 *buf++ = M[ba >> 1];\r
275 }\r
276 return (lim - alim);\r
277 }\r
278}\r
279\r
280int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)\r
281{\r
282uint32 alim, lim, ma;\r
283\r
284ba = ba & BUSMASK; /* trim address */\r
285lim = ba + bc;\r
286if (cpu_bme) { /* map enabled? */\r
287 for ( ; ba < lim; ba++) { /* by bytes */\r
288 ma = Map_Addr (ba); /* map addr */\r
289 if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */\r
290 if (ma & 1) M[ma >> 1] = (M[ma >> 1] & 0377) |\r
291 ((uint16) *buf++ << 8);\r
292 else M[ma >> 1] = (M[ma >> 1] & ~0377) | *buf++;\r
293 }\r
294 return 0;\r
295 }\r
296else { /* physical */\r
297 if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */\r
298 else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */\r
299 else return bc; /* no, err */\r
300 for ( ; ba < alim; ba++) { /* by bytes */\r
301 if (ba & 1) M[ba >> 1] = (M[ba >> 1] & 0377) |\r
302 ((uint16) *buf++ << 8);\r
303 else M[ba >> 1] = (M[ba >> 1] & ~0377) | *buf++;\r
304 }\r
305 return (lim - alim);\r
306 }\r
307}\r
308\r
309int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)\r
310{\r
311uint32 alim, lim, ma;\r
312\r
313ba = (ba & BUSMASK) & ~01; /* trim, align addr */\r
314lim = ba + (bc & ~01);\r
315if (cpu_bme) { /* map enabled? */\r
316 for (; ba < lim; ba = ba + 2) { /* by words */\r
317 ma = Map_Addr (ba); /* map addr */\r
318 if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */\r
319 M[ma >> 1] = *buf++;\r
320 }\r
321 return 0;\r
322 }\r
323else { /* physical */\r
324 if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */\r
325 else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */\r
326 else return bc; /* no, err */\r
327 for ( ; ba < alim; ba = ba + 2) { /* by words */\r
328 M[ba >> 1] = *buf++;\r
329 }\r
330 return (lim - alim);\r
331 }\r
332}\r
333\r
334/* Enable/disable autoconfiguration */\r
335\r
336t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc)\r
337{\r
338if (cptr != NULL) return SCPE_ARG;\r
339autcon_enb = val;\r
340return auto_config (NULL, 0);\r
341}\r
342\r
343/* Show autoconfiguration status */\r
344\r
345t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc)\r
346{\r
347fprintf (st, "autoconfiguration %s", (autcon_enb? "on": "off"));\r
348return SCPE_OK;\r
349}\r
350\r
351/* Change device address */\r
352\r
353t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)\r
354{\r
355DEVICE *dptr;\r
356DIB *dibp;\r
357uint32 newba;\r
358t_stat r;\r
359\r
360if (cptr == NULL) return SCPE_ARG;\r
361if ((val == 0) || (uptr == NULL)) return SCPE_IERR;\r
362dptr = find_dev_from_unit (uptr);\r
363if (dptr == NULL) return SCPE_IERR;\r
364dibp = (DIB *) dptr->ctxt;\r
365if (dibp == NULL) return SCPE_IERR;\r
366newba = get_uint (cptr, 8, PAMASK, &r); /* get new */\r
367if (r != SCPE_OK) return r; /* error? */\r
368if ((newba <= IOPAGEBASE) || /* > IO page base? */\r
369 (newba % ((uint32) val))) return SCPE_ARG; /* check modulus */\r
370dibp->ba = newba; /* store */\r
371dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */\r
372autcon_enb = 0; /* autoconfig off */\r
373return SCPE_OK;\r
374}\r
375\r
376/* Show device address */\r
377\r
378t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc)\r
379{\r
380DEVICE *dptr;\r
381DIB *dibp;\r
382\r
383if (uptr == NULL) return SCPE_IERR;\r
384dptr = find_dev_from_unit (uptr);\r
385if (dptr == NULL) return SCPE_IERR;\r
386dibp = (DIB *) dptr->ctxt;\r
387if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;\r
388fprintf (st, "address=%08o", dibp->ba);\r
389if (dibp->lnt > 1)\r
390 fprintf (st, "-%08o", dibp->ba + dibp->lnt - 1);\r
391if (dptr->flags & DEV_FLTA) fprintf (st, "*");\r
392return SCPE_OK;\r
393}\r
394\r
395/* Set address floating */\r
396\r
397t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc)\r
398{\r
399DEVICE *dptr;\r
400\r
401if (cptr != NULL) return SCPE_ARG;\r
402if (uptr == NULL) return SCPE_IERR;\r
403dptr = find_dev_from_unit (uptr);\r
404if (dptr == NULL) return SCPE_IERR;\r
405dptr->flags = dptr->flags | DEV_FLTA; /* floating */\r
406return auto_config (NULL, 0); /* autoconfigure */\r
407}\r
408\r
409/* Change device vector */\r
410\r
411t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc)\r
412{\r
413DEVICE *dptr;\r
414DIB *dibp;\r
415uint32 newvec;\r
416t_stat r;\r
417\r
418if (cptr == NULL) return SCPE_ARG;\r
419if (uptr == NULL) return SCPE_IERR;\r
420dptr = find_dev_from_unit (uptr);\r
421if (dptr == NULL) return SCPE_IERR;\r
422dibp = (DIB *) dptr->ctxt;\r
423if (dibp == NULL) return SCPE_IERR;\r
424newvec = get_uint (cptr, 8, VEC_Q + 01000, &r);\r
425if ((r != SCPE_OK) || (newvec == VEC_Q) ||\r
426 ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) ||\r
427 (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG;\r
428dibp->vec = newvec;\r
429dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */\r
430autcon_enb = 0; /* autoconfig off */\r
431return SCPE_OK;\r
432}\r
433\r
434/* Show device vector */\r
435\r
436t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc)\r
437{\r
438DEVICE *dptr;\r
439DIB *dibp;\r
440uint32 vec, numvec;\r
441\r
442if (uptr == NULL) return SCPE_IERR;\r
443dptr = find_dev_from_unit (uptr);\r
444if (dptr == NULL) return SCPE_IERR;\r
445dibp = (DIB *) dptr->ctxt;\r
446if (dibp == NULL) return SCPE_IERR;\r
447vec = dibp->vec;\r
448if (arg) numvec = arg;\r
449else numvec = dibp->vnum;\r
450if (vec == 0) fprintf (st, "no vector");\r
451else {\r
452 fprintf (st, "vector=%o", vec);\r
453 if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1)));\r
454 }\r
455return SCPE_OK;\r
456}\r
457\r
458/* Init Unibus tables */\r
459\r
460void init_ubus_tab (void)\r
461{\r
462int32 i, j;\r
463\r
464for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */\r
465 for (j = 0; j < 32; j++) {\r
466 int_vec[i][j] = 0;\r
467 int_ack[i][j] = NULL;\r
468 }\r
469 }\r
470for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */\r
471 iodispR[i] = NULL;\r
472 iodispW[i] = NULL;\r
473 iodibp[i] = NULL;\r
474 }\r
475return;\r
476}\r
477\r
478/* Build Unibus tables */\r
479\r
480t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp)\r
481{\r
482int32 i, idx, vec, ilvl, ibit;\r
483\r
484if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */\r
485if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;\r
486for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */\r
487 idx = dibp->vloc + i; /* vector index */\r
488 vec = dibp->vec? (dibp->vec + (i * 4)): 0; /* vector addr */\r
489 ilvl = idx / 32;\r
490 ibit = idx % 32;\r
491 if ((int_ack[ilvl][ibit] && dibp->ack[i] && /* conflict? */\r
492 (int_ack[ilvl][ibit] != dibp->ack[i])) ||\r
493 (int_vec[ilvl][ibit] && vec &&\r
494 (int_vec[ilvl][ibit] != vec))) {\r
495 printf ("Device %s interrupt slot conflict at %d\n",\r
496 sim_dname (dptr), idx);\r
497 if (sim_log) fprintf (sim_log,\r
498 "Device %s interrupt slot conflict at %d\n",\r
499 sim_dname (dptr), idx);\r
500 return SCPE_STOP;\r
501 }\r
502 if (dibp->ack[i]) int_ack[ilvl][ibit] = dibp->ack[i];\r
503 else if (vec) int_vec[ilvl][ibit] = vec;\r
504 }\r
505for (i = 0; i < (int32) dibp->lnt; i = i + 2) { /* create entries */\r
506 idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */\r
507 if ((iodispR[idx] && dibp->rd && /* conflict? */\r
508 (iodispR[idx] != dibp->rd)) ||\r
509 (iodispW[idx] && dibp->wr &&\r
510 (iodispW[idx] != dibp->wr))) {\r
511 printf ("Device %s address conflict at %08o\n",\r
512 sim_dname (dptr), dibp->ba);\r
513 if (sim_log) fprintf (sim_log,\r
514 "Device %s address conflict at %08o\n",\r
515 sim_dname (dptr), dibp->ba);\r
516 return SCPE_STOP;\r
517 }\r
518 if (dibp->rd) iodispR[idx] = dibp->rd; /* set rd dispatch */\r
519 if (dibp->wr) iodispW[idx] = dibp->wr; /* set wr dispatch */\r
520 iodibp[idx] = dibp; /* remember DIB */\r
521 }\r
522return SCPE_OK;\r
523}\r
524\r
525/* Build tables from device list */\r
526\r
527t_stat build_dib_tab (void)\r
528{\r
529int32 i;\r
530DEVICE *dptr;\r
531DIB *dibp;\r
532t_stat r;\r
533\r
534init_ubus_tab (); /* init Unibus tables */\r
535init_mbus_tab (); /* init Massbus tables */\r
536for (i = 0; i < 7; i++) /* seed PIRQ intr */\r
537 int_vec[i + 1][pirq_bit[i]] = VEC_PIRQ;\r
538if (r = cpu_build_dib ()) return r; /* build CPU entries */\r
539for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */\r
540 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
541 if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */\r
542 if (dptr->flags & DEV_MBUS) { /* Massbus? */\r
543 if (r = build_mbus_tab (dptr, dibp)) /* add to Mbus tab */\r
544 return r;\r
545 }\r
546 else { /* no, Unibus */\r
547 if (r = build_ubus_tab (dptr, dibp)) /* add to Unibus tab */\r
548 return r;\r
549 }\r
550 } /* end if enabled */\r
551 } /* end for */\r
552return SCPE_OK;\r
553}\r
554\r
555/* Show IO space */\r
556\r
557t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc)\r
558{\r
559uint32 i, j;\r
560DEVICE *dptr;\r
561DIB *dibp;\r
562\r
563if (build_dib_tab ()) return SCPE_OK; /* build IO page */\r
564for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */\r
565 if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */\r
566 dibp = iodibp[i]; /* DIB for block */\r
567 for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {\r
568 if (((DIB*) sim_devices[j]->ctxt) == dibp) {\r
569 dptr = sim_devices[j]; /* locate device */\r
570 break;\r
571 } /* end if */\r
572 } /* end for j */\r
573 fprintf (st, "%08o - %08o%c\t%s\n", /* print block entry */\r
574 dibp->ba, dibp->ba + dibp->lnt - 1,\r
575 (dptr && (dptr->flags & DEV_FLTA))? '*': ' ',\r
576 dptr? sim_dname (dptr): "CPU");\r
577 } /* end if */\r
578 } /* end for i */\r
579return SCPE_OK;\r
580}\r
581\r
582/* Autoconfiguration\r
583\r
584 The table reflects the MicroVAX 3900 microcode, with one addition - the\r
585 number of controllers field handles devices where multiple instances\r
586 are simulated through a single DEVICE structure (e.g., DZ, VH).\r
587\r
588 A minus number of vectors indicates a field that should be calculated\r
589 but not placed in the DIB (RQ, TQ dynamic vectors) */\r
590\r
591#define AUTO_MAXC 4\r
592#define AUTO_CSRBASE 0010\r
593#define AUTO_VECBASE 0300\r
594\r
595typedef struct {\r
596 char *dnam[AUTO_MAXC];\r
597 int32 numc;\r
598 int32 numv;\r
599 uint32 amod;\r
600 uint32 vmod;\r
601 uint32 fixa[AUTO_MAXC];\r
602 uint32 fixv[AUTO_MAXC];\r
603 } AUTO_CON;\r
604\r
605AUTO_CON auto_tab[] = {\r
606 { { "DCI" }, DCX_LINES, 2, 0, 8, { 0 } }, /* DC11 - fx CSRs */\r
607 { { "DLI" }, DLX_LINES, 2, 0, 8, { 0 } }, /* KL11/DL11/DLV11 - fx CSRs */\r
608 { { NULL }, 1, 2, 8, 8 }, /* DJ11 */\r
609 { { NULL }, 1, 2, 16, 8 }, /* DH11 */\r
610 { { NULL }, 1, 2, 8, 8 }, /* DQ11 */\r
611 { { NULL }, 1, 2, 8, 8 }, /* DU11 */\r
612 { { NULL }, 1, 2, 8, 8 }, /* DUP11 */\r
613 { { NULL }, 10, 2, 8, 8 }, /* LK11A */\r
614 { { NULL }, 1, 2, 8, 8 }, /* DMC11 */\r
615 { { "DZ" }, DZ_MUXES, 2, 8, 8 }, /* DZ11 */\r
616 { { NULL }, 1, 2, 8, 8 }, /* KMC11 */\r
617 { { NULL }, 1, 2, 8, 8 }, /* LPP11 */\r
618 { { NULL }, 1, 2, 8, 8 }, /* VMV21 */\r
619 { { NULL }, 1, 2, 16, 8 }, /* VMV31 */\r
620 { { NULL }, 1, 2, 8, 8 }, /* DWR70 */\r
621 { { "RL", "RLB" }, 1, 1, 8, 4, {IOBA_RL}, {VEC_RL} }, /* RL11 */\r
622 { { "TS", "TSB", "TSC", "TSD" }, 1, 1, 0, 4, /* TS11 */\r
623 {IOBA_TS, IOBA_TS + 4, IOBA_TS + 8, IOBA_TS + 12},\r
624 {VEC_TS} },\r
625 { { NULL }, 1, 2, 16, 8 }, /* LPA11K */\r
626 { { NULL }, 1, 2, 8, 8 }, /* KW11C */\r
627 { { NULL }, 1, 1, 8, 8 }, /* reserved */\r
628 { { "RX", "RY" }, 1, 1, 8, 4, {IOBA_RX} , {VEC_RX} }, /* RX11/RX211 */\r
629 { { NULL }, 1, 1, 8, 4 }, /* DR11W */\r
630 { { NULL }, 1, 1, 8, 4, { 0, 0 }, { 0 } }, /* DR11B - fx CSRs,vec */\r
631 { { NULL }, 1, 2, 8, 8 }, /* DMP11 */\r
632 { { NULL }, 1, 2, 8, 8 }, /* DPV11 */\r
633 { { NULL }, 1, 2, 8, 8 }, /* ISB11 */\r
634 { { NULL }, 1, 2, 16, 8 }, /* DMV11 */\r
635 { { "XU", "XUB" }, 1, 1, 8, 4, {IOBA_XU}, {VEC_XU} }, /* DEUNA */\r
636 { { "XQ", "XQB" }, 1, 1, 0, 4, /* DEQNA */\r
637 {IOBA_XQ,IOBA_XQB}, {VEC_XQ} },\r
638 { { "RQ", "RQB", "RQC", "RQD" }, 1, -1, 4, 4, /* RQDX3 */\r
639 {IOBA_RQ}, {VEC_RQ} },\r
640 { { NULL }, 1, 8, 32, 4 }, /* DMF32 */\r
641 { { NULL }, 1, 2, 16, 8 }, /* KMS11 */\r
642 { { NULL }, 1, 1, 16, 4 }, /* VS100 */\r
643 { { "TQ", "TQB" }, 1, -1, 4, 4, {IOBA_TQ}, {VEC_TQ} }, /* TQK50 */\r
644 { { NULL }, 1, 2, 16, 8 }, /* KMV11 */\r
645 { { "VH" }, VH_MUXES, 2, 16, 8 }, /* DHU11/DHQ11 */\r
646 { { NULL }, 1, 6, 32, 4 }, /* DMZ32 */\r
647 { { NULL }, 1, 6, 32, 4 }, /* CP132 */\r
648 { { NULL }, 1, 2, 64, 8, { 0 } }, /* QVSS - fx CSR */\r
649 { { NULL }, 1, 1, 8, 4 }, /* VS31 */\r
650 { { NULL }, 1, 1, 0, 4, { 0 } }, /* LNV11 - fx CSR */\r
651 { { NULL }, 1, 1, 16, 4 }, /* LNV21/QPSS */\r
652 { { NULL }, 1, 1, 8, 4, { 0 } }, /* QTA - fx CSR */\r
653 { { NULL }, 1, 1, 8, 4 }, /* DSV11 */\r
654 { { NULL }, 1, 2, 8, 8 }, /* CSAM */\r
655 { { NULL }, 1, 2, 8, 8 }, /* ADV11C */\r
656 { { NULL }, 1, 0, 8, 0 }, /* AAV11C */\r
657 { { NULL }, 1, 2, 8, 8, { 0 }, { 0 } }, /* AXV11C - fx CSR,vec */\r
658 { { NULL }, 1, 2, 4, 8, { 0 } }, /* KWV11C - fx CSR */\r
659 { { NULL }, 1, 2, 8, 8, { 0 } }, /* ADV11D - fx CSR */\r
660 { { NULL }, 1, 2, 8, 8, { 0 } }, /* AAV11D - fx CSR */\r
661/* { { "QDSS" }, 1, 3, 0, 16, {IOBA_QDSS} }, /* QDSS - fx CSR */\r
662 { { NULL }, -1 } /* end table */\r
663};\r
664\r
665t_stat auto_config (char *name, int32 nctrl)\r
666{\r
667uint32 csr = IOPAGEBASE + AUTO_CSRBASE;\r
668uint32 vec = VEC_Q + AUTO_VECBASE;\r
669AUTO_CON *autp;\r
670DEVICE *dptr;\r
671DIB *dibp;\r
672uint32 j, k, vmask, amask;\r
673\r
674if (autcon_enb == 0) return SCPE_OK; /* enabled? */\r
675if (name) { /* updating? */\r
676 if (nctrl < 0) return SCPE_ARG;\r
677 for (autp = auto_tab; autp->numc >= 0; autp++) {\r
678 for (j = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {\r
679 if (strcmp (name, autp->dnam[j]) == 0)\r
680 autp->numc = nctrl;\r
681 }\r
682 }\r
683 }\r
684for (autp = auto_tab; autp->numc >= 0; autp++) { /* loop thru table */\r
685 if (autp->amod) { /* floating csr? */\r
686 amask = autp->amod - 1;\r
687 csr = (csr + amask) & ~amask; /* align csr */\r
688 }\r
689 for (j = k = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {\r
690 dptr = find_dev (autp->dnam[j]); /* find ctrl */\r
691 if ((dptr == NULL) || (dptr->flags & DEV_DIS) ||\r
692 !(dptr->flags & DEV_FLTA)) continue; /* enabled, floating? */\r
693 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
694 if (dibp == NULL) return SCPE_IERR; /* not there??? */\r
695 if (autp->amod) { /* dyn csr needed? */\r
696 if (autp->fixa[k]) /* fixed csr avail? */\r
697 dibp->ba = autp->fixa[k]; /* use it */\r
698 else { /* no fixed left */\r
699 dibp->ba = csr; /* set CSR */\r
700 csr += (autp->numc * autp->amod); /* next CSR */\r
701 } /* end else */\r
702 } /* end if dyn csr */\r
703 if (autp->numv && autp->vmod) { /* dyn vec needed? */\r
704 uint32 numv = abs (autp->numv); /* get num vec */\r
705 if (autp->fixv[k]) { /* fixed vec avail? */\r
706 if (autp->numv > 0)\r
707 dibp->vec = autp->fixv[k]; /* use it */\r
708 }\r
709 else { /* no fixed left */\r
710 vmask = autp->vmod - 1;\r
711 vec = (vec + vmask) & ~vmask; /* align vector */\r
712 if (autp->numv > 0)\r
713 dibp->vec = vec; /* set vector */\r
714 vec += (autp->numc * numv * 4);\r
715 } /* end else */\r
716 } /* end if dyn vec */\r
717 k++; /* next instance */\r
718 } /* end for j */\r
719 if (autp->amod) csr = csr + 2; /* flt CSR? gap */\r
720 } /* end for i */\r
721return SCPE_OK;\r
722}\r