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