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