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
mba_rdreg(int32 * val,int32 pa,int32 lnt)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) /* valid? */
279 return SCPE_NXM;
280 rtype = MBA_RTYPE (pa); /* get reg type */
281
282 switch (rtype) { /* case on type */
283
284 case MBART_INT: /* internal */
285 ofs = MBA_INTOFS (pa); /* check range */
286 switch (ofs) {
287
288 case MBACNF_OF: /* CNF */
289 *val = (mba_cnf[mb] & MBACNF_RD) | MBACNF_CODE;
290 break;
291
292 case MBACR_OF: /* CR */
293 *val = mba_cr[mb] & MBACR_RD;
294 break;
295
296 case MBASR_OF: /* SR */
297 *val = mba_sr[mb] & MBASR_RD;
298 break;
299
300 case MBAVA_OF: /* VA */
301 *val = mba_va[mb] & MBAVA_RD;
302 break;
303
304 case MBABC_OF: /* BC */
305 t = mba_bc[mb] & MBABC_WR;
306 *val = (t << MBABC_V_MBC) | t;
307 break;
308
309 case MBADR_OF: /* DR */
310 *val = mba_dr[mb] & MBADR_RD;
311 break;
312
313 case MBASMR_OF: /* SMR */
314 *val = mba_smr[mb] & MBASMR_RD;
315 break;
316
317 case MBACMD_OF: /* CMD */
318 *val = 0;
319 break;
320
321 default:
322 return SCPE_NXM;
323 }
324 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RRD))
325 fprintf (sim_deb, ">>MBA%d: int reg %d read, value = %X\n", mb, ofs, *val);
326 break;
327
328 case MBART_EXT: /* external */
329 if (!mbregR[mb]) /* device there? */
330 return SCPE_NXM;
331 drv = MBA_EXTDRV (pa); /* get dev num */
332 ofs = MBA_EXTOFS (pa); /* get reg offs */
333 r = mbregR[mb] (val, ofs, drv); /* call device */
334 if (r == MBE_NXD) /* nx drive? */
335 mba_upd_sr (MBASR_NFD, 0, mb);
336 else if (r == MBE_NXR) /* nx reg? */
337 return SCPE_NXM;
338 *val |= (mba_sr[mb] & ~WMASK); /* upper 16b from SR */
339 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RRD))
340 fprintf (sim_deb, ">>MBA%d: drv %d ext reg %d read, value = %X\n", mb, drv, ofs, *val);
341 break;
342
343 case MBART_MAP: /* map */
344 ofs = MBA_INTOFS (pa);
345 *val = mba_map[mb][ofs] & MBAMAP_RD;
346 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_MRD))
347 fprintf (sim_deb, ">>MBA%d: map %d read, value = %X\n", mb, ofs, *val);
348 break;
349
350 default:
351 return SCPE_NXM;
352 }
353
354 return SCPE_OK;
355 }
356
357 /* Write Massbus adapter register */
358
mba_wrreg(int32 val,int32 pa,int32 lnt)359 t_stat mba_wrreg (int32 val, int32 pa, int32 lnt)
360 {
361 int32 mb, ofs, drv, rtype;
362 t_stat r;
363 t_bool cs1dt;
364
365 mb = NEXUS_GETNEX (pa) - TR_MBA0; /* get MBA */
366 if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */
367 printf (">>MBA%d: invalid adapter write mask, pa = %X, lnt = %d\r\n", mb, pa, lnt);
368 sbi_set_errcnf (); /* err confirmation */
369 return SCPE_OK;
370 }
371 if (mb >= MBA_NUM) /* valid? */
372 return SCPE_NXM;
373 rtype = MBA_RTYPE (pa); /* get reg type */
374
375 switch (rtype) { /* case on type */
376
377 case MBART_INT: /* internal */
378 ofs = MBA_INTOFS (pa); /* check range */
379 switch (ofs) {
380
381 case MBACNF_OF: /* CNF */
382 mba_cnf[mb] &= ~(val & MBACNF_W1C);
383 break;
384
385 case MBACR_OF: /* CR */
386 if (val & MBACR_INIT) /* init? */
387 mba_reset (&mba_dev[mb]); /* reset MBA */
388 if ((val & MBACR_ABORT) &&
389 (mba_sr[mb] & MBASR_DTBUSY)) {
390 if (mbabort[mb]) /* abort? */
391 mbabort[mb] ();
392 mba_upd_sr (MBASR_DTABT, 0, mb);
393 }
394 if ((val & MBACR_MNT) &&
395 (mba_sr[mb] & MBASR_DTBUSY)) {
396 mba_upd_sr (MBASR_PGE, 0, mb); /* mnt & xfer? */
397 val = val & ~MBACR_MNT;
398 }
399 if ((val & MBACR_IE) == 0)
400 mba_clr_int (mb);
401 mba_cr[mb] = (mba_cr[mb] & ~MBACR_WR) |
402 (val & MBACR_WR);
403 break;
404
405 case MBASR_OF: /* SR */
406 mba_sr[mb] = mba_sr[mb] & ~(val & MBASR_W1C);
407 break;
408
409 case MBAVA_OF: /* VA */
410 if (mba_sr[mb] & MBASR_DTBUSY) /* err if xfr */
411 mba_upd_sr (MBASR_PGE, 0, mb);
412 else mba_va[mb] = val & MBAVA_WR;
413 break;
414
415 case MBABC_OF: /* BC */
416 if (mba_sr[mb] & MBASR_DTBUSY) /* err if xfr */
417 mba_upd_sr (MBASR_PGE, 0, mb);
418 else mba_bc[mb] = val & MBABC_WR;
419 break;
420
421 case MBADR_OF: /* DR */
422 mba_dr[mb] = (mba_dr[mb] & ~MBADR_WR) |
423 (val & MBADR_WR);
424 break;
425
426 default:
427 return SCPE_NXM;
428 }
429 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RWR))
430 fprintf (sim_deb, ">>MBA%d: int reg %d write, value = %X\n", mb, ofs, val);
431 break;
432
433 case MBART_EXT: /* external */
434 if (!mbregW[mb]) /* device there? */
435 return SCPE_NXM;
436 drv = MBA_EXTDRV (pa); /* get dev num */
437 ofs = MBA_EXTOFS (pa); /* get reg offs */
438 cs1dt = (ofs == MBA_CS1) && (val & CSR_GO) && /* starting xfr? */
439 ((val & MBA_CS1_WR) >= MBA_CS1_DT);
440 if (cs1dt && (mba_sr[mb] & MBASR_DTBUSY)) { /* xfr while busy? */
441 mba_upd_sr (MBASR_PGE, 0, mb); /* prog error */
442 break;
443 }
444 r = mbregW[mb] (val & WMASK, ofs, drv); /* write dev reg */
445 if (r == MBE_NXD) /* nx drive? */
446 mba_upd_sr (MBASR_NFD, 0, mb);
447 else if (r == MBE_NXR) /* nx reg? */
448 return SCPE_NXM;
449 if (cs1dt && (r == SCPE_OK)) /* did dt start? */
450 mba_sr[mb] = (mba_sr[mb] | MBASR_DTBUSY) & ~MBASR_W1C;
451 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_RWR))
452 fprintf (sim_deb, ">>MBA%d: drv %d ext reg %d write, value = %X\n", mb, drv, ofs, val);
453 break;
454
455 case MBART_MAP: /* map */
456 ofs = MBA_INTOFS (pa);
457 mba_map[mb][ofs] = val & MBAMAP_WR;
458 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_MWR))
459 fprintf (sim_deb, ">>MBA%d: map %d write, value = %X\n", mb, ofs, val);
460 break;
461
462 default:
463 return SCPE_NXM;
464 }
465
466 return SCPE_OK;
467 }
468
469 /* Massbus I/O routine
470
471 mb_rdbufW - fetch word buffer from memory
472 mb_wrbufW - store word buffer into memory
473 mb_chbufW - compare word buffer with memory
474
475 Returns number of bytes successfully transferred/checked
476 */
477
mba_rdbufW(uint32 mb,int32 bc,uint16 * buf)478 int32 mba_rdbufW (uint32 mb, int32 bc, uint16 *buf)
479 {
480 int32 i, j, ba, mbc, pbc;
481 uint32 pa, dat;
482
483 if (mb >= MBA_NUM) /* valid MBA? */
484 return 0;
485 ba = mba_va[mb]; /* get virt addr */
486 mbc = (MBABC_WR + 1) - mba_bc[mb]; /* get Mbus bc */
487 if (bc > mbc) /* use smaller */
488 bc = mbc;
489 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
490 if (!mba_map_addr (ba + i, &pa, mb)) /* page inv? */
491 break;
492 if (!ADDR_IS_MEM (pa)) { /* NXM? */
493 mba_upd_sr (MBASR_RTMO, 0, mb);
494 break;
495 }
496 pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
497 if (pbc > (bc - i)) /* limit to rem xfr */
498 pbc = bc - i;
499 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_XFR))
500 fprintf (sim_deb, ">>MBA%d: read, pa = %X, bc = %X\n", mb, pa, pbc);
501 if ((pa | pbc) & 1) { /* aligned word? */
502 for (j = 0; j < pbc; pa++, j++) { /* no, bytes */
503 if ((i + j) & 1) { /* odd byte? */
504 *buf = (*buf & BMASK) | (ReadB (pa) << 8);
505 buf++;
506 }
507 else *buf = (*buf & ~BMASK) | ReadB (pa);
508 }
509 }
510 else if ((pa | pbc) & 3) { /* aligned LW? */
511 for (j = 0; j < pbc; pa = pa + 2, j = j + 2) { /* no, words */
512 *buf++ = ReadW (pa); /* get word */
513 }
514 }
515 else { /* yes, do by LW */
516 for (j = 0; j < pbc; pa = pa + 4, j = j + 4) {
517 dat = ReadL (pa); /* get lw */
518 *buf++ = dat & WMASK; /* low 16b */
519 *buf++ = (dat >> 16) & WMASK; /* high 16b */
520 }
521 }
522 }
523 mba_bc[mb] = (mba_bc[mb] + i) & MBABC_WR;
524 mba_va[mb] = (mba_va[mb] + i) & MBAVA_WR;
525 return i;
526 }
527
mba_wrbufW(uint32 mb,int32 bc,uint16 * buf)528 int32 mba_wrbufW (uint32 mb, int32 bc, uint16 *buf)
529 {
530 int32 i, j, ba, mbc, pbc;
531 uint32 pa, dat;
532
533 if (mb >= MBA_NUM) /* valid MBA? */
534 return 0;
535 ba = mba_va[mb]; /* get virt addr */
536 mbc = (MBABC_WR + 1) - mba_bc[mb]; /* get Mbus bc */
537 if (bc > mbc) /* use smaller */
538 bc = mbc;
539 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
540 if (!mba_map_addr (ba + i, &pa, mb)) /* page inv? */
541 break;
542 if (!ADDR_IS_MEM (pa)) { /* NXM? */
543 mba_upd_sr (MBASR_RTMO, 0, mb);
544 break;
545 }
546 pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
547 if (pbc > (bc - i)) /* limit to rem xfr */
548 pbc = bc - i;
549 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_XFR))
550 fprintf (sim_deb, ">>MBA%d: write, pa = %X, bc = %X\n", mb, pa, pbc);
551 if ((pa | pbc) & 1) { /* aligned word? */
552 for (j = 0; j < pbc; pa++, j++) { /* no, bytes */
553 if ((i + j) & 1) {
554 WriteB (pa, (*buf >> 8) & BMASK);
555 buf++;
556 }
557 else WriteB (pa, *buf & BMASK);
558 }
559 }
560 else if ((pa | pbc) & 3) { /* aligned LW? */
561 for (j = 0; j < pbc; pa = pa + 2, j = j + 2) { /* no, words */
562 WriteW (pa, *buf); /* write word */
563 buf++;
564 }
565 }
566 else { /* yes, do by LW */
567 for (j = 0; j < pbc; pa = pa + 4, j = j + 4) {
568 dat = (uint32) *buf++; /* get low 16b */
569 dat = dat | (((uint32) *buf++) << 16); /* merge hi 16b */
570 WriteL (pa, dat); /* store LW */
571 }
572 }
573 }
574 mba_bc[mb] = (mba_bc[mb] + i) & MBABC_WR;
575 mba_va[mb] = (mba_va[mb] + i) & MBAVA_WR;
576 return i;
577 }
578
mba_chbufW(uint32 mb,int32 bc,uint16 * buf)579 int32 mba_chbufW (uint32 mb, int32 bc, uint16 *buf)
580 {
581 int32 i, j, ba, mbc, pbc;
582 uint32 pa, dat, cmp;
583
584 if (mb >= MBA_NUM) /* valid MBA? */
585 return 0;
586 ba = mba_va[mb]; /* get virt addr */
587 mbc = (MBABC_WR + 1) - mba_bc[mb]; /* get Mbus bc */
588 if (bc > mbc) /* use smaller */
589 bc = mbc;
590 for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
591 if (!mba_map_addr (ba + i, &pa, mb)) /* page inv? */
592 break;
593 if (!ADDR_IS_MEM (pa)) { /* NXM? */
594 mba_upd_sr (MBASR_RTMO, 0, mb);
595 break;
596 }
597 pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
598 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_XFR))
599 fprintf (sim_deb, ">>MBA%d: check, pa = %X, bc = %X\n", mb, pa, pbc);
600 if (pbc > (bc - i)) /* limit to rem xfr */
601 pbc = bc - i;
602 for (j = 0; j < pbc; j++, pa++) { /* byte by byte */
603 cmp = ReadB (pa);
604 if ((i + j) & 1)
605 dat = (*buf++ >> 8) & BMASK;
606 else dat = *buf & BMASK;
607 if (cmp != dat) {
608 mba_upd_sr ((j & 1)? MBASR_WCEU: MBASR_WCEL, 0, mb);
609 break;
610 } /* end if */
611 } /* end for j */
612 } /* end for i */
613 mba_bc[mb] = (mba_bc[mb] + i) & MBABC_WR;
614 mba_va[mb] = (mba_va[mb] + i) & MBAVA_WR;
615 return i;
616 }
617
618 /* Map an address via the translation map */
619
mba_map_addr(uint32 va,uint32 * ma,uint32 mb)620 t_bool mba_map_addr (uint32 va, uint32 *ma, uint32 mb)
621 {
622 uint32 vblk = (va >> VA_V_VPN); /* map index */
623 uint32 mmap = mba_map[mb][vblk]; /* get map */
624
625 mba_smr[mb] = mmap; /* save map reg */
626 if (mmap & MBAMAP_VLD) { /* valid? */
627 *ma = ((mmap & MBAMAP_PAG) << VA_V_VPN) + VA_GETOFF (va);
628 return 1; /* legit addr */
629 }
630 mba_upd_sr (MBASR_INVM, 0, mb); /* invalid map */
631 return 0;
632 }
633
634 /* Device access, status, and interrupt routines */
635
mba_set_don(uint32 mb)636 void mba_set_don (uint32 mb)
637 {
638 mba_upd_sr (MBASR_DTCMP, 0, mb);
639 return;
640 }
641
mba_upd_ata(uint32 mb,uint32 val)642 void mba_upd_ata (uint32 mb, uint32 val)
643 {
644 if (val)
645 mba_upd_sr (MBASR_ATA, 0, mb);
646 else mba_upd_sr (0, MBASR_ATA, mb);
647 return;
648 }
649
mba_set_exc(uint32 mb)650 void mba_set_exc (uint32 mb)
651 {
652 mba_upd_sr (MBASR_MBEXC, 0, mb);
653 if (DEBUG_PRI (mba_dev[mb], MBA_DEB_ERR))
654 fprintf (sim_deb, ">>MBA%d: EXC write\n", mb);
655 return;
656 }
657
mba_get_bc(uint32 mb)658 int32 mba_get_bc (uint32 mb)
659 {
660 if (mb >= MBA_NUM)
661 return 0;
662 return (MBABC_WR + 1) - mba_bc[mb];
663 }
664
mba_set_int(uint32 mb)665 void mba_set_int (uint32 mb)
666 {
667 DIB *dibp;
668
669 if (mb >= MBA_NUM)
670 return;
671 dibp = (DIB *) mba_dev[mb].ctxt;
672 if (dibp)
673 nexus_req[dibp->vloc >> 5] |= (1u << (dibp->vloc & 0x1F));
674 return;
675 }
676
mba_clr_int(uint32 mb)677 void mba_clr_int (uint32 mb)
678 {
679 DIB *dibp;
680
681 if (mb >= MBA_NUM)
682 return;
683 dibp = (DIB *) mba_dev[mb].ctxt;
684 if (dibp)
685 nexus_req[dibp->vloc >> 5] &= ~(1u << (dibp->vloc & 0x1F));
686 return;
687 }
688
mba_upd_sr(uint32 set,uint32 clr,uint32 mb)689 void mba_upd_sr (uint32 set, uint32 clr, uint32 mb)
690 {
691 if (mb >= MBA_NUM)
692 return;
693 if (set & MBASR_ABORTS)
694 set |= (MBASR_DTCMP|MBASR_DTABT);
695 if (set & (MBASR_DTCMP|MBASR_DTABT))
696 mba_sr[mb] &= ~MBASR_DTBUSY;
697 mba_sr[mb] = (mba_sr[mb] | set) & ~clr;
698 if ((set & MBASR_INTR) && (mba_cr[mb] & MBACR_IE))
699 mba_set_int (mb);
700 if ((set & MBASR_ERRORS) && (DEBUG_PRI (mba_dev[mb], MBA_DEB_ERR)))
701 fprintf (sim_deb, ">>MBA%d: CS error = %X\n", mb, mba_sr[mb]);
702 return;
703 }
704
705 /* Reset Massbus adapter */
706
mba_reset(DEVICE * dptr)707 t_stat mba_reset (DEVICE *dptr)
708 {
709 int32 i, mb;
710 DIB *dibp;
711
712 dibp = (DIB *) dptr->ctxt;
713 if (dibp == NULL)
714 return SCPE_IERR;
715 mb = dibp->ba - TR_MBA0;
716 if ((mb < 0) || (mb >= MBA_NUM))
717 return SCPE_IERR;
718 mba_cnf[mb] = 0;
719 mba_cr[mb] &= MBACR_MNT;
720 mba_sr[mb] = 0;
721 mba_bc[mb] = 0;
722 mba_va[mb] = 0;
723 mba_dr[mb] = 0;
724 mba_smr[mb] = 0;
725 if (sim_switches & SWMASK ('P')) {
726 for (i = 0; i < MBA_NMAPR; i++)
727 mba_map[mb][i] = 0;
728 }
729 if (mbabort[mb]) /* reset device */
730 mbabort[mb] ();
731 return SCPE_OK;
732 }
733
734 /* Show Massbus adapter number */
735
mba_show_num(FILE * st,UNIT * uptr,int32 val,void * desc)736 t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc)
737 {
738 DEVICE *dptr = find_dev_from_unit (uptr);
739 DIB *dibp;
740
741 if (dptr == NULL)
742 return SCPE_IERR;
743 dibp = (DIB *) dptr->ctxt;
744 if (dibp == NULL)
745 return SCPE_IERR;
746 fprintf (st, "Massbus adapter %d", dibp->ba);
747 return SCPE_OK;
748 }
749
750 /* Enable/disable Massbus adapter */
751
mba_set_enbdis(uint32 mb,t_bool dis)752 void mba_set_enbdis (uint32 mb, t_bool dis)
753 {
754 if (mb >= MBA_NUM) /* valid MBA? */
755 return;
756 if (dis)
757 mba_dev[mb].flags |= DEV_DIS;
758 else mba_dev[mb].flags &= ~DEV_DIS;
759 return;
760 }
761
762 /* Init Mbus tables */
763
init_mbus_tab(void)764 void init_mbus_tab (void)
765 {
766 uint32 i;
767
768 for (i = 0; i < MBA_NUM; i++) {
769 mbregR[i] = NULL;
770 mbregW[i] = NULL;
771 mbabort[i] = NULL;
772 }
773 return;
774 }
775
776 /* Build dispatch tables */
777
build_mbus_tab(DEVICE * dptr,DIB * dibp)778 t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp)
779 {
780 uint32 idx;
781
782 if ((dptr == NULL) || (dibp == NULL)) /* validate args */
783 return SCPE_IERR;
784 idx = dibp->ba; /* Mbus # */
785 if (idx >= MBA_NUM)
786 return SCPE_STOP;
787 if ((mbregR[idx] && dibp->rd && /* conflict? */
788 (mbregR[idx] != dibp->rd)) ||
789 (mbregW[idx] && dibp->wr &&
790 (mbregW[idx] != dibp->wr)) ||
791 (mbabort[idx] && dibp->ack[0] &&
792 (mbabort[idx] != dibp->ack[0]))) {
793 printf ("Massbus %s assignment conflict at %d\n",
794 sim_dname (dptr), dibp->ba);
795 if (sim_log)
796 fprintf (sim_log, "Massbus %s assignment conflict at %d\n",
797 sim_dname (dptr), dibp->ba);
798 return SCPE_STOP;
799 }
800 if (dibp->rd) /* set rd dispatch */
801 mbregR[idx] = dibp->rd;
802 if (dibp->wr) /* set wr dispatch */
803 mbregW[idx] = dibp->wr;
804 if (dibp->ack[0]) /* set abort dispatch */
805 mbabort[idx] = dibp->ack[0];
806 return SCPE_OK;
807 }
808
809