First Commit of my working state
[simh.git] / VAX / vax780_uba.c
1 /* vax780_uba.c: VAX 11/780 Unibus adapter
2
3 Copyright (c) 2004-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 uba DW780 Unibus adapter
27
28 28-May-08 RMS Inlined physical memory routines
29 25-Jan-08 RMS Fixed declarations (from Mark Pizzolato)
30 */
31
32 #include "vax_defs.h"
33
34 /* Unibus adapter */
35
36 #define UBA_NDPATH 16 /* number of data paths */
37 #define UBA_NMAPR 496 /* number of map reg */
38
39 /* Unibus configuration register */
40
41 #define UBACNF_OF 0x00
42 #define UBACNF_ADPDN 0x00800000 /* adap pdn - ni */
43 #define UBACNF_ADPUP 0x00400000 /* adap pup - ni */
44 #define UBACNF_UBINIT 0x00040000 /* UB INIT - ni */
45 #define UBACNF_UBPDN 0x00020000 /* UB pdn */
46 #define UBACNF_UBIC 0x00010000 /* UB init done */
47 #define UBACNF_CODE 0x00000028 /* adapter code */
48 #define UBACNF_RD (SBI_FAULTS|UBACNF_W1C)
49 #define UBACNF_W1C 0x00C70000
50
51 /* Control register */
52
53 #define UBACR_OF 0x01
54 #define UBACR_V_DSB 26 /* map disable */
55 #define UBACR_M_DSB 0x1F
56 #define UBACR_GETDSB(x) (((x) >> (UBACR_V_DSB - 4)) & (UBACR_M_DSB << 4))
57 #define UBACR_IFS 0x00000040 /* SBI field intr */
58 #define UBACR_BRIE 0x00000020 /* BR int enable */
59 #define UBACR_USEFIE 0x00000010 /* UB to SBI int enb */
60 #define UBACR_SUEFIE 0x00000008 /* SBI to UB int enb */
61 #define UBACR_CNFIE 0x00000004 /* config int enb */
62 #define UBACR_UPF 0x00000002 /* power fail UB */
63 #define UBACR_ADINIT 0x00000001 /* adapter init */
64 #define UBACR_RD ((UBACR_M_DSB << UBACR_V_DSB) | 0x0000007E)
65 #define UBACR_WR (UBACR_RD)
66
67 #define UBA_USEFIE_SR (UBASR_RDTO|UBASR_RDS|UBASR_CRD|UBASR_CXTER| \
68 UBASR_CXTO|UBASR_DPPE|UBASR_IVMR|UBASR_MRPF)
69 #define UBA_SUEFIE_SR (UBASR_UBSTO|UBASR_UBTMO)
70 #define UBA_CNFIE_CR (UBACNF_ADPDN|UBACNF_ADPUP|UBACNF_UBINIT|\
71 UBACNF_UBPDN|UBACNF_UBIC)
72
73 /* Status register */
74
75 #define UBASR_OF 0x02
76 #define UBASR_V_BR4 24 /* filled br's - ni */
77 #define UBASR_RDTO 0x00000400 /* read tmo - ni */
78 #define UBASR_RDS 0x00000200 /* read sub - ni */
79 #define UBASR_CRD 0x00000100 /* read crd - ni */
80 #define UBASR_CXTER 0x00000080 /* cmd xfr err - ni */
81 #define UBASR_CXTO 0x00000040 /* cmd xfr tmo - ni */
82 #define UBASR_DPPE 0x00000020 /* parity err - ni */
83 #define UBASR_IVMR 0x00000010 /* invalid map reg */
84 #define UBASR_MRPF 0x00000008 /* map reg par - ni */
85 #define UBASR_LEB 0x00000004 /* locked err */
86 #define UBASR_UBSTO 0x00000002 /* UB select tmo - ni */
87 #define UBASR_UBTMO 0x00000001 /* UB nxm */
88 #define UBASR_RD 0x0F0007FF
89 #define UBASR_W1C 0x000007FF
90
91 /* Diagnostic register */
92
93 #define UBADR_OF 0x03
94 #define UBADR_SPARE 0x80000000 /* spare */
95 #define UBADR_DINTR 0x40000000 /* disable intr */
96 #define UBADR_DMP 0x20000000
97 #define UBADR_DDPP 0x10000000
98 #define UBADR_MICOK 0x08000000 /* microseq ok */
99 #define UBADR_RD 0xF8000000
100 #define UBADR_WR 0xF0000000
101 #define UBADR_CNF_RD 0x07FFFFFF
102
103 /* Failing map entry - read only */
104
105 #define UBAFMER_OF 0x04
106 #define UBAFMER_OF1 0x06
107 #define UBAFMER_RD 0x1FF
108
109 /* Failing Unibus address - read only */
110
111 #define UBAFUBAR_OF 0x05
112 #define UBAFUBAR_OF1 0x07
113 #define UBAFUBAR_RD 0xFFFF
114
115 /* Spare registers - read/write */
116
117 #define UBABRSVR_OF 0x08
118
119 /* Vector registers - read only */
120
121 #define UBABRRVR_OF 0x0C
122 #define UBA_UVEC 0x80000000
123
124 /* Data path registers */
125
126 #define UBADPR_OF 0x010
127 #define UBADPR_BNE 0x80000000 /* buf not empty - ni */
128 #define UBADPR_BTE 0x40000000 /* buf xfr err - ni */
129 #define UBADPR_DIR 0x20000000 /* buf rd/wr */
130 #define UBADPR_STATE 0x00FF0000 /* byte full state - ni */
131 #define UBADPR_UA 0x0000FFFF /* Unibus addr<17:2> */
132 #define UBADPR_UA 0x0000FFFF /* last UB addr */
133 #define UBADPR_RD 0xC0FFFFFF
134 #define UBADPR_W1C 0xC0000000
135
136 /* Map registers */
137
138 #define UBAMAP_OF 0x200
139 #define UBAMAP_VLD 0x80000000 /* valid */
140 #define UBAMAP_LWAE 0x04000000 /* LW access enb - ni */
141 #define UBAMAP_ODD 0x02000000 /* odd byte */
142 #define UBAMAP_V_DP 21 /* data path */
143 #define UBAMAP_M_DP 0xF
144 #define UBAMAP_DP (UBAMAP_M_DP << UBAMAP_V_DP)
145 #define UBAMAP_GETDP(x) (((x) >> UBAMAP_V_DP) & UBAMAP_M_DP)
146 #define UBAMAP_PAG 0x001FFFFF
147 #define UBAMAP_RD (0x86000000 | UBAMAP_DP | UBAMAP_PAG)
148 #define UBAMAP_WR (UBAMAP_RD)
149
150 /* Debug switches */
151
152 #define UBA_DEB_RRD 0x01 /* reg reads */
153 #define UBA_DEB_RWR 0x02 /* reg writes */
154 #define UBA_DEB_MRD 0x04 /* map reads */
155 #define UBA_DEB_MWR 0x08 /* map writes */
156 #define UBA_DEB_XFR 0x10 /* transfers */
157 #define UBA_DEB_ERR 0x20 /* errors */
158
159 int32 int_req[IPL_HLVL] = { 0 }; /* intr, IPL 14-17 */
160 uint32 uba_cnf = 0; /* config reg */
161 uint32 uba_cr = 0; /* control reg */
162 uint32 uba_sr = 0; /* status reg */
163 uint32 uba_dr = 0; /* diag ctrl */
164 uint32 uba_int = 0; /* UBA interrupt */
165 uint32 uba_fmer = 0; /* failing map reg */
166 uint32 uba_fubar = 0; /* failing Unibus addr */
167 uint32 uba_svr[4] = { 0 }; /* diag registers */
168 uint32 uba_rvr[4] = { 0 }; /* vector reg */
169 uint32 uba_dpr[UBA_NDPATH] = { 0 }; /* number data paths */
170 uint32 uba_map[UBA_NMAPR] = { 0 }; /* map registers */
171 uint32 uba_aiip = 0; /* adapter init in prog */
172 uint32 uba_uiip = 0; /* Unibus init in prog */
173 uint32 uba_aitime = 250; /* adapter init time */
174 uint32 uba_uitime = 12250; /* Unibus init time */
175 int32 autcon_enb = 1; /* autoconfig enable */
176
177 extern int32 trpirq;
178 extern int32 autcon_enb;
179 extern jmp_buf save_env;
180 extern DEVICE *sim_devices[];
181 extern UNIT cpu_unit;
182 extern uint32 nexus_req[NEXUS_HLVL];
183 extern int32 sim_switches;
184 extern FILE *sim_log, *sim_deb;
185
186 t_stat uba_svc (UNIT *uptr);
187 t_stat uba_reset (DEVICE *dptr);
188 t_stat uba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
189 t_stat uba_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw);
190 t_stat uba_rdreg (int32 *val, int32 pa, int32 mode);
191 t_stat uba_wrreg (int32 val, int32 pa, int32 lnt);
192 int32 uba_get_ubvector (int32 lvl);
193 void uba_ub_nxm (int32 ua);
194 void uba_inv_map (int32 ublk);
195 void uba_eval_int (void);
196 void uba_adap_set_int (int32 flg);
197 void uba_adap_clr_int ();
198 void uba_set_dpr (uint32 ua, t_bool wr);
199 void uba_ubpdn (int32 time);
200 t_bool uba_map_addr (uint32 ua, uint32 *ma);
201 t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc);
202 t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc);
203 t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc);
204 t_stat uba_show_virt (FILE *st, UNIT *uptr, int32 val, void *desc);
205
206 extern int32 eval_int (void);
207 extern t_stat build_dib_tab (void);
208
209 /* Unibus IO page dispatches */
210
211 static t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
212 static t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
213 static DIB *iodibp[IOPAGESIZE >> 1];
214
215 /* Unibus interrupt request to interrupt action map */
216
217 int32 (*int_ack[IPL_HLVL][32])(); /* int ack routines */
218
219 /* Unibus interrupt request to vector map */
220
221 int32 int_vec[IPL_HLVL][32]; /* int req to vector */
222
223 /* Unibus adapter data structures
224
225 uba_dev UBA device descriptor
226 uba_unit UBA units
227 uba_reg UBA register list
228 */
229
230 DIB uba_dib = { TR_UBA, 0, &uba_rdreg, &uba_wrreg, 0, 0 };
231
232 UNIT uba_unit = { UDATA (&uba_svc, 0, 0) };
233
234 REG uba_reg[] = {
235 { HRDATA (IPL14, int_req[0], 32), REG_RO },
236 { HRDATA (IPL15, int_req[1], 32), REG_RO },
237 { HRDATA (IPL16, int_req[2], 32), REG_RO },
238 { HRDATA (IPL17, int_req[3], 32), REG_RO },
239 { HRDATA (CNFR, uba_cnf, 32) },
240 { HRDATA (CR, uba_cr, 32) },
241 { HRDATA (SR, uba_sr, 32) },
242 { HRDATA (DR, uba_dr, 32) },
243 { FLDATA (INT, uba_int, 0) },
244 { FLDATA (NEXINT, nexus_req[IPL_UBA], TR_UBA) },
245 { FLDATA (AIIP, uba_aiip, 0) },
246 { FLDATA (UIIP, uba_uiip, 0) },
247 { HRDATA (FMER, uba_fmer, 32) },
248 { HRDATA (FUBAR, uba_fubar, 32) },
249 { HRDATA (BRSVR0, uba_svr[0], 32) },
250 { HRDATA (BRSVR1, uba_svr[1], 32) },
251 { HRDATA (BRSVR2, uba_svr[2], 32) },
252 { HRDATA (BRSVR3, uba_svr[3], 32) },
253 { HRDATA (BRRVR4, uba_rvr[0], 32) },
254 { HRDATA (BRRVR5, uba_rvr[1], 32) },
255 { HRDATA (BRRVR6, uba_rvr[2], 32) },
256 { HRDATA (BRRVR7, uba_rvr[3], 32) },
257 { BRDATA (DPR, uba_dpr, 16, 32, 16) },
258 { BRDATA (MAP, uba_map, 16, 32, 496) },
259 { DRDATA (AITIME, uba_aitime, 24), PV_LEFT + REG_NZ },
260 { DRDATA (UITIME, uba_uitime, 24), PV_LEFT + REG_NZ },
261 { FLDATA (AUTOCON, autcon_enb, 0), REG_HRO },
262 { NULL }
263 };
264
265 MTAB uba_mod[] = {
266 { MTAB_XTD|MTAB_VDV, TR_UBA, "NEXUS", NULL,
267 NULL, &show_nexus },
268 { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
269 NULL, &show_iospace },
270 { MTAB_XTD|MTAB_VDV, 1, "AUTOCONFIG", "AUTOCONFIG",
271 &set_autocon, &show_autocon },
272 { MTAB_XTD|MTAB_VDV, 0, NULL, "NOAUTOCONFIG",
273 &set_autocon, NULL },
274 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL,
275 NULL, &uba_show_virt },
276 { 0 }
277 };
278
279 DEBTAB uba_deb[] = {
280 { "REGREAD", UBA_DEB_RRD },
281 { "REGWRITE", UBA_DEB_RWR },
282 { "MAPREAD", UBA_DEB_MRD },
283 { "MAPWRITE", UBA_DEB_MWR },
284 { "XFER", UBA_DEB_XFR },
285 { "ERROR", UBA_DEB_ERR },
286 { NULL, 0 }
287 };
288
289 DEVICE uba_dev = {
290 "UBA", &uba_unit, uba_reg, uba_mod,
291 1, 16, UBADDRWIDTH, 2, 16, 16,
292 &uba_ex, &uba_dep, &uba_reset,
293 NULL, NULL, NULL,
294 &uba_dib, DEV_NEXUS | DEV_DEBUG, 0,
295 uba_deb, 0, 0
296 };
297
298 /* Read Unibus adapter register - aligned lw only */
299
300 t_stat uba_rdreg (int32 *val, int32 pa, int32 lnt)
301 {
302 int32 idx, ofs;
303
304 if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */
305 printf (">>UBA: invalid adapter read mask, pa = %X, lnt = %d\r\n", pa, lnt);
306 sbi_set_errcnf (); /* err confirmation */
307 return SCPE_OK;
308 }
309 ofs = NEXUS_GETOFS (pa); /* get offset */
310 if (uba_aiip && (ofs != UBACNF_OF) /* init in prog? */
311 && (ofs != UBADR_OF)) return SCPE_NXM; /* only cnf, dr */
312 if (ofs >= UBAMAP_OF) { /* map? */
313 idx = ofs - UBAMAP_OF;
314 if (idx >= UBA_NMAPR) return SCPE_NXM; /* valid? */
315 *val = uba_map[idx] & UBAMAP_RD;
316 if (DEBUG_PRI (uba_dev, UBA_DEB_MRD))
317 fprintf (sim_deb, ">>UBA: map %d read, value = %X\n", idx, *val);
318 return SCPE_OK;
319 }
320
321 switch (ofs) { /* case on offset */
322
323 case UBACNF_OF: /* CNF */
324 *val = (uba_cnf & UBACNF_RD) | UBACNF_CODE;
325 break;
326
327 case UBACR_OF: /* CR */
328 *val = uba_cr & UBACR_RD;
329 break;
330
331 case UBASR_OF: /* SR */
332 *val = uba_sr & UBASR_RD;
333 break;
334
335 case UBADR_OF: /* DR */
336 *val = (uba_dr & UBADR_RD) | UBADR_MICOK |
337 ((uba_cnf & UBADR_CNF_RD) | UBACNF_CODE);
338 break;
339
340 case UBAFMER_OF: case UBAFMER_OF1: /* FMER */
341 *val = uba_fmer & UBAFMER_RD;
342 break;
343
344 case UBAFUBAR_OF: case UBAFUBAR_OF1: /* FUBAR */
345 *val = uba_fubar & UBAFUBAR_RD;
346 break;
347
348 case UBABRSVR_OF + 0: case UBABRSVR_OF + 1: /* BRSVR */
349 case UBABRSVR_OF + 2: case UBABRSVR_OF + 3:
350 idx = ofs - UBABRSVR_OF;
351 *val = uba_svr[idx];
352 break;
353
354 case UBABRRVR_OF + 0: case UBABRRVR_OF + 1: /* BRRVR */
355 case UBABRRVR_OF + 2: case UBABRRVR_OF + 3:
356 idx = ofs - UBABRRVR_OF;
357 uba_rvr[idx] = uba_get_ubvector (idx);
358 *val = uba_rvr[idx];
359 break;
360
361 case UBADPR_OF + 0: /* DPR */
362 *val = 0; /* direct */
363 break;
364
365 case UBADPR_OF + 1:
366 case UBADPR_OF + 2: case UBADPR_OF + 3:
367 case UBADPR_OF + 4: case UBADPR_OF + 5:
368 case UBADPR_OF + 6: case UBADPR_OF + 7:
369 case UBADPR_OF + 8: case UBADPR_OF + 9:
370 case UBADPR_OF + 10: case UBADPR_OF + 11:
371 case UBADPR_OF + 12: case UBADPR_OF + 13:
372 case UBADPR_OF + 14: case UBADPR_OF + 15:
373 idx = ofs - UBADPR_OF;
374 *val = uba_dpr[idx] & UBADPR_RD;
375 break;
376
377 default:
378 return SCPE_NXM;
379 }
380
381 if (DEBUG_PRI (uba_dev, UBA_DEB_RRD))
382 fprintf (sim_deb, ">>UBA: reg %d read, value = %X\n", ofs, *val);
383 return SCPE_OK;
384 }
385
386 /* Write Unibus adapter register */
387
388 t_stat uba_wrreg (int32 val, int32 pa, int32 lnt)
389 {
390 int32 idx, ofs, old_cr;
391
392 if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */
393 printf (">>UBA: invalid adapter write mask, pa = %X, lnt = %d\r\n", pa, lnt);
394 sbi_set_errcnf (); /* err confirmation */
395 return SCPE_OK;
396 }
397 ofs = NEXUS_GETOFS (pa); /* get offset */
398 if (uba_aiip && (ofs != UBACNF_OF) && (ofs != UBADR_OF) &&
399 (ofs != UBACR_OF) && (ofs != UBASR_OF)) return SCPE_NXM;
400 if (ofs >= UBAMAP_OF) { /* map? */
401 idx = ofs - UBAMAP_OF;
402 if (idx >= UBA_NMAPR) return SCPE_NXM; /* valid? */
403 uba_map[idx] = val & UBAMAP_WR;
404 if (DEBUG_PRI (uba_dev, UBA_DEB_MWR))
405 fprintf (sim_deb, ">>UBA: map %d write, value = %X\n", idx, val);
406 return SCPE_OK;
407 }
408
409 switch (ofs) { /* case on offset */
410
411 case UBACNF_OF: /* CNF */
412 uba_cnf = uba_cnf & ~(val & UBACNF_W1C); /* W1C bits */
413 uba_adap_clr_int (); /* possible clr int */
414 break;
415
416 case UBACR_OF: /* CR */
417 old_cr = uba_cr;
418 if (val & UBACR_ADINIT) { /* adapter init */
419 uba_reset (&uba_dev); /* reset adapter */
420 uba_aiip = 1; /* set init in prog */
421 uba_ubpdn (uba_aitime); /* power fail UB */
422 }
423 if ((val & UBACR_UPF) && !(old_cr & UBACR_UPF) /* Unibus power clear */
424 && !sim_is_active (&uba_unit))
425 uba_ubpdn (uba_aitime + uba_uitime); /* power fail UB */
426 uba_cr = (uba_cr & ~UBACR_WR) | (val & UBACR_WR);
427 uba_adap_set_int (uba_cr & ~old_cr); /* possible int set */
428 uba_adap_clr_int (); /* possible int clr */
429 break;
430
431 case UBASR_OF: /* SR */
432 uba_sr = uba_sr & ~(val & UBASR_W1C); /* W1C bits */
433 uba_adap_clr_int (); /* possible clr int */
434 break;
435
436 case UBADR_OF: /* DR */
437 uba_dr = (uba_dr & ~UBADR_WR) | (val & UBADR_WR);
438 uba_cnf = uba_cnf & ~(val & UBACNF_W1C);
439 uba_adap_clr_int (); /* possible clr int */
440 break;
441
442 case UBABRSVR_OF + 0: case UBABRSVR_OF + 1: /* BRSVR */
443 case UBABRSVR_OF + 2: case UBABRSVR_OF + 3:
444 idx = ofs - UBABRSVR_OF;
445 uba_svr[idx] = val;
446 break;
447
448 case UBADPR_OF + 0: /* DPR */
449 break; /* direct */
450
451 case UBADPR_OF + 1:
452 case UBADPR_OF + 2: case UBADPR_OF + 3:
453 case UBADPR_OF + 4: case UBADPR_OF + 5:
454 case UBADPR_OF + 6: case UBADPR_OF + 7:
455 case UBADPR_OF + 8: case UBADPR_OF + 9:
456 case UBADPR_OF + 10: case UBADPR_OF + 11:
457 case UBADPR_OF + 12: case UBADPR_OF + 13:
458 case UBADPR_OF + 14: case UBADPR_OF + 15:
459 idx = ofs - UBADPR_OF;
460 uba_dpr[idx] = uba_dpr[idx] & ~(val & UBADPR_W1C);
461 break;
462
463 default:
464 return SCPE_NXM;
465 }
466
467 if (DEBUG_PRI (uba_dev, UBA_DEB_RWR))
468 fprintf (sim_deb, ">>UBA: reg %d write, value = %X\n", ofs, val);
469 return SCPE_OK;
470 }
471
472 /* Read and write Unibus I/O space */
473
474 int32 ReadUb (uint32 pa)
475 {
476 int32 idx, val;
477
478 if (ADDR_IS_IOP (pa) && !uba_uiip) { /* iopage,!init */
479 idx = (pa & IOPAGEMASK) >> 1;
480 if (iodispR[idx]) {
481 iodispR[idx] (&val, pa, READ);
482 return val;
483 }
484 }
485 uba_ub_nxm (pa); /* UB nxm */
486 return 0;
487 }
488
489 void WriteUb (uint32 pa, int32 val, int32 mode)
490 {
491 int32 idx;
492
493 if (ADDR_IS_IOP (pa) && !uba_uiip) { /* iopage,!init */
494 idx = (pa & IOPAGEMASK) >> 1;
495 if (iodispW[idx]) {
496 iodispW[idx] (val, pa, mode);
497 return;
498 }
499 }
500 uba_ub_nxm (pa); /* UB nxm */
501 return;
502 }
503
504 /* ReadIO - read from IO - UBA only responds to byte, aligned word
505
506 Inputs:
507 pa = physical address
508 lnt = length (BWLQ)
509 Output:
510 longword of data
511 */
512
513 int32 ReadIO (uint32 pa, int32 lnt)
514 {
515 uint32 iod;
516
517 if ((lnt == L_BYTE) || /* byte? */
518 ((lnt == L_WORD) && ((pa & 1) == 0))) { /* aligned word? */
519 iod = ReadUb (pa); /* DATI from Unibus */
520 if (pa & 2) iod = iod << 16; /* position */
521 }
522 else {
523 printf (">>UBA: invalid read mask, pa = %x, lnt = %d\n", pa, lnt);
524 sbi_set_errcnf (); /* err confirmation */
525 iod = 0;
526 }
527 SET_IRQL;
528 return iod;
529 }
530
531 /* WriteIO - write to IO - UBA only responds to byte, aligned word
532
533 Inputs:
534 pa = physical address
535 val = data to write, right justified in 32b longword
536 lnt = length (BWL)
537 Outputs:
538 none
539 */
540
541 void WriteIO (uint32 pa, int32 val, int32 lnt)
542 {
543 if (lnt == L_BYTE) WriteUb (pa, val, WRITEB); /* byte? DATOB */
544 else if ((lnt == L_WORD) && ((pa & 1) == 0)) /* aligned word? */
545 WriteUb (pa, val, WRITE); /* DATO */
546 else {
547 printf (">>UBA: invalid write mask, pa = %x, lnt = %d\n", pa, lnt);
548 sbi_set_errcnf (); /* err confirmation */
549 }
550 SET_IRQL; /* update ints */
551 return;
552 }
553
554 /* Update UBA nexus interrupts */
555
556 void uba_eval_int (void)
557 {
558 int32 i;
559
560 for (i = 0; i < (IPL_HMAX - IPL_HMIN); i++) /* clear all UBA req */
561 nexus_req[i] &= ~(1 << TR_UBA);
562 if (((uba_dr & UBADR_DINTR) == 0) && !uba_uiip && /* intr enabled? */
563 (uba_cr & UBACR_IFS) && (uba_cr & UBACR_BRIE)) {
564 for (i = 0; i < (IPL_HMAX - IPL_HMIN); i++) {
565 if (int_req[i]) nexus_req[i] |= (1 << TR_UBA);
566 }
567 }
568 if (uba_int) SET_NEXUS_INT (UBA); /* adapter int? */
569 return;
570 }
571
572 /* Return vector for Unibus interrupt at relative IPL level [0-3] */
573
574 int32 uba_get_ubvector (int32 lvl)
575 {
576 int32 i, vec;
577
578 vec = 0;
579 if ((lvl == (IPL_UBA - IPL_HMIN)) && uba_int) { /* UBA lvl, int? */
580 vec = UBA_UVEC; /* set flag */
581 uba_int = 0; /* clear int */
582 }
583 if (((uba_dr & UBADR_DINTR) == 0) && !uba_uiip && /* intr enabled? */
584 (uba_cr & UBACR_IFS) && (uba_cr & UBACR_BRIE)) {
585 for (i = 0; int_req[lvl] && (i < 32); i++) {
586 if ((int_req[lvl] >> i) & 1) {
587 int_req[lvl] = int_req[lvl] & ~(1u << i);
588 if (int_ack[lvl][i]) return (vec | int_ack[lvl][i]());
589 return (vec | int_vec[lvl][i]);
590 }
591 }
592 }
593 return vec;
594 }
595
596 /* Unibus I/O buffer routines
597
598 Map_ReadB - fetch byte buffer from memory
599 Map_ReadW - fetch word buffer from memory
600 Map_WriteB - store byte buffer into memory
601 Map_WriteW - store word buffer into memory
602 */
603
604 int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)
605 {
606 int32 i, j, pbc;
607 uint32 ma, dat;
608
609 ba = ba & UBADDRMASK; /* mask UB addr */
610 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
611 if (!uba_map_addr (ba + i, &ma)) return (bc - i); /* page inv or NXM? */
612 pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */
613 if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
614 if (DEBUG_PRI (uba_dev, UBA_DEB_XFR))
615 fprintf (sim_deb, ">>UBA: 8b read, ma = %X, bc = %X\n", ma, pbc);
616 if ((ma | pbc) & 3) { /* aligned LW? */
617 for (j = 0; j < pbc; ma++, j++) { /* no, do by bytes */
618 *buf++ = ReadB (ma);
619 }
620 }
621 else { /* yes, do by LW */
622 for (j = 0; j < pbc; ma = ma + 4, j = j + 4) {
623 dat = ReadL (ma); /* get lw */
624 *buf++ = dat & BMASK; /* low 8b */
625 *buf++ = (dat >> 8) & BMASK; /* next 8b */
626 *buf++ = (dat >> 16) & BMASK; /* next 8b */
627 *buf++ = (dat >> 24) & BMASK;
628 }
629 }
630 uba_set_dpr (ba + i + pbc - L_BYTE, FALSE);
631 }
632 return 0;
633 }
634
635 int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
636 {
637 int32 i, j, pbc;
638 uint32 ma, dat;
639
640 ba = ba & UBADDRMASK; /* mask UB addr */
641 bc = bc & ~01;
642 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
643 if (!uba_map_addr (ba + i, &ma)) return (bc - i); /* page inv or NXM? */
644 pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */
645 if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
646 if (DEBUG_PRI (uba_dev, UBA_DEB_XFR))
647 fprintf (sim_deb, ">>UBA: 16b read, ma = %X, bc = %X\n", ma, pbc);
648 if ((ma | pbc) & 1) { /* aligned word? */
649 for (j = 0; j < pbc; ma++, j++) { /* no, do by bytes */
650 if ((i + j) & 1) { /* odd byte? */
651 *buf = (*buf & BMASK) | (ReadB (ma) << 8);
652 buf++;
653 }
654 else *buf = (*buf & ~BMASK) | ReadB (ma);
655 }
656 }
657 else if ((ma | pbc) & 3) { /* aligned LW? */
658 for (j = 0; j < pbc; ma = ma + 2, j = j + 2) { /* no, words */
659 *buf++ = ReadW (ma); /* get word */
660 }
661 }
662 else { /* yes, do by LW */
663 for (j = 0; j < pbc; ma = ma + 4, j = j + 4) {
664 dat = ReadL (ma); /* get lw */
665 *buf++ = dat & WMASK; /* low 16b */
666 *buf++ = (dat >> 16) & WMASK; /* high 16b */
667 }
668 }
669 uba_set_dpr (ba + i + pbc - L_WORD, FALSE);
670 }
671 return 0;
672 }
673
674 int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)
675 {
676 int32 i, j, pbc;
677 uint32 ma, dat;
678
679 ba = ba & UBADDRMASK; /* mask UB addr */
680 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
681 if (!uba_map_addr (ba + i, &ma)) return (bc - i); /* page inv or NXM? */
682 pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */
683 if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
684 if (DEBUG_PRI (uba_dev, UBA_DEB_XFR))
685 fprintf (sim_deb, ">>UBA: 8b write, ma = %X, bc = %X\n", ma, pbc);
686 if ((ma | pbc) & 3) { /* aligned LW? */
687 for (j = 0; j < pbc; ma++, j++) { /* no, do by bytes */
688 WriteB (ma, *buf);
689 buf++;
690 }
691 }
692 else { /* yes, do by LW */
693 for (j = 0; j < pbc; ma = ma + 4, j = j + 4) {
694 dat = (uint32) *buf++; /* get low 8b */
695 dat = dat | (((uint32) *buf++) << 8); /* merge next 8b */
696 dat = dat | (((uint32) *buf++) << 16); /* merge next 8b */
697 dat = dat | (((uint32) *buf++) << 24); /* merge hi 8b */
698 WriteL (ma, dat); /* store lw */
699 }
700 }
701 uba_set_dpr (ba + i + pbc - L_BYTE, TRUE);
702 }
703 return 0;
704 }
705
706 int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)
707 {
708 int32 i, j, pbc;
709 uint32 ma, dat;
710
711 ba = ba & UBADDRMASK; /* mask UB addr */
712 bc = bc & ~01;
713 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
714 if (!uba_map_addr (ba + i, &ma)) return (bc - i); /* page inv or NXM? */
715 pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */
716 if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
717 if (DEBUG_PRI (uba_dev, UBA_DEB_XFR))
718 fprintf (sim_deb, ">>UBA: 16b write, ma = %X, bc = %X\n", ma, pbc);
719 if ((ma | pbc) & 1) { /* aligned word? */
720 for (j = 0; j < pbc; ma++, j++) { /* no, bytes */
721 if ((i + j) & 1) {
722 WriteB (ma, (*buf >> 8) & BMASK);
723 buf++;
724 }
725 else WriteB (ma, *buf & BMASK);
726 }
727 }
728 else if ((ma | pbc) & 3) { /* aligned LW? */
729 for (j = 0; j < pbc; ma = ma + 2, j = j + 2) { /* no, words */
730 WriteW (ma, *buf); /* write word */
731 buf++;
732 }
733 }
734 else { /* yes, do by LW */
735 for (j = 0; j < pbc; ma = ma + 4, j = j + 4) {
736 dat = (uint32) *buf++; /* get low 16b */
737 dat = dat | (((uint32) *buf++) << 16); /* merge hi 16b */
738 WriteL (ma, dat); /* store LW */
739 }
740 }
741 uba_set_dpr (ba + i + pbc - L_WORD, TRUE);
742 }
743 return 0;
744 }
745
746 /* Map an address via the translation map */
747
748 t_bool uba_map_addr (uint32 ua, uint32 *ma)
749 {
750 uint32 ublk, umap;
751
752 ublk = ua >> VA_V_VPN; /* Unibus blk */
753 if ((ublk < UBACR_GETDSB (uba_cr)) || /* map disabled? */
754 (ublk >= UBA_NMAPR)) return FALSE; /* unimplemented? */
755 umap = uba_map[ublk]; /* get map */
756 if (umap & UBAMAP_VLD) { /* valid? */
757 *ma = ((umap & UBAMAP_PAG) << VA_V_VPN) + VA_GETOFF (ua);
758 if ((umap & UBAMAP_DP) && (umap & UBAMAP_ODD)) /* buffered dp? */
759 *ma = *ma + 1; /* byte offset? */
760 return (ADDR_IS_MEM (*ma)); /* legit addr */
761 }
762 uba_inv_map (ua); /* invalid map */
763 return FALSE;
764 }
765
766 /* Map an address via the translation map - console version (no status changes) */
767
768 t_bool uba_map_addr_c (uint32 ua, uint32 *ma)
769 {
770 uint32 ublk, umap;
771
772 ublk = ua >> VA_V_VPN; /* Unibus blk */
773 if ((ublk < UBACR_GETDSB (uba_cr)) || /* map disabled? */
774 (ublk >= UBA_NMAPR)) return FALSE; /* unimplemented? */
775 umap = uba_map[ublk]; /* get map */
776 if (umap & UBAMAP_VLD) { /* valid? */
777 *ma = ((umap & UBAMAP_PAG) << VA_V_VPN) + VA_GETOFF (ua);
778 if ((umap & UBAMAP_DP) && (umap & UBAMAP_ODD)) /* buffered dp? */
779 *ma = *ma + 1; /* byte offset? */
780 return TRUE; /* legit addr */
781 }
782 return FALSE;
783 }
784
785 /* At end of page or transfer, update DPR register, in case next page
786 gets an error */
787
788 void uba_set_dpr (uint32 ua, t_bool wr)
789 {
790 uint32 ublk, umap, dpr;
791
792 ublk = ua >> VA_V_VPN; /* Unibus blk */
793 if (ublk >= UBA_NMAPR) return; /* paranoia */
794 umap = uba_map[ublk]; /* get map */
795 dpr = UBAMAP_GETDP (umap); /* get bdp */
796 if (dpr) uba_dpr[dpr] = (uba_dpr[dpr] & ~(UBADPR_UA|UBADPR_DIR)) |
797 (wr? UBADPR_DIR: 0) |
798 (((ua >> 2) + ((umap & UBAMAP_ODD)? 1: 0)) & UBADPR_UA);
799 return;
800 }
801
802 /* Error routines
803
804 uba_ub_nxm SBI read/write to nx Unibus address
805 uba_inv_map Unibus reference to invalid map reg
806 */
807
808 void uba_ub_nxm (int32 ua)
809 {
810 if ((uba_sr & UBASR_UBTMO) == 0) {
811 uba_sr |= UBASR_UBTMO;
812 uba_adap_set_int (uba_cr & UBACR_SUEFIE);
813 uba_fubar = (ua >> 2) & UBAFUBAR_RD;
814 }
815 else uba_sr |= UBASR_LEB;
816 if (DEBUG_PRI (uba_dev, UBA_DEB_ERR))
817 fprintf (sim_deb, ">>UBA: nxm error, ua = %X\n", ua);
818 return;
819 }
820
821 void uba_inv_map (int32 ublk)
822 {
823 if ((uba_sr & UBASR_IVMR) == 0) {
824 uba_sr |= UBASR_IVMR;
825 uba_adap_set_int (uba_cr & UBACR_USEFIE);
826 uba_fmer = ublk & UBAFMER_RD;
827 }
828 else uba_sr |= UBASR_LEB;
829 if (DEBUG_PRI (uba_dev, UBA_DEB_ERR))
830 fprintf (sim_deb, ">>UBA: inv map error, ublk = %X\n", ublk);
831 return;
832 }
833
834 /* Unibus power fail routines */
835
836 void uba_ubpdn (int32 time)
837 {
838 int32 i;
839 DEVICE *dptr;
840
841 uba_cnf = (uba_cnf & ~UBACNF_UBIC) | UBACNF_UBPDN; /* update cnf */
842 sim_activate (&uba_unit, time); /* schedule */
843 uba_uiip = 1; /* UB init in prog */
844 for (i = 0; sim_devices[i] != NULL; i++) { /* reset Unibus */
845 dptr = sim_devices[i];
846 if (dptr->reset && (dptr->flags & DEV_UBUS))
847 dptr->reset (dptr);
848 }
849 return;
850 }
851
852 /* Init timeout service routine */
853
854 t_stat uba_svc (UNIT *uptr)
855 {
856 if (uba_aiip) { /* adapter init? */
857 uba_aiip = 0; /* clear in prog */
858 sim_activate (uptr, uba_uitime); /* schedule UB */
859 }
860 else {
861 uba_uiip = 0; /* no, UB */
862 uba_cnf = (uba_cnf & ~UBACNF_UBPDN) | UBACNF_UBIC;
863 uba_adap_set_int (uba_cr & UBACR_CNFIE); /* possible int */
864 }
865 return SCPE_OK;
866 }
867
868 /* Interrupt routines */
869
870 void uba_adap_set_int (int32 flg)
871 {
872 if (((flg & UBACR_SUEFIE) && (uba_sr & UBA_SUEFIE_SR)) ||
873 ((flg & UBACR_USEFIE) && (uba_sr & UBA_USEFIE_SR)) ||
874 ((flg & UBACR_CNFIE) && (uba_cr & UBA_CNFIE_CR))) {
875 uba_int = 1;
876 if (DEBUG_PRI (uba_dev, UBA_DEB_ERR)) fprintf (sim_deb,
877 ">>UBA: adapter int req, sr = %X, cr = %X\n", uba_sr, uba_cr);
878 }
879 return;
880 }
881
882 void uba_adap_clr_int ()
883 {
884 if ((!(uba_cr & UBACR_SUEFIE) || !(uba_sr & UBA_SUEFIE_SR)) &&
885 (!(uba_cr & UBACR_USEFIE) || !(uba_sr & UBA_USEFIE_SR)) &&
886 (!(uba_cr & UBACR_CNFIE) || !(uba_cr & UBA_CNFIE_CR)))
887 uba_int = 0;
888 return;
889 }
890
891 /* Reset Unibus adapter */
892
893 t_stat uba_reset (DEVICE *dptr)
894 {
895 int32 i;
896
897 uba_int = 0;
898 uba_aiip = uba_uiip = 0;
899 sim_cancel (&uba_unit);
900 for (i = 0; i < IPL_HLVL; i++) {
901 nexus_req[i] &= ~(1 << TR_UBA);
902 int_req[i] = 0;
903 uba_svr[i] = 0;
904 uba_rvr[i] = 0;
905 }
906 for (i = 0; i < UBA_NMAPR; i++) uba_map[i] = 0;
907 for (i = 0; i < UBA_NDPATH; i++) uba_dpr[i] = 0;
908 uba_sr = 0;
909 uba_cr = 0;
910 uba_dr = 0;
911 uba_cnf = UBACNF_UBIC;
912 return SCPE_OK;
913 }
914
915 /* Memory examine via map (word only) */
916
917 t_stat uba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
918 {
919 uint32 ua = (uint32) exta, pa;
920
921 if ((vptr == NULL) || (ua >= UBADDRSIZE)) return SCPE_ARG;
922 if (uba_map_addr_c (ua, &pa) && ADDR_IS_MEM (pa)) {
923 *vptr = (uint32) ReadW (pa);
924 return SCPE_OK;
925 }
926 return SCPE_NXM;
927 }
928
929 /* Memory deposit via map (word only) */
930
931 t_stat uba_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
932 {
933 uint32 ua = (uint32) exta, pa;
934
935 if (ua >= UBADDRSIZE) return SCPE_ARG;
936 if (uba_map_addr_c (ua, &pa) && ADDR_IS_MEM (pa)) {
937 WriteW (pa, (int32) val);
938 return SCPE_OK;
939 }
940 return SCPE_NXM;
941 }
942
943 /* Enable/disable autoconfiguration */
944
945 t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc)
946 {
947 if (cptr != NULL) return SCPE_ARG;
948 autcon_enb = val;
949 return auto_config (NULL, 0);
950 }
951
952 /* Show autoconfiguration status */
953
954 t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc)
955 {
956 fprintf (st, "autoconfiguration ");
957 fprintf (st, autcon_enb? "enabled": "disabled");
958 return SCPE_OK;
959 }
960
961 /* Change device address */
962
963 t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)
964 {
965 DEVICE *dptr;
966 DIB *dibp;
967 uint32 newba;
968 t_stat r;
969
970 if (cptr == NULL) return SCPE_ARG;
971 if ((val == 0) || (uptr == NULL)) return SCPE_IERR;
972 dptr = find_dev_from_unit (uptr);
973 if (dptr == NULL) return SCPE_IERR;
974 dibp = (DIB *) dptr->ctxt;
975 if (dibp == NULL) return SCPE_IERR;
976 newba = (uint32) get_uint (cptr, 16, IOPAGEBASE+IOPAGEMASK, &r);
977 if (r != SCPE_OK) return r;
978 if ((newba <= IOPAGEBASE) || /* must be > 0 */
979 (newba % ((uint32) val))) return SCPE_ARG; /* check modulus */
980 dibp->ba = newba; /* store */
981 dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */
982 autcon_enb = 0; /* autoconfig off */
983 return SCPE_OK;
984 }
985
986 /* Show device address */
987
988 t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc)
989 {
990 DEVICE *dptr;
991 DIB *dibp;
992
993 if (uptr == NULL) return SCPE_IERR;
994 dptr = find_dev_from_unit (uptr);
995 if (dptr == NULL) return SCPE_IERR;
996 dibp = (DIB *) dptr->ctxt;
997 if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;
998 fprintf (st, "address=%08X", dibp->ba);
999 if (dibp->lnt > 1)
1000 fprintf (st, "-%08X", dibp->ba + dibp->lnt - 1);
1001 if (dptr->flags & DEV_FLTA) fprintf (st, "*");
1002 return SCPE_OK;
1003 }
1004
1005 /* Set address floating */
1006
1007 t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc)
1008 {
1009 DEVICE *dptr;
1010
1011 if (cptr == NULL) return SCPE_ARG;
1012 if ((val == 0) || (uptr == NULL)) return SCPE_IERR;
1013 dptr = find_dev_from_unit (uptr);
1014 if (dptr == NULL) return SCPE_IERR;
1015 dptr->flags = dptr->flags | DEV_FLTA; /* floating */
1016 return auto_config (NULL, 0); /* autoconfigure */
1017 }
1018
1019 /* Change device vector */
1020
1021 t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc)
1022 {
1023 DEVICE *dptr;
1024 DIB *dibp;
1025 uint32 newvec;
1026 t_stat r;
1027
1028 if (cptr == NULL) return SCPE_ARG;
1029 if (uptr == NULL) return SCPE_IERR;
1030 dptr = find_dev_from_unit (uptr);
1031 if (dptr == NULL) return SCPE_IERR;
1032 dibp = (DIB *) dptr->ctxt;
1033 if (dibp == NULL) return SCPE_IERR;
1034 newvec = (uint32) get_uint (cptr, 16, 01000, &r);
1035 if ((r != SCPE_OK) ||
1036 ((newvec + (dibp->vnum * 4)) >= 01000) ||
1037 (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG;
1038 dibp->vec = newvec;
1039 dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */
1040 autcon_enb = 0; /* autoconfig off */
1041 return SCPE_OK;
1042 }
1043
1044 /* Show device vector */
1045
1046 t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc)
1047 {
1048 DEVICE *dptr;
1049 DIB *dibp;
1050 uint32 vec, numvec;
1051
1052 if (uptr == NULL) return SCPE_IERR;
1053 dptr = find_dev_from_unit (uptr);
1054 if (dptr == NULL) return SCPE_IERR;
1055 dibp = (DIB *) dptr->ctxt;
1056 if (dibp == NULL) return SCPE_IERR;
1057 vec = dibp->vec;
1058 if (arg) numvec = arg;
1059 else numvec = dibp->vnum;
1060 if (vec == 0) fprintf (st, "no vector");
1061 else {
1062 fprintf (st, "vector=%X", vec);
1063 if (numvec > 1) fprintf (st, "-%X", vec + (4 * (numvec - 1)));
1064 }
1065 return SCPE_OK;
1066 }
1067
1068 /* Init Unibus tables */
1069
1070 void init_ubus_tab (void)
1071 {
1072 int32 i, j;
1073
1074 for (i = 0; i < IPL_HLVL; i++) { /* clear int tables */
1075 for (j = 0; j < 32; j++) {
1076 int_vec[i][j] = 0;
1077 int_ack[i][j] = NULL;
1078 }
1079 }
1080 for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */
1081 iodispR[i] = NULL;
1082 iodispW[i] = NULL;
1083 iodibp[i] = NULL;
1084 }
1085 return;
1086 }
1087
1088 /* Build Unibus tables */
1089
1090 t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp)
1091 {
1092 int32 i, idx, vec, ilvl, ibit;
1093
1094 if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */
1095 if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;
1096 for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */
1097 idx = dibp->vloc + i; /* vector index */
1098 vec = dibp->vec? (dibp->vec + (i * 4)): 0; /* vector addr */
1099 ilvl = idx / 32;
1100 ibit = idx % 32;
1101 if ((int_ack[ilvl][ibit] && dibp->ack[i] && /* conflict? */
1102 (int_ack[ilvl][ibit] != dibp->ack[i])) ||
1103 (int_vec[ilvl][ibit] && vec &&
1104 (int_vec[ilvl][ibit] != vec))) {
1105 printf ("Device %s interrupt slot conflict at %d\n",
1106 sim_dname (dptr), idx);
1107 if (sim_log) fprintf (sim_log,
1108 "Device %s interrupt slot conflict at %d\n",
1109 sim_dname (dptr), idx);
1110 return SCPE_STOP;
1111 }
1112 if (dibp->ack[i]) int_ack[ilvl][ibit] = dibp->ack[i];
1113 else if (vec) int_vec[ilvl][ibit] = vec;
1114 }
1115 for (i = 0; i < (int32) dibp->lnt; i = i + 2) { /* create entries */
1116 idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */
1117 if ((iodispR[idx] && dibp->rd && /* conflict? */
1118 (iodispR[idx] != dibp->rd)) ||
1119 (iodispW[idx] && dibp->wr &&
1120 (iodispW[idx] != dibp->wr))) {
1121 printf ("Device %s address conflict at %08o\n",
1122 sim_dname (dptr), dibp->ba);
1123 if (sim_log) fprintf (sim_log,
1124 "Device %s address conflict at %08o\n",
1125 sim_dname (dptr), dibp->ba);
1126 return SCPE_STOP;
1127 }
1128 if (dibp->rd) iodispR[idx] = dibp->rd; /* set rd dispatch */
1129 if (dibp->wr) iodispW[idx] = dibp->wr; /* set wr dispatch */
1130 iodibp[idx] = dibp; /* remember DIB */
1131 }
1132 return SCPE_OK;
1133 }
1134
1135 /* Show IO space */
1136
1137 t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc)
1138 {
1139 uint32 i, j;
1140 DEVICE *dptr;
1141 DIB *dibp;
1142
1143 if (build_dib_tab ()) return SCPE_OK; /* build IO page */
1144 for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */
1145 if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */
1146 dibp = iodibp[i]; /* DIB for block */
1147 for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
1148 if (((DIB*) sim_devices[j]->ctxt) == dibp) {
1149 dptr = sim_devices[j]; /* locate device */
1150 break;
1151 } /* end if */
1152 } /* end for j */
1153 fprintf (st, "%08X - %08X%c\t%s\n", dibp->ba,
1154 dibp->ba + dibp->lnt - 1,
1155 (dptr && (dptr->flags & DEV_FLTA))? '*': ' ',
1156 dptr? sim_dname (dptr): "CPU");
1157 } /* end if */
1158 } /* end for i */
1159 return SCPE_OK;
1160 }
1161
1162 /* Show UBA virtual address */
1163
1164 t_stat uba_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc)
1165 {
1166 t_stat r;
1167 char *cptr = (char *) desc;
1168 uint32 ua, pa;
1169
1170 if (cptr) {
1171 ua = (uint32) get_uint (cptr, 16, UBADDRSIZE - 1, &r);
1172 if (r == SCPE_OK) {
1173 if (uba_map_addr_c (ua, &pa))
1174 fprintf (of, "Unibus %-X = physical %-X\n", ua, pa);
1175 else fprintf (of, "Unibus %-X: invalid mapping\n", ua);
1176 return SCPE_OK;
1177 }
1178 }
1179 fprintf (of, "Invalid argument\n");
1180 return SCPE_OK;
1181 }
1182
1183 /* Autoconfiguration
1184
1185 The table reflects the MicroVAX 3900 microcode, with one addition - the
1186 number of controllers field handles devices where multiple instances
1187 are simulated through a single DEVICE structure (e.g., DZ, VH).
1188
1189 A minus number of vectors indicates a field that should be calculated
1190 but not placed in the DIB (RQ, TQ dynamic vectors) */
1191
1192 #define AUTO_MAXC 4
1193 #define AUTO_CSRBASE 0010
1194 #define AUTO_VECBASE 0300
1195
1196 typedef struct {
1197 char *dnam[AUTO_MAXC];
1198 int32 numc;
1199 int32 numv;
1200 uint32 amod;
1201 uint32 vmod;
1202 uint32 fixa[AUTO_MAXC];
1203 uint32 fixv[AUTO_MAXC];
1204 } AUTO_CON;
1205
1206 AUTO_CON auto_tab[] = {
1207 { { NULL }, 1, 2, 0, 8, { 0 } }, /* DLV11J - fx CSRs */
1208 { { NULL }, 1, 2, 8, 8 }, /* DJ11 */
1209 { { NULL }, 1, 2, 16, 8 }, /* DH11 */
1210 { { NULL }, 1, 2, 8, 8 }, /* DQ11 */
1211 { { NULL }, 1, 2, 8, 8 }, /* DU11 */
1212 { { NULL }, 1, 2, 8, 8 }, /* DUP11 */
1213 { { NULL }, 10, 2, 8, 8 }, /* LK11A */
1214 { { NULL }, 1, 2, 8, 8 }, /* DMC11 */
1215 { { "DZ" }, DZ_MUXES, 2, 8, 8 }, /* DZ11 */
1216 { { NULL }, 1, 2, 8, 8 }, /* KMC11 */
1217 { { NULL }, 1, 2, 8, 8 }, /* LPP11 */
1218 { { NULL }, 1, 2, 8, 8 }, /* VMV21 */
1219 { { NULL }, 1, 2, 16, 8 }, /* VMV31 */
1220 { { NULL }, 1, 2, 8, 8 }, /* DWR70 */
1221 { { "RL", "RLB" }, 1, 1, 8, 4, {IOBA_RL}, {VEC_RL} }, /* RL11 */
1222 { { "TS", "TSB", "TSC", "TSD" }, 1, 1, 0, 4, /* TS11 */
1223 {IOBA_TS, IOBA_TS + 4, IOBA_TS + 8, IOBA_TS + 12},
1224 {VEC_TS} },
1225 { { NULL }, 1, 2, 16, 8 }, /* LPA11K */
1226 { { NULL }, 1, 2, 8, 8 }, /* KW11C */
1227 { { NULL }, 1, 1, 8, 8 }, /* reserved */
1228 { { "RX", "RY" }, 1, 1, 8, 4, {IOBA_RX} , {VEC_RX} }, /* RX11/RX211 */
1229 { { NULL }, 1, 1, 8, 4 }, /* DR11W */
1230 { { NULL }, 1, 1, 8, 4, { 0, 0 }, { 0 } }, /* DR11B - fx CSRs,vec */
1231 { { NULL }, 1, 2, 8, 8 }, /* DMP11 */
1232 { { NULL }, 1, 2, 8, 8 }, /* DPV11 */
1233 { { NULL }, 1, 2, 8, 8 }, /* ISB11 */
1234 { { NULL }, 1, 2, 16, 8 }, /* DMV11 */
1235 { { "XU", "XUB" }, 1, 1, 8, 4, {IOBA_XU}, {VEC_XU} }, /* DEUNA */
1236 { { "XQ", "XQB" }, 1, 1, 0, 4, /* DEQNA */
1237 {IOBA_XQ,IOBA_XQB}, {VEC_XQ} }, /* */
1238 { { "RQ", "RQB", "RQC", "RQD" }, 1, -1, 4, 4, /* RQDX3 */
1239 {IOBA_RQ}, {VEC_RQ} },
1240 { { NULL }, 1, 8, 32, 4 }, /* DMF32 */
1241 { { NULL }, 1, 2, 16, 8 }, /* KMS11 */
1242 { { NULL }, 1, 1, 16, 4 }, /* VS100 */
1243 { { "TQ", "TQB" }, 1, -1, 4, 4, {IOBA_TQ}, {VEC_TQ} }, /* TQK50 */
1244 { { NULL }, 1, 2, 16, 8 }, /* KMV11 */
1245 { { "VH" }, VH_MUXES, 2, 16, 8 }, /* DHU11/DHQ11 */
1246 { { NULL }, 1, 6, 32, 4 }, /* DMZ32 */
1247 { { NULL }, 1, 6, 32, 4 }, /* CP132 */
1248 { { NULL }, 1, 2, 64, 8, { 0 } }, /* QVSS - fx CSR */
1249 { { NULL }, 1, 1, 8, 4 }, /* VS31 */
1250 { { NULL }, 1, 1, 0, 4, { 0 } }, /* LNV11 - fx CSR */
1251 { { NULL }, 1, 1, 16, 4 }, /* LNV21/QPSS */
1252 { { NULL }, 1, 1, 8, 4, { 0 } }, /* QTA - fx CSR */
1253 { { NULL }, 1, 1, 8, 4 }, /* DSV11 */
1254 { { NULL }, 1, 2, 8, 8 }, /* CSAM */
1255 { { NULL }, 1, 2, 8, 8 }, /* ADV11C */
1256 { { NULL }, 1, 0, 8, 0 }, /* AAV11C */
1257 { { NULL }, 1, 2, 8, 8, { 0 }, { 0 } }, /* AXV11C - fx CSR,vec */
1258 { { NULL }, 1, 2, 4, 8, { 0 } }, /* KWV11C - fx CSR */
1259 { { NULL }, 1, 2, 8, 8, { 0 } }, /* ADV11D - fx CSR */
1260 { { NULL }, 1, 2, 8, 8, { 0 } }, /* AAV11D - fx CSR */
1261 { { "QDSS" }, 1, 3, 0, 16, {IOBA_QDSS} }, /* QDSS - fx CSR */
1262 { { NULL }, -1 } /* end table */
1263 };
1264
1265 t_stat auto_config (char *name, int32 nctrl)
1266 {
1267 uint32 csr = IOPAGEBASE + AUTO_CSRBASE;
1268 uint32 vec = VEC_Q + AUTO_VECBASE;
1269 AUTO_CON *autp;
1270 DEVICE *dptr;
1271 DIB *dibp;
1272 uint32 j, k, vmask, amask;
1273
1274 if (autcon_enb == 0) return SCPE_OK; /* enabled? */
1275 if (name) { /* updating? */
1276 if (nctrl < 0) return SCPE_ARG;
1277 for (autp = auto_tab; autp->numc >= 0; autp++) {
1278 for (j = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {
1279 if (strcmp (name, autp->dnam[j]) == 0)
1280 autp->numc = nctrl;
1281 }
1282 }
1283 }
1284 for (autp = auto_tab; autp->numc >= 0; autp++) { /* loop thru table */
1285 if (autp->amod) { /* floating csr? */
1286 amask = autp->amod - 1;
1287 csr = (csr + amask) & ~amask; /* align csr */
1288 }
1289 for (j = k = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {
1290 dptr = find_dev (autp->dnam[j]); /* find ctrl */
1291 if ((dptr == NULL) || (dptr->flags & DEV_DIS) ||
1292 !(dptr->flags & DEV_FLTA)) continue; /* enabled, floating? */
1293 dibp = (DIB *) dptr->ctxt; /* get DIB */
1294 if (dibp == NULL) return SCPE_IERR; /* not there??? */
1295 if (autp->amod) { /* dyn csr needed? */
1296 if (autp->fixa[k]) /* fixed csr avail? */
1297 dibp->ba = autp->fixa[k]; /* use it */
1298 else { /* no fixed left */
1299 dibp->ba = csr; /* set CSR */
1300 csr += (autp->numc * autp->amod); /* next CSR */
1301 } /* end else */
1302 } /* end if dyn csr */
1303 if (autp->numv && autp->vmod) { /* dyn vec needed? */
1304 uint32 numv = abs (autp->numv); /* get num vec */
1305 if (autp->fixv[k]) { /* fixed vec avail? */
1306 if (autp->numv > 0)
1307 dibp->vec = autp->fixv[k]; /* use it */
1308 }
1309 else { /* no fixed left */
1310 vmask = autp->vmod - 1;
1311 vec = (vec + vmask) & ~vmask; /* align vector */
1312 if (autp->numv > 0)
1313 dibp->vec = vec; /* set vector */
1314 vec += (autp->numc * numv * 4);
1315 } /* end else */
1316 } /* end if dyn vec */
1317 k++; /* next instance */
1318 } /* end for j */
1319 if (autp->amod) csr = csr + 2; /* flt CSR? gap */
1320 } /* end for i */
1321 return SCPE_OK;
1322 }