First Commit of my working state
[simh.git] / VAX / vax780_mba.c
1 /* vax780_mba.c: VAX 11/780 Massbus 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 mba0, mba1 RH780 Massbus adapter
27
28 28-May-08 RMS Inlined physical memory routines
29 */
30
31 #include "vax_defs.h"
32
33 /* Massbus */
34
35 #define MBA_NMAPR 256 /* number of map reg */
36 #define MBA_V_RTYPE 10 /* nexus addr: reg type */
37 #define MBA_M_RTYPE 0x3
38 #define MBART_INT 0x0 /* internal */
39 #define MBART_EXT 0x1 /* external */
40 #define MBART_MAP 0x2 /* map */
41 #define MBA_V_INTOFS 2 /* int reg: reg ofs */
42 #define MBA_M_INTOFS 0xFF
43 #define MBA_V_DRV 7 /* ext reg: drive num */
44 #define MBA_M_DRV 0x7
45 #define MBA_V_DEVOFS 2 /* ext reg: reg ofs */
46 #define MBA_M_DEVOFS 0x1F
47 #define MBA_RTYPE(x) (((x) >> MBA_V_RTYPE) & MBA_M_RTYPE)
48 #define MBA_INTOFS(x) (((x) >> MBA_V_INTOFS) & MBA_M_INTOFS)
49 #define MBA_EXTDRV(x) (((x) >> MBA_V_DRV) & MBA_M_DRV)
50 #define MBA_EXTOFS(x) (((x) >> MBA_V_DEVOFS) & MBA_M_DEVOFS)
51
52 /* Massbus configuration register */
53
54 #define MBACNF_OF 0x0
55 #define MBACNF_ADPDN 0x00800000 /* adap pdn - ni */
56 #define MBACNF_ADPUP 0x00400000 /* adap pup - ni */
57 #define MBACNF_CODE 0x00000020
58 #define MBACNF_RD (SBI_FAULTS|MBACNF_W1C)
59 #define MBACNF_W1C 0x00C00000
60
61 /* Control register */
62
63 #define MBACR_OF 0x1
64 #define MBACR_MNT 0x00000008 /* maint */
65 #define MBACR_IE 0x00000004 /* int enable */
66 #define MBACR_ABORT 0x00000002 /* abort */
67 #define MBACR_INIT 0x00000001
68 #define MBACR_RD 0x0000000E
69 #define MBACR_WR 0x0000000E
70
71 /* Status register */
72
73 #define MBASR_OF 0x2
74 #define MBASR_DTBUSY 0x80000000 /* DT busy RO */
75 #define MBASR_NRCONF 0x40000000 /* no conf - ni W1C */
76 #define MBASR_CRD 0x20000000 /* CRD - ni W1C */
77 #define MBASR_CBH 0x00800000 /* CBHUNG - ni W1C */
78 #define MBASR_PGE 0x00080000 /* prog err - W1C int */
79 #define MBASR_NFD 0x00040000 /* nx drive - W1C int */
80 #define MBASR_MCPE 0x00020000 /* ctl perr - ni W1C int */
81 #define MBASR_ATA 0x00010000 /* attn - W1C int */
82 #define MBASR_SPE 0x00004000 /* silo perr - ni W1C int */
83 #define MBASR_DTCMP 0x00002000 /* xfr done - W1C int */
84 #define MBASR_DTABT 0x00001000 /* abort - W1C int */
85 #define MBASR_DLT 0x00000800 /* dat late - ni W1C abt */
86 #define MBASR_WCEU 0x00000400 /* wrchk upper - W1C abt */
87 #define MBASR_WCEL 0x00000200 /* wrchk lower - W1C abt */
88 #define MBASR_MXF 0x00000100 /* miss xfr - ni W1C abt */
89 #define MBASR_MBEXC 0x00000080 /* except - ni W1C abt */
90 #define MBASR_MBDPE 0x00000040 /* dat perr - ni W1C abt */
91 #define MBASR_MAPPE 0x00000020 /* map perr - ni W1C abt */
92 #define MBASR_INVM 0x00000010 /* inv map - W1C abt */
93 #define MBASR_ERCONF 0x00000008 /* err conf - ni W1C abt */
94 #define MBASR_RDS 0x00000004 /* RDS - ni W1C abt */
95 #define MBASR_ITMO 0x00000002 /* timeout - W1C abt */
96 #define MBASR_RTMO 0x00000001 /* rd timeout - W1C abt */
97 #define MBASR_RD 0xE08F7FFF
98 #define MBASR_W1C 0x608F7FFF
99 #define MBASR_ABORTS 0x00000FFF
100 #define MBASR_ERRORS 0x608E49FF
101 #define MBASR_INTR 0x000F7000
102
103 /* Virtual address register */
104
105 #define MBAVA_OF 0x3
106 #define MBAVA_RD 0x0001FFFF
107 #define MBAVA_WR (MBAVA_RD)
108
109 /* Byte count */
110
111 #define MBABC_OF 0x4
112 #define MBABC_WR 0x0000FFFF
113 #define MBABC_V_MBC 16 /* MB count */
114
115 /* Diagnostic register */
116
117 #define MBADR_OF 0x5
118 #define MBADR_RD 0xFFFFFFFF
119 #define MBADR_WR 0xFFC00000
120
121 /* Selected map entry - read only */
122
123 #define MBASMR_OF 0x6
124 #define MBASMR_RD (MBAMAP_RD)
125
126 /* Command register (SBI) - read only */
127
128 #define MBACMD_OF 0x7
129
130 /* External registers */
131
132 #define MBA_CS1 0x00 /* device CSR1 */
133 #define MBA_CS1_WR 0x3F /* writeable bits */
134 #define MBA_CS1_DT 0x28 /* >= for data xfr */
135
136 /* Map registers */
137
138 #define MBAMAP_VLD 0x80000000 /* valid */
139 #define MBAMAP_PAG 0x001FFFFF
140 #define MBAMAP_RD (MBAMAP_VLD | MBAMAP_PAG)
141 #define MBAMAP_WR (MBAMAP_RD)
142
143 /* Debug switches */
144
145 #define MBA_DEB_RRD 0x01 /* reg reads */
146 #define MBA_DEB_RWR 0x02 /* reg writes */
147 #define MBA_DEB_MRD 0x04 /* map reads */
148 #define MBA_DEB_MWR 0x08 /* map writes */
149 #define MBA_DEB_XFR 0x10 /* transfers */
150 #define MBA_DEB_ERR 0x20 /* errors */
151
152 uint32 mba_cnf[MBA_NUM]; /* config reg */
153 uint32 mba_cr[MBA_NUM]; /* control reg */
154 uint32 mba_sr[MBA_NUM]; /* status reg */
155 uint32 mba_va[MBA_NUM]; /* virt addr */
156 uint32 mba_bc[MBA_NUM]; /* byte count */
157 uint32 mba_dr[MBA_NUM]; /* diag reg */
158 uint32 mba_smr[MBA_NUM]; /* sel map reg */
159 uint32 mba_map[MBA_NUM][MBA_NMAPR]; /* map */
160
161 extern uint32 nexus_req[NEXUS_HLVL];
162 extern UNIT cpu_unit;
163 extern FILE *sim_log;
164 extern FILE *sim_deb;
165 extern int32 sim_switches;
166
167 t_stat mba_reset (DEVICE *dptr);
168 t_stat mba_rdreg (int32 *val, int32 pa, int32 mode);
169 t_stat mba_wrreg (int32 val, int32 pa, int32 lnt);
170 t_bool mba_map_addr (uint32 va, uint32 *ma, uint32 mb);
171 void mba_set_int (uint32 mb);
172 void mba_clr_int (uint32 mb);
173 void mba_upd_sr (uint32 set, uint32 clr, uint32 mb);
174 DIB mba0_dib, mba1_dib;
175
176 /* Massbus register dispatches */
177
178 static t_stat (*mbregR[MBA_NUM])(int32 *dat, int32 ad, int32 md);
179 static t_stat (*mbregW[MBA_NUM])(int32 dat, int32 ad, int32 md);
180 static int32 (*mbabort[MBA_NUM])(void);
181
182 /* Massbus adapter data structures
183
184 mba_dev MBA device descriptors
185 mbax_unit MBA unit
186 mbax_reg MBA register list
187 */
188
189 DIB mba0_dib = { TR_MBA0, 0, &mba_rdreg, &mba_wrreg, 0, NVCL (MBA0) };
190
191 UNIT mba0_unit = { UDATA (NULL, 0, 0) };
192
193 REG mba0_reg[] = {
194 { HRDATA (CNFR, mba_cnf[0], 32) },
195 { HRDATA (CR, mba_cr[0], 4) },
196 { HRDATA (SR, mba_sr[0], 32) },
197 { HRDATA (VA, mba_va[0], 17) },
198 { HRDATA (BC, mba_bc[0], 16) },
199 { HRDATA (DR, mba_dr[0], 32) },
200 { HRDATA (SMR, mba_dr[0], 32) },
201 { BRDATA (MAP, mba_map[0], 16, 32, MBA_NMAPR) },
202 { FLDATA (NEXINT, nexus_req[IPL_MBA0], TR_MBA0) },
203 { NULL }
204 };
205
206 MTAB mba0_mod[] = {
207 { MTAB_XTD|MTAB_VDV, TR_MBA0, "NEXUS", NULL,
208 NULL, &show_nexus },
209 { 0 }
210 };
211
212 DIB mba1_dib = { TR_MBA1, 0, &mba_rdreg, &mba_wrreg, 0, NVCL (MBA1) };
213
214 UNIT mba1_unit = { UDATA (NULL, 0, 0) };
215
216 MTAB mba1_mod[] = {
217 { MTAB_XTD|MTAB_VDV, TR_MBA1, "NEXUS", NULL,
218 NULL, &show_nexus },
219 { 0 }
220 };
221
222 REG mba1_reg[] = {
223 { HRDATA (CNFR, mba_cnf[1], 32) },
224 { HRDATA (CR, mba_cr[1], 4) },
225 { HRDATA (SR, mba_sr[1], 32) },
226 { HRDATA (VA, mba_va[1], 17) },
227 { HRDATA (BC, mba_bc[1], 16) },
228 { HRDATA (DR, mba_dr[1], 32) },
229 { HRDATA (SMR, mba_dr[1], 32) },
230 { BRDATA (MAP, mba_map[1], 16, 32, MBA_NMAPR) },
231 { FLDATA (NEXINT, nexus_req[IPL_MBA1], TR_MBA1) },
232 { NULL }
233 };
234
235 DEBTAB mba_deb[] = {
236 { "REGREAD", MBA_DEB_RRD },
237 { "REGWRITE", MBA_DEB_RWR },
238 { "MAPREAD", MBA_DEB_MRD },
239 { "MAPWRITE", MBA_DEB_MWR },
240 { "XFER", MBA_DEB_XFR },
241 { "ERROR", MBA_DEB_ERR },
242 { NULL, 0 }
243 };
244
245 DEVICE mba_dev[] = {
246 {
247 "MBA0", &mba0_unit, mba0_reg, mba0_mod,
248 1, 0, 0, 0, 0, 0,
249 NULL, NULL, &mba_reset,
250 NULL, NULL, NULL,
251 &mba0_dib, DEV_NEXUS | DEV_DEBUG, 0,
252 mba_deb, 0, 0
253 },
254 {
255 "MBA1", &mba1_unit, mba1_reg, mba1_mod,
256 1, 0, 0, 0, 0, 0,
257 NULL, NULL, &mba_reset,
258 NULL, NULL, NULL,
259 &mba1_dib, DEV_NEXUS | DEV_DEBUG, 0,
260 mba_deb, 0, 0
261 }
262 };
263
264 /* Read Massbus adapter register */
265
266 t_stat mba_rdreg (int32 *val, int32 pa, int32 lnt)
267 {
268 int32 mb, ofs, drv, rtype;
269 uint32 t;
270 t_stat r;
271
272 mb = NEXUS_GETNEX (pa) - TR_MBA0; /* get MBA */
273 if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */
274 printf (">>MBA%d: invalid adapter read mask, pa = %X, lnt = %d\r\n", mb, pa, lnt);
275 sbi_set_errcnf (); /* err confirmation */
276 return SCPE_OK;
277 }
278 if (mb >= MBA_NUM) return SCPE_NXM; /* valid? */
279 rtype = MBA_RTYPE (pa); /* get reg type */
280
281 switch (rtype) { /* case on type */
282
283 case MBART_INT: /* internal */
284 ofs = MBA_INTOFS (pa); /* check range */
285 switch (ofs) {
286
287 case MBACNF_OF: /* CNF */
288 *val = (mba_cnf[mb] & MBACNF_RD) | MBACNF_CODE;
289 break;
290
291 case MBACR_OF: /* CR */
292 *val = mba_cr[mb] & MBACR_RD;
293 break;
294
295 case MBASR_OF: /* SR */
296 *val = mba_sr[mb] & MBASR_RD;
297 break;
298
299 case MBAVA_OF: /* VA */
300 *val = mba_va[mb] & MBAVA_RD;
301 break;
302
303 case MBABC_OF: /* BC */
304 t = mba_bc[mb] & MBABC_WR;
305 *val = (t << MBABC_V_MBC) | t;
306 break;
307
308 case MBADR_OF: /* DR */
309 *val = mba_dr[mb] & MBADR_RD;
310 break;
311
312 case MBASMR_OF: /* SMR */
313 *val = mba_smr[mb] & MBASMR_RD;
314 break;
315
316 case MBACMD_OF: /* CMD */
317 *val = 0;
318 break;
319
320 default:
321 return SCPE_NXM;
322 }
323 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RRD))
324 fprintf (sim_deb, ">>MBA%d: int reg %d read, value = %X\n", mb, ofs, *val);
325 break;
326
327 case MBART_EXT: /* external */
328 if (!mbregR[mb]) return SCPE_NXM; /* device there? */
329 drv = MBA_EXTDRV (pa); /* get dev num */
330 ofs = MBA_EXTOFS (pa); /* get reg offs */
331 r = mbregR[mb] (val, ofs, drv); /* call device */
332 if (r == MBE_NXD) mba_upd_sr (MBASR_NFD, 0, mb);/* nx drive? */
333 else if (r == MBE_NXR) return SCPE_NXM; /* nx reg? */
334 *val |= (mba_sr[mb] & ~WMASK); /* upper 16b from SR */
335 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RRD))
336 fprintf (sim_deb, ">>MBA%d: drv %d ext reg %d read, value = %X\n", mb, drv, ofs, *val);
337 break;
338
339 case MBART_MAP: /* map */
340 ofs = MBA_INTOFS (pa);
341 *val = mba_map[mb][ofs] & MBAMAP_RD;
342 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_MRD))
343 fprintf (sim_deb, ">>MBA%d: map %d read, value = %X\n", mb, ofs, *val);
344 break;
345
346 default:
347 return SCPE_NXM;
348 }
349
350 return SCPE_OK;
351 }
352
353 /* Write Massbus adapter register */
354
355 t_stat mba_wrreg (int32 val, int32 pa, int32 lnt)
356 {
357 int32 mb, ofs, drv, rtype;
358 t_stat r;
359 t_bool cs1dt;
360
361 mb = NEXUS_GETNEX (pa) - TR_MBA0; /* get MBA */
362 if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */
363 printf (">>MBA%d: invalid adapter write mask, pa = %X, lnt = %d\r\n", mb, pa, lnt);
364 sbi_set_errcnf (); /* err confirmation */
365 return SCPE_OK;
366 }
367 if (mb >= MBA_NUM) return SCPE_NXM; /* valid? */
368 rtype = MBA_RTYPE (pa); /* get reg type */
369
370 switch (rtype) { /* case on type */
371
372 case MBART_INT: /* internal */
373 ofs = MBA_INTOFS (pa); /* check range */
374 switch (ofs) {
375
376 case MBACNF_OF: /* CNF */
377 mba_cnf[mb] &= ~(val & MBACNF_W1C);
378 break;
379
380 case MBACR_OF: /* CR */
381 if (val & MBACR_INIT) /* init? */
382 mba_reset (&mba_dev[mb]); /* reset MBA */
383 if ((val & MBACR_ABORT) &&
384 (mba_sr[mb] & MBASR_DTBUSY)) {
385 if (mbabort[mb]) mbabort[mb] (); /* abort? */
386 mba_upd_sr (MBASR_DTABT, 0, mb);
387 }
388 if ((val & MBACR_MNT) &&
389 (mba_sr[mb] & MBASR_DTBUSY)) {
390 mba_upd_sr (MBASR_PGE, 0, mb); /* mnt & xfer? */
391 val = val & ~MBACR_MNT;
392 }
393 if ((val & MBACR_IE) == 0) mba_clr_int (mb);
394 mba_cr[mb] = (mba_cr[mb] & ~MBACR_WR) |
395 (val & MBACR_WR);
396 break;
397
398 case MBASR_OF: /* SR */
399 mba_sr[mb] = mba_sr[mb] & ~(val & MBASR_W1C);
400 break;
401
402 case MBAVA_OF: /* VA */
403 if (mba_sr[mb] & MBASR_DTBUSY) /* err if xfr */
404 mba_upd_sr (MBASR_PGE, 0, mb);
405 else mba_va[mb] = val & MBAVA_WR;
406 break;
407
408 case MBABC_OF: /* BC */
409 if (mba_sr[mb] & MBASR_DTBUSY) /* err if xfr */
410 mba_upd_sr (MBASR_PGE, 0, mb);
411 else mba_bc[mb] = val & MBABC_WR;
412 break;
413
414 case MBADR_OF: /* DR */
415 mba_dr[mb] = (mba_dr[mb] & ~MBADR_WR) |
416 (val & MBADR_WR);
417 break;
418
419 default:
420 return SCPE_NXM;
421 }
422 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RWR))
423 fprintf (sim_deb, ">>MBA%d: int reg %d write, value = %X\n", mb, ofs, val);
424 break;
425
426 case MBART_EXT: /* external */
427 if (!mbregW[mb]) return SCPE_NXM; /* device there? */
428 drv = MBA_EXTDRV (pa); /* get dev num */
429 ofs = MBA_EXTOFS (pa); /* get reg offs */
430 cs1dt = (ofs == MBA_CS1) && (val & CSR_GO) && /* starting xfr? */
431 ((val & MBA_CS1_WR) >= MBA_CS1_DT);
432 if (cs1dt && (mba_sr[mb] & MBASR_DTBUSY)) { /* xfr while busy? */
433 mba_upd_sr (MBASR_PGE, 0, mb); /* prog error */
434 break;
435 }
436 r = mbregW[mb] (val & WMASK, ofs, drv); /* write dev reg */
437 if (r == MBE_NXD) mba_upd_sr (MBASR_NFD, 0, mb);/* nx drive? */
438 else if (r == MBE_NXR) return SCPE_NXM; /* nx reg? */
439 if (cs1dt && (r == SCPE_OK)) /* did dt start? */
440 mba_sr[mb] = (mba_sr[mb] | MBASR_DTBUSY) & ~MBASR_W1C;
441 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RWR))
442 fprintf (sim_deb, ">>MBA%d: drv %d ext reg %d write, value = %X\n", mb, drv, ofs, val);
443 break;
444
445 case MBART_MAP: /* map */
446 ofs = MBA_INTOFS (pa);
447 mba_map[mb][ofs] = val & MBAMAP_WR;
448 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_MWR))
449 fprintf (sim_deb, ">>MBA%d: map %d write, value = %X\n", mb, ofs, val);
450 break;
451
452 default:
453 return SCPE_NXM;
454 }
455
456 return SCPE_OK;
457 }
458
459 /* Massbus I/O routine
460
461 mb_rdbufW - fetch word buffer from memory
462 mb_wrbufW - store word buffer into memory
463 mb_chbufW - compare word buffer with memory
464
465 Returns number of bytes successfully transferred/checked
466 */
467
468 int32 mba_rdbufW (uint32 mb, int32 bc, uint16 *buf)
469 {
470 int32 i, j, ba, mbc, pbc;
471 uint32 pa, dat;
472
473 if (mb >= MBA_NUM) return 0; /* valid MBA? */
474 ba = mba_va[mb]; /* get virt addr */
475 mbc = (MBABC_WR + 1) - mba_bc[mb]; /* get Mbus bc */
476 if (bc > mbc) bc = mbc; /* use smaller */
477 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
478 if (!mba_map_addr (ba + i, &pa, mb)) break; /* page inv? */
479 if (!ADDR_IS_MEM (pa)) { /* NXM? */
480 mba_upd_sr (MBASR_RTMO, 0, mb);
481 break;
482 }
483 pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
484 if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
485 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_XFR))
486 fprintf (sim_deb, ">>MBA%d: read, pa = %X, bc = %X\n", mb, pa, pbc);
487 if ((pa | pbc) & 1) { /* aligned word? */
488 for (j = 0; j < pbc; pa++, j++) { /* no, bytes */
489 if ((i + j) & 1) { /* odd byte? */
490 *buf = (*buf & BMASK) | (ReadB (pa) << 8);
491 buf++;
492 }
493 else *buf = (*buf & ~BMASK) | ReadB (pa);
494 }
495 }
496 else if ((pa | pbc) & 3) { /* aligned LW? */
497 for (j = 0; j < pbc; pa = pa + 2, j = j + 2) { /* no, words */
498 *buf++ = ReadW (pa); /* get word */
499 }
500 }
501 else { /* yes, do by LW */
502 for (j = 0; j < pbc; pa = pa + 4, j = j + 4) {
503 dat = ReadL (pa); /* get lw */
504 *buf++ = dat & WMASK; /* low 16b */
505 *buf++ = (dat >> 16) & WMASK; /* high 16b */
506 }
507 }
508 }
509 mba_bc[mb] = (mba_bc[mb] + i) & MBABC_WR;
510 mba_va[mb] = (mba_va[mb] + i) & MBAVA_WR;
511 return i;
512 }
513
514 int32 mba_wrbufW (uint32 mb, int32 bc, uint16 *buf)
515 {
516 int32 i, j, ba, mbc, pbc;
517 uint32 pa, dat;
518
519 if (mb >= MBA_NUM) return 0; /* valid MBA? */
520 ba = mba_va[mb]; /* get virt addr */
521 mbc = (MBABC_WR + 1) - mba_bc[mb]; /* get Mbus bc */
522 if (bc > mbc) bc = mbc; /* use smaller */
523 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
524 if (!mba_map_addr (ba + i, &pa, mb)) break; /* page inv? */
525 if (!ADDR_IS_MEM (pa)) { /* NXM? */
526 mba_upd_sr (MBASR_RTMO, 0, mb);
527 break;
528 }
529 pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
530 if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
531 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_XFR))
532 fprintf (sim_deb, ">>MBA%d: write, pa = %X, bc = %X\n", mb, pa, pbc);
533 if ((pa | pbc) & 1) { /* aligned word? */
534 for (j = 0; j < pbc; pa++, j++) { /* no, bytes */
535 if ((i + j) & 1) {
536 WriteB (pa, (*buf >> 8) & BMASK);
537 buf++;
538 }
539 else WriteB (pa, *buf & BMASK);
540 }
541 }
542 else if ((pa | pbc) & 3) { /* aligned LW? */
543 for (j = 0; j < pbc; pa = pa + 2, j = j + 2) { /* no, words */
544 WriteW (pa, *buf); /* write word */
545 buf++;
546 }
547 }
548 else { /* yes, do by LW */
549 for (j = 0; j < pbc; pa = pa + 4, j = j + 4) {
550 dat = (uint32) *buf++; /* get low 16b */
551 dat = dat | (((uint32) *buf++) << 16); /* merge hi 16b */
552 WriteL (pa, dat); /* store LW */
553 }
554 }
555 }
556 mba_bc[mb] = (mba_bc[mb] + i) & MBABC_WR;
557 mba_va[mb] = (mba_va[mb] + i) & MBAVA_WR;
558 return i;
559 }
560
561 int32 mba_chbufW (uint32 mb, int32 bc, uint16 *buf)
562 {
563 int32 i, j, ba, mbc, pbc;
564 uint32 pa, dat, cmp;
565
566 if (mb >= MBA_NUM) return 0; /* valid MBA? */
567 ba = mba_va[mb]; /* get virt addr */
568 mbc = (MBABC_WR + 1) - mba_bc[mb]; /* get Mbus bc */
569 if (bc > mbc) bc = mbc; /* use smaller */
570 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
571 if (!mba_map_addr (ba + i, &pa, mb)) break; /* page inv? */
572 if (!ADDR_IS_MEM (pa)) { /* NXM? */
573 mba_upd_sr (MBASR_RTMO, 0, mb);
574 break;
575 }
576 pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
577 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_XFR))
578 fprintf (sim_deb, ">>MBA%d: check, pa = %X, bc = %X\n", mb, pa, pbc);
579 if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
580 for (j = 0; j < pbc; j++, pa++) { /* byte by byte */
581 cmp = ReadB (pa);
582 if ((i + j) & 1) dat = (*buf++ >> 8) & BMASK;
583 else dat = *buf & BMASK;
584 if (cmp != dat) {
585 mba_upd_sr ((j & 1)? MBASR_WCEU: MBASR_WCEL, 0, mb);
586 break;
587 } /* end if */
588 } /* end for j */
589 } /* end for i */
590 mba_bc[mb] = (mba_bc[mb] + i) & MBABC_WR;
591 mba_va[mb] = (mba_va[mb] + i) & MBAVA_WR;
592 return i;
593 }
594
595 /* Map an address via the translation map */
596
597 t_bool mba_map_addr (uint32 va, uint32 *ma, uint32 mb)
598 {
599 uint32 vblk = (va >> VA_V_VPN); /* map index */
600 uint32 mmap = mba_map[mb][vblk]; /* get map */
601
602 mba_smr[mb] = mmap; /* save map reg */
603 if (mmap & MBAMAP_VLD) { /* valid? */
604 *ma = ((mmap & MBAMAP_PAG) << VA_V_VPN) + VA_GETOFF (va);
605 return 1; /* legit addr */
606 }
607 mba_upd_sr (MBASR_INVM, 0, mb); /* invalid map */
608 return 0;
609 }
610
611 /* Device access, status, and interrupt routines */
612
613 void mba_set_don (uint32 mb)
614 {
615 mba_upd_sr (MBASR_DTCMP, 0, mb);
616 return;
617 }
618
619 void mba_upd_ata (uint32 mb, uint32 val)
620 {
621 if (val) mba_upd_sr (MBASR_ATA, 0, mb);
622 else mba_upd_sr (0, MBASR_ATA, mb);
623 return;
624 }
625
626 void mba_set_exc (uint32 mb)
627 {
628 mba_upd_sr (MBASR_MBEXC, 0, mb);
629 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_ERR))
630 fprintf (sim_deb, ">>MBA%d: EXC write\n", mb);
631 return;
632 }
633
634 int32 mba_get_bc (uint32 mb)
635 {
636 if (mb >= MBA_NUM) return 0;
637 return (MBABC_WR + 1) - mba_bc[mb];
638 }
639
640 void mba_set_int (uint32 mb)
641 {
642 DIB *dibp;
643
644 if (mb >= MBA_NUM) return;
645 dibp = (DIB *) mba_dev[mb].ctxt;
646 if (dibp)
647 nexus_req[dibp->vloc >> 5] |= (1u << (dibp->vloc & 0x1F));
648 return;
649 }
650
651 void mba_clr_int (uint32 mb)
652 {
653 DIB *dibp;
654
655 if (mb >= MBA_NUM) return;
656 dibp = (DIB *) mba_dev[mb].ctxt;
657 if (dibp)
658 nexus_req[dibp->vloc >> 5] &= ~(1u << (dibp->vloc & 0x1F));
659 return;
660 }
661
662 void mba_upd_sr (uint32 set, uint32 clr, uint32 mb)
663 {
664 if (mb >= MBA_NUM) return;
665 if (set & MBASR_ABORTS) set |= (MBASR_DTCMP|MBASR_DTABT);
666 if (set & (MBASR_DTCMP|MBASR_DTABT)) mba_sr[mb] &= ~MBASR_DTBUSY;
667 mba_sr[mb] = (mba_sr[mb] | set) & ~clr;
668 if ((set & MBASR_INTR) && (mba_cr[mb] & MBACR_IE))
669 mba_set_int (mb);
670 if ((set & MBASR_ERRORS) && (DEBUG_PRI (mba_dev[mb], MBA_DEB_ERR)))
671 fprintf (sim_deb, ">>MBA%d: CS error = %X\n", mb, mba_sr[mb]);
672 return;
673 }
674
675 /* Reset Massbus adapter */
676
677 t_stat mba_reset (DEVICE *dptr)
678 {
679 int32 i, mb;
680 DIB *dibp;
681
682 dibp = (DIB *) dptr->ctxt;
683 if (dibp == NULL) return SCPE_IERR;
684 mb = dibp->ba - TR_MBA0;
685 if ((mb < 0) || (mb >= MBA_NUM)) return SCPE_IERR;
686 mba_cnf[mb] = 0;
687 mba_cr[mb] &= MBACR_MNT;
688 mba_sr[mb] = 0;
689 mba_bc[mb] = 0;
690 mba_va[mb] = 0;
691 mba_dr[mb] = 0;
692 mba_smr[mb] = 0;
693 if (sim_switches & SWMASK ('P')) {
694 for (i = 0; i < MBA_NMAPR; i++) mba_map[mb][i] = 0;
695 }
696 if (mbabort[mb]) mbabort[mb] (); /* reset device */
697 return SCPE_OK;
698 }
699
700 /* Show Massbus adapter number */
701
702 t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc)
703 {
704 DEVICE *dptr = find_dev_from_unit (uptr);
705 DIB *dibp;
706
707 if (dptr == NULL) return SCPE_IERR;
708 dibp = (DIB *) dptr->ctxt;
709 if (dibp == NULL) return SCPE_IERR;
710 fprintf (st, "Massbus adapter %d", dibp->ba);
711 return SCPE_OK;
712 }
713
714 /* Enable/disable Massbus adapter */
715
716 void mba_set_enbdis (uint32 mb, t_bool dis)
717 {
718 if (mb >= MBA_NUM) return; /* valid MBA? */
719 if (dis) mba_dev[mb].flags |= DEV_DIS;
720 else mba_dev[mb].flags &= ~DEV_DIS;
721 return;
722 }
723
724 /* Init Mbus tables */
725
726 void init_mbus_tab (void)
727 {
728 uint32 i;
729
730 for (i = 0; i < MBA_NUM; i++) {
731 mbregR[i] = NULL;
732 mbregW[i] = NULL;
733 mbabort[i] = NULL;
734 }
735 return;
736 }
737
738 /* Build dispatch tables */
739
740 t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp)
741 {
742 uint32 idx;
743
744 if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */
745 idx = dibp->ba; /* Mbus # */
746 if (idx >= MBA_NUM) return SCPE_STOP;
747 if ((mbregR[idx] && dibp->rd && /* conflict? */
748 (mbregR[idx] != dibp->rd)) ||
749 (mbregW[idx] && dibp->wr &&
750 (mbregW[idx] != dibp->wr)) ||
751 (mbabort[idx] && dibp->ack[0] &&
752 (mbabort[idx] != dibp->ack[0]))) {
753 printf ("Massbus %s assignment conflict at %d\n",
754 sim_dname (dptr), dibp->ba);
755 if (sim_log) fprintf (sim_log,
756 "Massbus %s assignment conflict at %d\n",
757 sim_dname (dptr), dibp->ba);
758 return SCPE_STOP;
759 }
760 if (dibp->rd) mbregR[idx] = dibp->rd; /* set rd dispatch */
761 if (dibp->wr) mbregW[idx] = dibp->wr; /* set wr dispatch */
762 if (dibp->ack[0]) mbabort[idx] = dibp->ack[0]; /* set abort dispatch */
763 return SCPE_OK;
764 }
765