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