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