1 /* pdp11_rh.c: PDP-11 Massbus adapter simulator
2 
3    Copyright (c) 2005-2012, 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    rha, rhb             RH11/RH70 Massbus adapter
27 
28    19-Mar-12    RMS     Fixed declaration of cpu_opt (Mark Pizzolato)
29    02-Feb-08    RMS     Fixed DMA memory address limit test (John Dundas)
30    17-May-07    RMS     Moved CS1 drive enable to devices
31    21-Nov-05    RMS     Added enable/disable routine
32    07-Jul-05    RMS     Removed extraneous externs
33 
34    WARNING: The interupt logic of the RH11/RH70 is unusual and must be
35    simulated with great precision.  The RH11 has an internal interrupt
36    request flop, CSTB INTR, which is controlled as follows:
37 
38    - Writing IE and DONE simultaneously sets CSTB INTR
39    - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR
40      (and also clear IE)
41    - A transition of DONE from 0 to 1 sets CSTB INTR from IE
42 
43    The output of CSTB INTR is OR'd with the AND of RPCS1<SC,DONE,IE> to
44    create the interrupt request signal.  Thus,
45 
46    - The DONE interrupt is edge sensitive, but the SC interrupt is
47      level sensitive.
48    - The DONE interrupt, once set, is not disabled if IE is cleared,
49      but the SC interrupt is.
50 */
51 
52 #if defined (VM_PDP10)                                  /* PDP10 version */
53 #error "PDP-10 uses pdp10_rp.c and pdp10_tu.c!"
54 
55 #elif defined (VM_VAX)                                  /* VAX version */
56 #error "VAX uses vax780_mba.c!"
57 
58 #else                                                   /* PDP-11 version */
59 #include "pdp11_defs.h"
60 #endif
61 
62 /* CS1 - base + 000 - control/status 1 */
63 
64 #define CS1_OF          0
65 #define CS1_GO          CSR_GO                          /* go */
66 #define CS1_V_FNC       1                               /* function pos */
67 #define CS1_M_FNC       037                             /* function mask */
68 #define CS1_FNC         (CS1_M_FNC << CS1_V_FNC)
69 #define FNC_XFER        024                             /* >=? data xfr */
70 #define CS1_IE          CSR_IE                          /* int enable */
71 #define CS1_DONE        CSR_DONE                        /* ready */
72 #define CS1_V_UAE       8                               /* Unibus addr ext */
73 #define CS1_M_UAE       03
74 #define CS1_UAE         (CS1_M_UAE << CS1_V_UAE)
75 #define CS1_MCPE        0020000                         /* Mbus par err NI */
76 #define CS1_TRE         0040000                         /* transfer err */
77 #define CS1_SC          0100000                         /* special cond */
78 #define CS1_MBZ         0012000
79 #define CS1_DRV         (CS1_FNC | CS1_GO)
80 #define GET_FNC(x)      (((x) >> CS1_V_FNC) & CS1_M_FNC)
81 
82 /* WC - base + 002 - word count */
83 
84 #define WC_OF           1
85 
86 /* BA - base + 004 - base address */
87 
88 #define BA_OF           2
89 #define BA_MBZ          0000001                         /* must be zero */
90 
91 /* CS2 - base + 010 - control/status 2 */
92 
93 #define CS2_OF          3
94 #define CS2_V_UNIT      0                               /* unit pos */
95 #define CS2_M_UNIT      07                              /* unit mask */
96 #define CS2_UNIT        (CS2_M_UNIT << CS2_V_UNIT)
97 #define CS2_UAI         0000010                         /* addr inhibit */
98 #define CS2_PAT         0000020                         /* parity test NI */
99 #define CS2_CLR         0000040                         /* controller clear */
100 #define CS2_IR          0000100                         /* input ready */
101 #define CS2_OR          0000200                         /* output ready */
102 #define CS2_MDPE        0000400                         /* Mbus par err NI */
103 #define CS2_MXF         0001000                         /* missed xfer NI */
104 #define CS2_PGE         0002000                         /* program err */
105 #define CS2_NEM         0004000                         /* nx mem err */
106 #define CS2_NED         0010000                         /* nx drive err */
107 #define CS2_PE          0020000                         /* parity err NI */
108 #define CS2_WCE         0040000                         /* write check err */
109 #define CS2_DLT         0100000                         /* data late NI */
110 #define CS2_MBZ         (CS2_CLR)
111 #define CS2_RW          (CS2_UNIT | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE)
112 #define CS2_ERR         (CS2_MDPE | CS2_MXF | CS2_PGE | CS2_NEM | \
113                          CS2_NED | CS2_PE | CS2_WCE | CS2_DLT)
114 #define GET_UNIT(x)     (((x) >> CS2_V_UNIT) & CS2_M_UNIT)
115 
116 /* DB - base + 022 - data buffer */
117 
118 #define DB_OF           4
119 
120 /* BAE - base + 050/34 - bus address extension */
121 
122 #define BAE_OF          5
123 #define AE_M_MAE        0                               /* addr ext pos */
124 #define AE_V_MAE        077                             /* addr ext mask */
125 #define AE_MBZ          0177700
126 
127 /* CS3 - base + 052/36 - control/status 3 */
128 
129 #define CS3_OF          6
130 #define CS3_APE         0100000                         /* addr perr - NI */
131 #define CS3_DPO         0040000                         /* data perr odd - NI */
132 #define CS3_DPE         0020000                         /* data perr even - NI */
133 #define CS3_WCO         0010000                         /* wchk err odd */
134 #define CS3_WCE         0004000                         /* wchk err even */
135 #define CS3_DBL         0002000                         /* dbl word xfer - NI */
136 #define CS3_IPCK        0000017                         /* wrong par - NI */
137 #define CS3_ERR         (CS3_APE|CS3_DPO|CS3_DPE|CS3_WCO|CS3_WCE)
138 #define CS3_MBZ         0001660
139 #define CS3_RW          (CS1_IE | CS3_IPCK)
140 
141 #define MBA_OFSMASK     077                             /* max 32 reg */
142 #define INT             0000                            /* int reg flag */
143 #define EXT             0100                            /* ext reg flag */
144 
145 /* Declarations */
146 
147 #define RH11            (cpu_opt & OPT_RH11)
148 
149 typedef struct {
150     uint32 cs1;                                         /* ctrl/status 1 */
151     uint32 wc;                                          /* word count */
152     uint32 ba;                                          /* bus addr */
153     uint32 cs2;                                         /* ctrl/status 2 */
154     uint32 db;                                          /* data buffer */
155     uint32 bae;                                         /* addr ext */
156     uint32 cs3;                                         /* ctrl/status 3 */
157     uint32 iff;                                         /* int flip flop */
158     } MBACTX;
159 
160 MBACTX massbus[MBA_NUM];
161 
162 extern uint32 cpu_opt;
163 extern int32 cpu_bme;
164 extern uint16 *M;
165 extern int32 int_req[IPL_HLVL];
166 extern t_addr cpu_memsize;
167 extern FILE *sim_deb;
168 extern FILE *sim_log;
169 extern int32 sim_switches;
170 
171 t_stat mba_reset (DEVICE *dptr);
172 t_stat mba_rd (int32 *val, int32 pa, int32 access);
173 t_stat mba_wr (int32 val, int32 pa, int32 access);
174 t_stat mba_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);
175 t_stat mba_show_type (FILE *st, UNIT *uptr, int32 val, void *desc);
176 int32 mba0_inta (void);
177 int32 mba1_inta (void);
178 void mba_set_int (uint32 mb);
179 void mba_clr_int (uint32 mb);
180 void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb);
181 void mba_set_cs2 (uint32 flg, uint32 mb);
182 uint32 mba_map_pa (int32 pa, int32 *ofs);
183 DEVICE mba0_dev, mba1_dev;
184 
185 extern uint32 Map_Addr (uint32 ba);
186 
187 /* Massbus register dispatches */
188 
189 static t_stat (*mbregR[MBA_NUM])(int32 *dat, int32 ad, int32 md);
190 static t_stat (*mbregW[MBA_NUM])(int32 dat, int32 ad, int32 md);
191 static int32 (*mbabort[MBA_NUM])(void);
192 
193 /* Unibus to register offset map */
194 
195 static int32 mba_mapofs[(MBA_OFSMASK + 1) >> 1] = {
196  INT|0,  INT|1,  INT|2,  EXT|5,  INT|3,  EXT|1,  EXT|2,  EXT|4,
197  EXT|7,  INT|4,  EXT|3,  EXT|6,  EXT|8,  EXT|9,  EXT|10, EXT|11,
198  EXT|12, EXT|13, EXT|14, EXT|15, EXT|16, EXT|17, EXT|18, EXT|19,
199  EXT|20, EXT|21, EXT|22, EXT|23, EXT|24, EXT|25, EXT|26, EXT|27
200  };
201 
202 /* Massbus adapter data structures
203 
204    mbax_dev     RHx device descriptor
205    mbax_unit    RHx units
206    mbax_reg     RHx register list
207 */
208 
209 DIB mba0_dib = {
210     IOBA_RP, IOLN_RP, &mba_rd, &mba_wr,
211     1, IVCL (RP), VEC_RP, { &mba0_inta }
212     };
213 
214 UNIT mba0_unit = { UDATA (NULL, 0, 0) };
215 
216 REG mba0_reg[] = {
217     { ORDATA (CS1, massbus[0].cs1, 16) },
218     { ORDATA (WC, massbus[0].wc, 16) },
219     { ORDATA (BA, massbus[0].ba, 16) },
220     { ORDATA (CS2, massbus[0].cs2, 16) },
221     { ORDATA (DB, massbus[0].db, 16) },
222     { ORDATA (BAE, massbus[0].bae, 6) },
223     { ORDATA (CS3, massbus[0].cs3, 16) },
224     { FLDATA (IFF, massbus[0].iff, 0) },
225     { FLDATA (INT, IREQ (RP), INT_V_RP) },
226     { FLDATA (SC, massbus[0].cs1, CSR_V_ERR) },
227     { FLDATA (DONE, massbus[0].cs1, CSR_V_DONE) },
228     { FLDATA (IE, massbus[0].cs1, CSR_V_IE) },
229     { ORDATA (DEVADDR, mba0_dib.ba, 32), REG_HRO },
230     { ORDATA (DEVVEC, mba0_dib.vec, 16), REG_HRO },
231     { NULL }
232     };
233 
234 MTAB mba0_mod[] = {
235     { MTAB_XTD|MTAB_VDV, 0100, "ADDRESS", "ADDRESS",
236       &set_addr, &show_addr, NULL },
237     { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
238       &set_vec, &show_vec, NULL },
239     { 0 }
240     };
241 
242 DIB mba1_dib = {
243     IOBA_TU, IOLN_TU, &mba_rd, &mba_wr,
244     1, IVCL (TU), VEC_TU, { &mba1_inta }
245     };
246 
247 UNIT mba1_unit = { UDATA (NULL, 0, 0) };
248 
249 REG mba1_reg[] = {
250     { ORDATA (CS1, massbus[1].cs1, 16) },
251     { ORDATA (WC, massbus[1].wc, 16) },
252     { ORDATA (BA, massbus[1].ba, 16) },
253     { ORDATA (CS2, massbus[1].cs2, 16) },
254     { ORDATA (DB, massbus[1].db, 16) },
255     { ORDATA (BAE, massbus[1].bae, 6) },
256     { ORDATA (CS3, massbus[1].cs3, 16) },
257     { FLDATA (IFF, massbus[1].iff, 0) },
258     { FLDATA (INT, IREQ (TU), INT_V_TU) },
259     { FLDATA (SC, massbus[1].cs1, CSR_V_ERR) },
260     { FLDATA (DONE, massbus[1].cs1, CSR_V_DONE) },
261     { FLDATA (IE, massbus[1].cs1, CSR_V_IE) },
262     { ORDATA (DEVADDR, mba1_dib.ba, 32), REG_HRO },
263     { ORDATA (DEVVEC, mba1_dib.vec, 16), REG_HRO },
264     { NULL }
265     };
266 
267 MTAB mba1_mod[] = {
268     { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS",
269       &set_addr, &show_addr, NULL },
270     { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
271       &set_vec, &show_vec, NULL },
272     { 0 }
273     };
274 
275 DEVICE mba_dev[] = {
276     {
277     "RHA", &mba0_unit, mba0_reg, mba0_mod,
278     1, 0, 0, 0, 0, 0,
279     NULL, NULL, &mba_reset,
280     NULL, NULL, NULL,
281     &mba0_dib, DEV_DEBUG | DEV_DISABLE | DEV_UBUS | DEV_QBUS
282     },
283     {
284     "RHB", &mba1_unit, mba1_reg, mba1_mod,
285     1, 0, 0, 0, 0, 0,
286     NULL, NULL, &mba_reset,
287     NULL, NULL, NULL,
288     &mba1_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS
289     }
290     };
291 
292 /* Read Massbus adapter register */
293 
mba_rd(int32 * val,int32 pa,int32 mode)294 t_stat mba_rd (int32 *val, int32 pa, int32 mode)
295 {
296 int32 ofs, dat, mb, drv;
297 t_stat r;
298 
299 mb = mba_map_pa (pa, &ofs);                             /* get mb number */
300 if ((mb < 0) || (ofs < 0))                              /* valid? */
301     return SCPE_NXM;
302 drv = GET_UNIT (massbus[mb].cs2);                       /* get drive */
303 mba_upd_cs1 (0, 0, mb);                                 /* update CS1 */
304 
305 if (ofs & EXT) {                                        /* external? */
306     if (!mbregR[mb])                                    /* device there? */
307         return SCPE_NXM;
308     r = mbregR[mb] (val, ofs & ~EXT, drv);              /* call device */
309     if (r == MBE_NXD)                                   /* nx drive? */
310         mba_set_cs2 (CS2_NED, mb);
311     else if (r == MBE_NXR)                              /* nx reg? */
312         return SCPE_NXM;
313     return SCPE_OK;
314     }
315 
316 switch (ofs) {                                          /* case on reg */
317 
318     case CS1_OF:                                        /* CS1 */
319         if (!mbregR[mb])                                /* nx device? */
320             return SCPE_NXM;
321         r = mbregR[mb] (&dat, ofs, drv);                /* get dev cs1 */
322         if (r == MBE_NXD)                               /* nx drive? */
323             mba_set_cs2 (CS2_NED, mb);
324         *val = massbus[mb].cs1 | dat;
325         break;
326 
327     case WC_OF:                                         /* WC */
328         *val = massbus[mb].wc;
329         break;
330 
331     case BA_OF:                                         /* BA */
332         *val = massbus[mb].ba & ~BA_MBZ;
333         break;
334 
335     case CS2_OF:                                        /* CS2 */
336         *val = massbus[mb].cs2 = (massbus[mb].cs2 & ~CS2_MBZ) | CS2_IR | CS2_OR;
337         break;
338 
339     case DB_OF:                                         /* DB */
340         *val = massbus[mb].db;
341         break;
342 
343     case BAE_OF:                                        /* BAE */
344         *val = massbus[mb].bae = massbus[mb].bae & ~AE_MBZ;
345         break;
346 
347     case CS3_OF:                                        /* CS3 */
348         *val = massbus[mb].cs3 = (massbus[mb].cs3 & ~(CS1_IE | CS3_MBZ)) |
349             (massbus[mb].cs1 & CS1_IE);
350         break;
351 
352     default:                                            /* huh? */
353         return SCPE_NXM;
354         }
355 
356 return SCPE_OK;
357 }
358 
mba_wr(int32 val,int32 pa,int32 access)359 t_stat mba_wr (int32 val, int32 pa, int32 access)
360 {
361 int32 ofs, cs1f, drv, mb;
362 t_stat r;
363 t_bool cs1dt;
364 
365 mb = mba_map_pa (pa, &ofs);                             /* get mb number */
366 if ((mb < 0) || (ofs < 0))                              /* valid? */
367     return SCPE_NXM;
368 drv = GET_UNIT (massbus[mb].cs2);                       /* get drive */
369 
370 if (ofs & EXT) {                                        /* external? */
371     if (!mbregW[mb])                                    /* device there? */
372         return SCPE_NXM;
373     if ((access == WRITEB) && (pa & 1))                 /* byte writes */
374         val = val << 8;                                 /* don't work */
375     r = mbregW[mb] (val, ofs & ~EXT, drv);              /* write dev reg */
376     if (r == MBE_NXD)                                   /* nx drive? */
377         mba_set_cs2 (CS2_NED, mb);
378     else if (r == MBE_NXR)                              /* nx reg? */
379         return SCPE_NXM;
380     mba_upd_cs1 (0, 0, mb);                             /* update status */
381     return SCPE_OK;
382     }
383 
384 cs1f = 0;                                               /* no int on cs1 upd */
385 switch (ofs) {                                          /* case on reg */
386 
387     case CS1_OF:                                        /* CS1 */
388         if (!mbregW[mb])                                /* device exist? */
389             return SCPE_NXM;
390         if ((access == WRITEB) && (pa & 1))
391             val = val << 8;
392         if (val & CS1_TRE) {                            /* error clear? */
393             massbus[mb].cs1 &= ~CS1_TRE;                /* clr CS1<TRE> */
394             massbus[mb].cs2 &= ~CS2_ERR;                /* clr CS2<15:8> */
395             massbus[mb].cs3 &= ~CS3_ERR;                /* clr CS3<15:11> */
396             }
397         if ((access == WRITE) || (pa & 1)) {            /* hi byte write? */
398             if (massbus[mb].cs1 & CS1_DONE)             /* done set? */
399                 massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_UAE) | (val & CS1_UAE);
400             }
401         if ((access == WRITE) || !(pa & 1)) {           /* lo byte write? */
402             if ((val & CS1_DONE) && (val & CS1_IE))     /* to DONE+IE? */
403                 massbus[mb].iff = 1;                    /* set CSTB INTR */
404             massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_IE) | (val & CS1_IE);
405             cs1dt = (val & CS1_GO) && (GET_FNC (val) >= FNC_XFER);
406             if (cs1dt && ((massbus[mb].cs1 & CS1_DONE) == 0))  /* dt, done clr? */
407                 mba_set_cs2 (CS2_PGE, mb);              /* prgm error */
408             else {
409                 r = mbregW[mb] (val & 077, ofs, drv);   /* write dev CS1 */
410                 if (r == MBE_NXD)                       /* nx drive? */
411                     mba_set_cs2 (CS2_NED, mb);
412                 else if (r == MBE_NXR)                  /* nx reg? */
413                     return SCPE_NXM;
414                 else if (cs1dt && (r == SCPE_OK)) {     /* xfer, no err? */
415                     massbus[mb].cs1 &= ~(CS1_TRE | CS1_MCPE | CS1_DONE);
416                     massbus[mb].cs2 &= ~CS2_ERR;        /* clear errors */
417                     massbus[mb].cs3 &= ~(CS3_ERR | CS3_DBL);
418                     }
419                 }
420             }
421         massbus[mb].cs3 = (massbus[mb].cs3 & ~CS1_IE) | /* update CS3 */
422             (massbus[mb].cs1 & CS1_IE);
423         massbus[mb].bae = (massbus[mb].bae & ~CS1_M_UAE) | /* update BAE */
424             ((massbus[mb].cs1 >> CS1_V_UAE) & CS1_M_UAE);
425         break;
426 
427     case WC_OF:                                         /* WC */
428         if (access == WRITEB)
429             val = (pa & 1)?
430             (massbus[mb].wc & 0377) | (val << 8):
431             (massbus[mb].wc & ~0377) | val;
432         massbus[mb].wc = val;
433         break;
434 
435     case BA_OF:                                         /* BA */
436         if (access == WRITEB)
437             val = (pa & 1)?
438             (massbus[mb].ba & 0377) | (val << 8):
439             (massbus[mb].ba & ~0377) | val;
440         massbus[mb].ba = val & ~BA_MBZ;
441         break;
442 
443     case CS2_OF:                                        /* CS2 */
444         if ((access == WRITEB) && (pa & 1))
445             val = val << 8;
446         if (val & CS2_CLR)                              /* init? */
447             mba_reset (&mba_dev[mb]);
448         else {
449             if ((val & ~massbus[mb].cs2) & (CS2_PE | CS2_MXF))
450                 cs1f = CS1_SC;                          /* diagn intr */
451             if (access == WRITEB)                       /* merge val */
452                 val = (massbus[mb].cs2 & ((pa & 1)? 0377: 0177400)) | val;
453             massbus[mb].cs2 = (massbus[mb].cs2 & ~CS2_RW) |
454                 (val & CS2_RW) | CS2_IR | CS2_OR;
455             }
456         break;
457 
458     case DB_OF:                                         /* DB */
459         if (access == WRITEB)
460             val = (pa & 1)?
461             (massbus[mb].db & 0377) | (val << 8):
462             (massbus[mb].db & ~0377) | val;
463         massbus[mb].db = val;
464         break;
465 
466     case BAE_OF:                                       /* BAE */
467         if ((access == WRITEB) && (pa & 1))
468             break;
469         massbus[mb].bae = val & ~AE_MBZ;
470         massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_UAE) | /* update CS1 */
471             ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE);
472         break;
473 
474     case CS3_OF:                                        /* CS3 */
475         if ((access == WRITEB) && (pa & 1))
476             break;
477         massbus[mb].cs3 = (massbus[mb].cs3 & ~CS3_RW) | (val & CS3_RW);
478         massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_IE) | /* update CS1 */
479             (massbus[mb].cs3 & CS1_IE);
480         break;
481 
482     default:
483         return SCPE_NXM;
484         }
485 
486 mba_upd_cs1 (cs1f, 0, mb);                              /* update status */
487 return SCPE_OK;
488 }
489 
490 /* Massbus I/O routines
491 
492    mb_rdbufW    -       fetch word buffer from memory
493    mb_wrbufW    -       store word buffer into memory
494    mb_chbufW    -       compare word buffer with memory
495 
496    Returns number of bytes successfully transferred/checked
497 */
498 
mba_rdbufW(uint32 mb,int32 bc,uint16 * buf)499 int32 mba_rdbufW (uint32 mb, int32 bc, uint16 *buf)
500 {
501 int32 i, j, ba, mbc, pbc;
502 uint32 pa;
503 
504 bc = bc & ~1;                                           /* bc even */
505 if (mb >= MBA_NUM)                                      /* valid MBA? */
506     return 0;
507 ba = (massbus[mb].bae << 16) | massbus[mb].ba;          /* get busaddr */
508 mbc = (0200000 - massbus[mb].wc) << 1;                  /* MB byte count */
509 if (bc > mbc)                                           /* use smaller */
510     bc = mbc;
511 for (i = 0; i < bc; i = i + pbc) {                      /* loop by pages */
512     if (RH11 && cpu_bme)                                /* map addr */
513         pa = Map_Addr (ba);
514     else pa = ba;
515     if (!ADDR_IS_MEM (pa)) {                            /* NXM? */
516         mba_set_cs2 (CS2_NEM, mb);                      /* set error */
517         break;
518         }
519     pbc = UBM_PAGSIZE - UBM_GETOFF (pa);                /* left in page */
520     if (pbc > (bc - i))                                 /* limit to rem xfr */
521         pbc = bc - i;
522     for (j = 0; j < pbc; j = j + 2) {                   /* loop by words */
523         *buf++ = M[pa >> 1];                            /* fetch word */
524         if (!(massbus[mb].cs2 & CS2_UAI)) {             /* if not inhb */
525             ba = ba + 2;                                /* incr ba, pa */
526             pa = pa + 2;
527             }
528         }
529     }
530 massbus[mb].wc = (massbus[mb].wc + (bc >> 1)) & DMASK;   /* update wc */
531 massbus[mb].ba = ba & DMASK;                             /* update ba */
532 massbus[mb].bae = (ba >> 16) & ~AE_MBZ;                  /* upper 6b */
533 massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) |         /* update CS1 */
534     ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE);
535 return i;
536 }
537 
mba_wrbufW(uint32 mb,int32 bc,uint16 * buf)538 int32 mba_wrbufW (uint32 mb, int32 bc, uint16 *buf)
539 {
540 int32 i, j, ba, mbc, pbc;
541 uint32 pa;
542 
543 bc = bc & ~1;                                           /* bc even */
544 if (mb >= MBA_NUM)                                      /* valid MBA? */
545     return 0;
546 ba = (massbus[mb].bae << 16) | massbus[mb].ba;          /* get busaddr */
547 mbc = (0200000 - massbus[mb].wc) << 1;                  /* MB byte count */
548 if (bc > mbc)                                           /* use smaller */
549     bc = mbc;
550 for (i = 0; i < bc; i = i + pbc) {                      /* loop by pages */
551     if (RH11 && cpu_bme)                                /* map addr */
552         pa = Map_Addr (ba);
553     else pa = ba;
554     if (!ADDR_IS_MEM (pa)) {                            /* NXM? */
555         mba_set_cs2 (CS2_NEM, mb);                      /* set error */
556         break;
557         }
558     pbc = UBM_PAGSIZE - UBM_GETOFF (pa);                /* left in page */
559     if (pbc > (bc - i))                                 /* limit to rem xfr */
560         pbc = bc - i;
561     for (j = 0; j < pbc; j = j + 2) {                   /* loop by words */
562         M[pa >> 1] = *buf++;                            /* put word */
563         if (!(massbus[mb].cs2 & CS2_UAI)) {             /* if not inhb */
564             ba = ba + 2;                                /* incr ba, pa */
565             pa = pa + 2;
566             }
567         }
568     }
569 massbus[mb].wc = (massbus[mb].wc + (bc >> 1)) & DMASK;  /* update wc */
570 massbus[mb].ba = ba & DMASK;                            /* update ba */
571 massbus[mb].bae = (ba >> 16) & ~AE_MBZ;                 /* upper 6b */
572 massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) |       /* update CS1 */
573     ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE);
574 return i;
575 }
576 
mba_chbufW(uint32 mb,int32 bc,uint16 * buf)577 int32 mba_chbufW (uint32 mb, int32 bc, uint16 *buf)
578 {
579 int32 i, j, ba, mbc, pbc;
580 uint32 pa;
581 
582 bc = bc & ~1;                                           /* bc even */
583 if (mb >= MBA_NUM)                                      /* valid MBA? */
584     return 0;
585 ba = (massbus[mb].bae << 16) | massbus[mb].ba;          /* get busaddr */
586 mbc = (0200000 - massbus[mb].wc) << 1;                  /* MB byte count */
587 if (bc > mbc)                                           /* use smaller */
588     bc = mbc;
589 for (i = 0; i < bc; i = i + pbc) {                      /* loop by pages */
590     if (RH11 && cpu_bme) pa = Map_Addr (ba);            /* map addr */
591     else pa = ba;
592     if (!ADDR_IS_MEM (pa)) {                            /* NXM? */
593         mba_set_cs2 (CS2_NEM, mb);                      /* set error */
594         break;
595         }
596     pbc = UBM_PAGSIZE - UBM_GETOFF (pa);                /* left in page */
597     if (pbc > (bc - i))                                 /* limit to rem xfr */
598         pbc = bc - i;
599     for (j = 0; j < pbc; j = j + 2) {                   /* loop by words */
600         massbus[mb].db = *buf++;                        /* get dev word */
601         if (M[pa >> 1] != massbus[mb].db) {             /* miscompare? */
602             mba_set_cs2 (CS2_WCE, mb);                  /* set error */
603             massbus[mb].cs3 = massbus[mb].cs3 |         /* set even/odd */
604                 ((pa & 1)? CS3_WCO: CS3_WCE);
605             break;
606             }
607         if (!(massbus[mb].cs2 & CS2_UAI)) {             /* if not inhb */
608             ba = ba + 2;                                /* incr ba, pa */
609             pa = pa + 2;
610             }
611         }
612     }
613 massbus[mb].wc = (massbus[mb].wc + (bc >> 1)) & DMASK;  /* update wc */
614 massbus[mb].ba = ba & DMASK;                            /* update ba */
615 massbus[mb].bae = (ba >> 16) & ~AE_MBZ;                 /* upper 6b */
616 massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) |       /* update CS1 */
617     ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE);
618 return i;
619 }
620 
621 /* Device access, status, and interrupt routines */
622 
mba_set_don(uint32 mb)623 void mba_set_don (uint32 mb)
624 {
625 mba_upd_cs1 (CS1_DONE, 0, mb);
626 return;
627 }
628 
mba_upd_ata(uint32 mb,uint32 val)629 void mba_upd_ata (uint32 mb, uint32 val)
630 {
631 if (val)
632     mba_upd_cs1 (CS1_SC, 0, mb);
633 else mba_upd_cs1 (0, CS1_SC, mb);
634 return;
635 }
636 
mba_set_exc(uint32 mb)637 void mba_set_exc (uint32 mb)
638 {
639 mba_upd_cs1 (CS1_TRE | CS1_DONE, 0, mb);
640 return;
641 }
642 
mba_get_bc(uint32 mb)643 int32 mba_get_bc (uint32 mb)
644 {
645 if (mb >= MBA_NUM)
646     return 0;
647 return ((0200000 - massbus[mb].wc) << 1);
648 }
649 
mba_get_csr(uint32 mb)650 int32 mba_get_csr (uint32 mb)
651 {
652 DIB *dibp;
653 
654 if (mb >= MBA_NUM)
655     return 0;
656 dibp = (DIB *) mba_dev[mb].ctxt;
657 return dibp->ba;
658 }
659 
mba_set_int(uint32 mb)660 void mba_set_int (uint32 mb)
661 {
662 DIB *dibp;
663 
664 if (mb >= MBA_NUM)
665     return;
666 dibp = (DIB *) mba_dev[mb].ctxt;
667 int_req[dibp->vloc >> 5] |= (1 << (dibp->vloc & 037));
668 return;
669 }
670 
mba_clr_int(uint32 mb)671 void mba_clr_int (uint32 mb)
672 {
673 DIB *dibp;
674 
675 if (mb >= MBA_NUM)
676     return;
677 dibp = (DIB *) mba_dev[mb].ctxt;
678 int_req[dibp->vloc >> 5] &= ~(1 << (dibp->vloc & 037));
679 return;
680 }
681 
mba_upd_cs1(uint32 set,uint32 clr,uint32 mb)682 void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb)
683 {
684 if (mb >= MBA_NUM)
685     return;
686 if ((set & ~massbus[mb].cs1) & CS1_DONE)                    /* DONE 0 to 1? */
687     massbus[mb].iff = (massbus[mb].cs1 & CS1_IE)? 1: 0;     /* CSTB INTR <- IE */
688 massbus[mb].cs1 = (massbus[mb].cs1 & ~(clr | CS1_MCPE | CS1_MBZ | CS1_DRV)) | set;
689 if (massbus[mb].cs2 & CS2_ERR)
690     massbus[mb].cs1 = massbus[mb].cs1 | CS1_TRE | CS1_SC;
691 else if (massbus[mb].cs1 & CS1_TRE)
692     massbus[mb].cs1 = massbus[mb].cs1 | CS1_SC;
693 if (massbus[mb].iff ||
694     ((massbus[mb].cs1 & CS1_SC) &&
695      (massbus[mb].cs1 & CS1_DONE) &&
696      (massbus[mb].cs1 & CS1_IE)))
697     mba_set_int (mb);
698 else mba_clr_int (mb);
699 return;
700 }
701 
mba_set_cs2(uint32 flag,uint32 mb)702 void mba_set_cs2 (uint32 flag, uint32 mb)
703 {
704 if (mb >= MBA_NUM)
705     return;
706 massbus[mb].cs2 = massbus[mb].cs2 | flag;
707 mba_upd_cs1 (0, 0, mb);
708 return;
709 }
710 
711 /* Interrupt acknowledge */
712 
mba0_inta(void)713 int32 mba0_inta (void)
714 {
715 massbus[0].cs1 &= ~CS1_IE;                              /* clear int enable */
716 massbus[0].cs3 &= ~CS1_IE;                              /* in both registers */
717 massbus[0].iff = 0;                                     /* clear CSTB INTR */
718 return mba0_dib.vec;                                    /* acknowledge */
719 }
720 
mba1_inta(void)721 int32 mba1_inta (void)
722 {
723 massbus[1].cs1 &= ~CS1_IE;                              /* clear int enable */
724 massbus[1].cs3 &= ~CS1_IE;                              /* in both registers */
725 massbus[1].iff = 0;                                     /* clear CSTB INTR */
726 return mba1_dib.vec;                                    /* acknowledge */
727 }
728 
729 /* Map physical address to Massbus number, offset */
730 
mba_map_pa(int32 pa,int32 * ofs)731 uint32 mba_map_pa (int32 pa, int32 *ofs)
732 {
733 int32 i, uo, ba, lnt;
734 DIB *dibp;
735 
736 for (i = 0; i < MBA_NUM; i++) {                         /* loop thru ctrls */
737     dibp = (DIB *) mba_dev[i].ctxt;                     /* get DIB */
738     ba = dibp->ba;
739     lnt = dibp->lnt;
740     if ((pa >= ba) &&                                   /* in range? */
741         (pa < (ba + lnt))) {
742         if (pa < (ba + (lnt - 4))) {                    /* not last two? */
743             uo = ((pa - ba) & MBA_OFSMASK) >> 1;        /* get Unibus offset */
744             *ofs = mba_mapofs[uo];                      /* map thru PROM */
745             return i;                                   /* return ctrl idx */
746             }
747         else if (RH11)                                  /* RH11? done */
748             return -1;
749         else {                                          /* RH70 */
750             uo = (pa - (ba + (lnt - 4))) >> 1;          /* offset relative */
751             *ofs = BAE_OF + uo;                         /* to BAE */
752             return i;
753             }
754         }
755     }
756 return -1;
757 }
758 
759 /* Reset Massbus adapter */
760 
mba_reset(DEVICE * dptr)761 t_stat mba_reset (DEVICE *dptr)
762 {
763 uint32 mb;
764 
765 mb = dptr - mba_dev;
766 if (mb >= MBA_NUM)
767     return SCPE_NOFNC;
768 massbus[mb].cs1 = CS1_DONE;
769 massbus[mb].wc = 0;
770 massbus[mb].ba = 0;
771 massbus[mb].cs2 = 0;
772 massbus[mb].db = 0;
773 massbus[mb].bae= 0;
774 massbus[mb].cs3 = 0;
775 massbus[mb].iff = 0;
776 mba_clr_int (mb);
777 if (mbabort[mb])
778     mbabort[mb] ();
779 return SCPE_OK;
780 }
781 
782 /* Enable/disable Massbus adapter */
783 
mba_set_enbdis(uint32 mb,t_bool dis)784 void mba_set_enbdis (uint32 mb, t_bool dis)
785 {
786 if (mb >= MBA_NUM)                                      /* valid MBA? */
787     return;
788 if (dis)
789     mba_dev[mb].flags |= DEV_DIS;
790 else mba_dev[mb].flags &= ~DEV_DIS;
791 return;
792 }
793 
794 /* Show Massbus adapter number */
795 
mba_show_num(FILE * st,UNIT * uptr,int32 val,void * desc)796 t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc)
797 {
798 DEVICE *dptr = find_dev_from_unit (uptr);
799 DIB *dibp;
800 
801 if (dptr == NULL)
802     return SCPE_IERR;
803 dibp = (DIB *) dptr->ctxt;
804 if (dibp == NULL)
805     return SCPE_IERR;
806 fprintf (st, "Massbus adapter %d", dibp->ba);
807 return SCPE_OK;
808 }
809 
810 /* Init Mbus tables */
811 
init_mbus_tab(void)812 void init_mbus_tab (void)
813 {
814 uint32 i;
815 
816 for (i = 0; i < MBA_NUM; i++) {
817     mbregR[i] = NULL;
818     mbregW[i] = NULL;
819     mbabort[i] = NULL;
820     }
821 return;
822 }
823 
824 /* Build dispatch tables */
825 
build_mbus_tab(DEVICE * dptr,DIB * dibp)826 t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp)
827 {
828 uint32 idx;
829 
830 if ((dptr == NULL) || (dibp == NULL))                   /* validate args */
831     return SCPE_IERR;
832 idx = dibp->ba;                                         /* Mbus # */
833 if (idx >= MBA_NUM)
834     return SCPE_STOP;
835 if ((mbregR[idx] && dibp->rd &&                         /* conflict? */
836     (mbregR[idx] != dibp->rd)) ||
837     (mbregW[idx] && dibp->wr &&
838     (mbregW[idx] != dibp->wr)) ||
839     (mbabort[idx] && dibp->ack[0] &&
840     (mbabort[idx] != dibp->ack[0]))) {
841         printf ("Massbus %s assignment conflict at %d\n",
842                 sim_dname (dptr), dibp->ba);
843         if (sim_log)
844             fprintf (sim_log, "Massbus %s assignment conflict at %d\n",
845                      sim_dname (dptr), dibp->ba);
846         return SCPE_STOP;
847         }
848 if (dibp->rd)                                           /* set rd dispatch */
849     mbregR[idx] = dibp->rd;
850 if (dibp->wr)                                           /* set wr dispatch */
851     mbregW[idx] = dibp->wr;
852 if (dibp->ack[0])                                       /* set abort dispatch */
853     mbabort[idx] = dibp->ack[0];
854 return SCPE_OK;
855 }
856 
857