First Commit of my working state
[simh.git] / PDP10 / pdp10_ksio.c
CommitLineData
196ba1fc
PH
1/* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator\r
2\r
3 Copyright (c) 1993-2005, 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 uba Unibus adapters\r
27\r
28 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r
29 25-Jan-04 RMS Added stub floating address routine\r
30 12-Mar-03 RMS Added logical name support\r
31 10-Oct-02 RMS Revised for dynamic table generation\r
32 Added SHOW IOSPACE routine\r
33 29-Sep-02 RMS Added variable vector, central map support\r
34 25-Jan-02 RMS Revised for multiple DZ11's\r
35 06-Jan-02 RMS Revised enable/disable support\r
36 23-Sep-01 RMS New IO page address constants\r
37 07-Sep-01 RMS Revised device disable mechanism\r
38 25-Aug-01 RMS Enabled DZ11\r
39 21-Aug-01 RMS Updated DZ11 disable\r
40 01-Jun-01 RMS Updated DZ11 vectors\r
41 12-May-01 RMS Fixed typo\r
42\r
43 The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While\r
44 nominally four adapters are supported, in practice only 1 and 3\r
45 are implemented. The disks are placed on adapter 1, the rest of\r
46 the I/O devices on adapter 3.\r
47\r
48 In theory, we should maintain completely separate Unibuses, with\r
49 distinct PI systems. In practice, this simulator has so few devices\r
50 that we can get away with a single PI system, masking for which\r
51 devices are on adapter 1, and which on adapter 3. The Unibus\r
52 implementation is modeled on the Qbus in the PDP-11 simulator and\r
53 is described there.\r
54\r
55 The I/O subsystem is programmed by I/O instructions which create\r
56 Unibus operations (read, read pause, write, write byte). DMA is\r
57 the responsibility of the I/O device simulators, which also implement\r
58 Unibus to physical memory mapping.\r
59\r
60 The priority interrupt subsystem (and other privileged functions)\r
61 is programmed by I/O instructions with internal devices codes\r
62 (opcodes 700-702). These are dispatched here, although many are\r
63 handled in the memory management unit or elsewhere.\r
64\r
65 The ITS instructions are significantly different from the TOPS-10/20\r
66 instructions. They do not use the extended address calculation but\r
67 instead provide instruction variants (Q for Unibus adapter 1, I for\r
68 Unibus adapter 3) which insert the Unibus adapter number into the\r
69 effective address.\r
70*/\r
71\r
72#include "pdp10_defs.h"\r
73#include <setjmp.h>\r
74\r
75#define XBA_MBZ 0400000 /* ba mbz */\r
76#define eaRB (ea & ~1)\r
77#define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377)\r
78#define UBNXM_FAIL(pa,op) \\r
79 n = iocmap[GET_IOUBA (pa)]; \\r
80 if (n >= 0) ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \\r
81 pager_word = PF_HARD | PF_VIRT | PF_IO | \\r
82 ((op == WRITEB)? PF_BYTE: 0) | \\r
83 (TSTF (F_USR)? PF_USER: 0) | (pa); \\r
84 ABORT (PAGE_FAIL)\r
85\r
86/* Unibus adapter data */\r
87\r
88int32 ubcs[UBANUM] = { 0 }; /* status registers */\r
89int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */\r
90int32 int_req = 0; /* interrupt requests */\r
91\r
92/* Map IO controller numbers to Unibus adapters: -1 = non-existent */\r
93\r
94static int iocmap[IO_N_UBA] = { /* map I/O ext to UBA # */\r
95 -1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
96 }; \r
97\r
98static const int32 ubabr76[UBANUM] = {\r
99 INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6)\r
100 };\r
101static const int32 ubabr54[UBANUM] = {\r
102 INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4)\r
103 };\r
104static const int32 ubashf[4] = { 18, 26, 0, 8 };\r
105\r
106extern d10 *M; /* main memory */\r
107extern d10 *ac_cur;\r
108extern d10 pager_word;\r
109extern int32 flags;\r
110extern const int32 pi_l2bit[8];\r
111extern UNIT cpu_unit;\r
112extern FILE *sim_log;\r
113extern jmp_buf save_env;\r
114extern DEVICE *sim_devices[];\r
115\r
116extern int32 pi_eval (void);\r
117extern int32 rp_inta (void);\r
118extern int32 tu_inta (void);\r
119extern int32 lp20_inta (void);\r
120extern int32 dz_rxinta (void);\r
121extern int32 dz_txinta (void);\r
122\r
123t_stat ubmap_rd (int32 *data, int32 addr, int32 access);\r
124t_stat ubmap_wr (int32 data, int32 addr, int32 access);\r
125t_stat ubs_rd (int32 *data, int32 addr, int32 access);\r
126t_stat ubs_wr (int32 data, int32 addr, int32 access);\r
127t_stat rd_zro (int32 *data, int32 addr, int32 access);\r
128t_stat wr_nop (int32 data, int32 addr, int32 access);\r
129t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
130t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
131t_stat uba_reset (DEVICE *dptr);\r
132d10 ReadIO (a10 ea);\r
133void WriteIO (a10 ea, d10 val, int32 mode);\r
134\r
135/* Unibus adapter data structures\r
136\r
137 uba_dev UBA device descriptor\r
138 uba_unit UBA units\r
139 uba_reg UBA register list\r
140*/\r
141\r
142DIB ubmp1_dib = { IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr, 0 };\r
143DIB ubmp3_dib = { IOBA_UBMAP3, IOLN_UBMAP3, &ubmap_rd, &ubmap_wr, 0 };\r
144DIB ubcs1_dib = { IOBA_UBCS1, IOLN_UBCS1, &ubs_rd, &ubs_wr, 0 };\r
145DIB ubcs3_dib = { IOBA_UBCS3, IOLN_UBCS3, &ubs_rd, &ubs_wr, 0 };\r
146DIB ubmn1_dib = { IOBA_UBMNT1, IOLN_UBMNT1, &rd_zro, &wr_nop, 0 };\r
147DIB ubmn3_dib = { IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop, 0 };\r
148DIB msys_dib = { 00100000, 1, &rd_zro, &wr_nop, 0 };\r
149\r
150UNIT uba_unit[] = {\r
151 { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) },\r
152 { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) }\r
153 };\r
154\r
155REG uba_reg[] = {\r
156 { ORDATA (INTREQ, int_req, 32), REG_RO },\r
157 { ORDATA (UB1CS, ubcs[0], 18) },\r
158 { ORDATA (UB3CS, ubcs[1], 18) },\r
159 { NULL }\r
160 };\r
161\r
162DEVICE uba_dev = {\r
163 "UBA", uba_unit, uba_reg, NULL,\r
164 UBANUM, 8, UMAP_ASIZE, 1, 8, 32,\r
165 &uba_ex, &uba_dep, &uba_reset,\r
166 NULL, NULL, NULL,\r
167 NULL, 0\r
168 };\r
169\r
170/* PDP-11 I/O structures */\r
171\r
172DIB *dib_tab[DIB_MAX]; /* run-time DIBs */\r
173\r
174int32 (*int_ack[32])(void); /* int ack routines */\r
175\r
176int32 int_vec[32]; /* int vectors */\r
177\r
178DIB *std_dib[] = { /* standard DIBs */\r
179 &ubmp1_dib,\r
180 &ubmp3_dib,\r
181 &ubcs1_dib,\r
182 &ubcs3_dib,\r
183 &ubmn1_dib,\r
184 &ubmn3_dib,\r
185 &msys_dib,\r
186 NULL\r
187 };\r
188\r
189/* IO 710 (DEC) TIOE - test I/O word, skip if zero\r
190 (ITS) IORDI - read word from Unibus 3\r
191 returns TRUE if skip, FALSE otherwise\r
192*/\r
193\r
194t_bool io710 (int32 ac, a10 ea)\r
195{\r
196d10 val;\r
197\r
198if (Q_ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */\r
199else { /* TIOE */\r
200 val = ReadIO (ea); /* read word */\r
201 if ((AC(ac) & val) == 0) return TRUE;\r
202 }\r
203return FALSE;\r
204}\r
205\r
206/* IO 711 (DEC) TION - test I/O word, skip if non-zero\r
207 (ITS) IORDQ - read word from Unibus 1\r
208 returns TRUE if skip, FALSE otherwise\r
209*/\r
210\r
211t_bool io711 (int32 ac, a10 ea)\r
212{\r
213d10 val;\r
214\r
215if (Q_ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */\r
216else { /* TION */\r
217 val = ReadIO (ea); /* read word */\r
218 if ((AC(ac) & val) != 0) return TRUE;\r
219 }\r
220return FALSE;\r
221}\r
222\r
223/* IO 712 (DEC) RDIO - read I/O word, addr in ea\r
224 (ITS) IORD - read I/O word, addr in M[ea]\r
225*/\r
226\r
227d10 io712 (a10 ea)\r
228{\r
229return ReadIO (ea); /* RDIO, IORD */\r
230}\r
231\r
232/* IO 713 (DEC) WRIO - write I/O word, addr in ea\r
233 (ITS) IOWR - write I/O word, addr in M[ea]\r
234*/\r
235\r
236void io713 (d10 val, a10 ea)\r
237{\r
238WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */\r
239return;\r
240}\r
241\r
242/* IO 714 (DEC) BSIO - set bit in I/O address\r
243 (ITS) IOWRI - write word to Unibus 3\r
244*/\r
245\r
246void io714 (d10 val, a10 ea)\r
247{\r
248d10 temp;\r
249\r
250val = val & 0177777;\r
251if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */\r
252else {\r
253 temp = ReadIO (ea); /* BSIO */\r
254 temp = temp | val;\r
255 WriteIO (ea, temp, WRITE);\r
256 }\r
257return;\r
258}\r
259\r
260/* IO 715 (DEC) BCIO - clear bit in I/O address\r
261 (ITS) IOWRQ - write word to Unibus 1\r
262*/\r
263\r
264void io715 (d10 val, a10 ea)\r
265{\r
266d10 temp;\r
267\r
268val = val & 0177777;\r
269if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */\r
270else {\r
271 temp = ReadIO (ea); /* BCIO */\r
272 temp = temp & ~val;\r
273 WriteIO (ea, temp, WRITE);\r
274 }\r
275return;\r
276}\r
277\r
278/* IO 720 (DEC) TIOEB - test I/O byte, skip if zero\r
279 (ITS) IORDBI - read byte from Unibus 3\r
280 returns TRUE if skip, FALSE otherwise\r
281*/\r
282\r
283t_bool io720 (int32 ac, a10 ea)\r
284{\r
285d10 val;\r
286\r
287if (Q_ITS) { /* IORDBI */\r
288 val = ReadIO (IO_UBA3 | eaRB);\r
289 AC(ac) = GETBYTE (ea, val);\r
290 }\r
291else { /* TIOEB */\r
292 val = ReadIO (eaRB);\r
293 val = GETBYTE (ea, val);\r
294 if ((AC(ac) & val) == 0) return TRUE;\r
295 }\r
296return FALSE;\r
297}\r
298\r
299/* IO 721 (DEC) TIONB - test I/O word, skip if non-zero\r
300 (ITS) IORDBQ - read word from Unibus 1\r
301 returns TRUE if skip, FALSE otherwise\r
302*/\r
303\r
304t_bool io721 (int32 ac, a10 ea)\r
305{\r
306d10 val;\r
307\r
308if (Q_ITS) { /* IORDBQ */\r
309 val = ReadIO (IO_UBA1 | eaRB);\r
310 AC(ac) = GETBYTE (ea, val);\r
311 }\r
312else { /* TIONB */\r
313 val = ReadIO (eaRB);\r
314 val = GETBYTE (ea, val);\r
315 if ((AC(ac) & val) != 0) return TRUE;\r
316 }\r
317return FALSE;\r
318}\r
319\r
320/* IO 722 (DEC) RDIOB - read I/O byte, addr in ea\r
321 (ITS) IORDB - read I/O byte, addr in M[ea]\r
322*/\r
323\r
324d10 io722 (a10 ea)\r
325{\r
326d10 val;\r
327\r
328val = ReadIO (eaRB); /* RDIOB, IORDB */\r
329return GETBYTE (ea, val);\r
330}\r
331\r
332/* IO 723 (DEC) WRIOB - write I/O byte, addr in ea\r
333 (ITS) IOWRB - write I/O byte, addr in M[ea]\r
334*/\r
335\r
336void io723 (d10 val, a10 ea)\r
337{\r
338WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */\r
339return;\r
340}\r
341\r
342/* IO 724 (DEC) BSIOB - set bit in I/O byte address\r
343 (ITS) IOWRBI - write byte to Unibus 3\r
344*/\r
345\r
346void io724 (d10 val, a10 ea)\r
347{\r
348d10 temp;\r
349\r
350val = val & 0377;\r
351if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */\r
352else {\r
353 temp = ReadIO (eaRB); /* BSIOB */\r
354 temp = GETBYTE (ea, temp);\r
355 temp = temp | val;\r
356 WriteIO (ea, temp, WRITEB);\r
357 }\r
358return;\r
359}\r
360\r
361/* IO 725 (DEC) BCIOB - clear bit in I/O byte address\r
362 (ITS) IOWRBQ - write byte to Unibus 1\r
363*/\r
364\r
365void io725 (d10 val, a10 ea)\r
366{\r
367d10 temp;\r
368\r
369val = val & 0377;\r
370if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */\r
371else {\r
372 temp = ReadIO (eaRB); /* BCIOB */\r
373 temp = GETBYTE (ea, temp);\r
374 temp = temp & ~val;\r
375 WriteIO (ea, temp, WRITEB);\r
376 }\r
377return;\r
378}\r
379\r
380/* Read and write I/O devices.\r
381 These routines are the linkage between the 64b world of the main\r
382 simulator and the 32b world of the device simulators.\r
383*/\r
384\r
385d10 ReadIO (a10 ea)\r
386{\r
387uint32 pa = (uint32) ea;\r
388int32 i, n, val;\r
389DIB *dibp;\r
390\r
391for (i = 0; dibp = dib_tab[i]; i++ ) {\r
392 if ((pa >= dibp->ba) &&\r
393 (pa < (dibp->ba + dibp->lnt))) {\r
394 dibp->rd (&val, pa, READ);\r
395 pi_eval ();\r
396 return ((d10) val);\r
397 }\r
398 }\r
399UBNXM_FAIL (pa, READ);\r
400}\r
401\r
402void WriteIO (a10 ea, d10 val, int32 mode)\r
403{\r
404uint32 pa = (uint32) ea;\r
405int32 i, n;\r
406DIB *dibp;\r
407\r
408for (i = 0; dibp = dib_tab[i]; i++ ) {\r
409 if ((pa >= dibp->ba) &&\r
410 (pa < (dibp->ba + dibp->lnt))) {\r
411 dibp->wr ((int32) val, pa, mode);\r
412 pi_eval ();\r
413 return;\r
414 } \r
415 }\r
416UBNXM_FAIL (pa, mode);\r
417}\r
418\r
419/* Mapped read and write routines - used by standard Unibus devices on Unibus 1 */\r
420\r
421a10 Map_Addr10 (a10 ba, int32 ub)\r
422{\r
423a10 pa10;\r
424int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */\r
425 \r
426if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) ||\r
427 ((ubmap[ub][vpn] & UMAP_VLD) == 0)) return -1; /* invalid map? */\r
428pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;\r
429return pa10;\r
430}\r
431\r
432int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)\r
433{\r
434uint32 lim;\r
435a10 pa10;\r
436\r
437lim = ba + bc;\r
438for ( ; ba < lim; ba++) { /* by bytes */\r
439 pa10 = Map_Addr10 (ba, 1); /* map addr */\r
440 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */\r
441 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */\r
442 return (lim - ba); /* return bc */\r
443 }\r
444 *buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);\r
445 }\r
446return 0;\r
447}\r
448\r
449int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)\r
450{\r
451uint32 lim;\r
452a10 pa10;\r
453\r
454ba = ba & ~01; /* align start */\r
455lim = ba + (bc & ~01);\r
456for ( ; ba < lim; ba = ba + 2) { /* by words */\r
457 pa10 = Map_Addr10 (ba, 1); /* map addr */\r
458 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */\r
459 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */\r
460 return (lim - ba); /* return bc */\r
461 }\r
462 *buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);\r
463 }\r
464return 0;\r
465}\r
466\r
467int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)\r
468{\r
469uint32 lim;\r
470a10 pa10;\r
471d10 mask;\r
472\r
473lim = ba + bc;\r
474for ( ; ba < lim; ba++) { /* by bytes */\r
475 pa10 = Map_Addr10 (ba, 1); /* map addr */\r
476 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */\r
477 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */\r
478 return (lim - ba); /* return bc */\r
479 }\r
480 mask = 0377;\r
481 M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) |\r
482 (((d10) *buf++) << ubashf[ba & 3]);\r
483 }\r
484return 0;\r
485}\r
486\r
487int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)\r
488{\r
489uint32 lim;\r
490a10 pa10;\r
491d10 val;\r
492\r
493ba = ba & ~01; /* align start */\r
494lim = ba + (bc & ~01);\r
495for ( ; ba < lim; ba++) { /* by bytes */\r
496 pa10 = Map_Addr10 (ba, 1); /* map addr */\r
497 if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */\r
498 ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */\r
499 return (lim - ba); /* return bc */\r
500 }\r
501 val = *buf++; /* get data */\r
502 if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val;\r
503 else M[pa10] = (M[pa10] & 0600000777777) | (val << 18);\r
504 }\r
505return 0;\r
506}\r
507\r
508/* Evaluate Unibus priority interrupts */\r
509\r
510int32 pi_ub_eval ()\r
511{\r
512int32 i, lvl;\r
513\r
514for (i = lvl = 0; i < UBANUM; i++) {\r
515 if (int_req & ubabr76[i])\r
516 lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];\r
517 if (int_req & ubabr54[i])\r
518 lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])];\r
519 }\r
520return lvl;\r
521}\r
522\r
523/* Return Unibus device vector\r
524\r
525 Takes as input the request level calculated by pi_eval\r
526 If there is an interrupting Unibus device at that level, return its vector,\r
527 otherwise, returns 0\r
528*/\r
529\r
530int32 pi_ub_vec (int32 rlvl, int32 *uba)\r
531{\r
532int32 i, masked_irq;\r
533\r
534for (i = masked_irq = 0; i < UBANUM; i++) {\r
535 if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */\r
536 (masked_irq = int_req & ubabr76[i])) break;\r
537 if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */\r
538 (masked_irq = int_req & ubabr54[i])) break;\r
539 }\r
540*uba = (i << 1) + 1; /* store uba # */\r
541for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */\r
542 if ((masked_irq >> i) & 1) {\r
543 int_req = int_req & ~(1u << i); /* clear req */\r
544 if (int_ack[i]) return int_ack[i]();\r
545 return int_vec[i]; /* return vector */\r
546 }\r
547 }\r
548return 0;\r
549}\r
550\r
551/* Unibus adapter map routines */\r
552\r
553t_stat ubmap_rd (int32 *val, int32 pa, int32 mode)\r
554{\r
555int32 n = iocmap[GET_IOUBA (pa)];\r
556\r
557if (n < 0) ABORT (STOP_ILLIOC);\r
558*val = ubmap[n][pa & UMAP_AMASK];\r
559return SCPE_OK;\r
560}\r
561\r
562t_stat ubmap_wr (int32 val, int32 pa, int32 mode)\r
563{\r
564int32 n = iocmap[GET_IOUBA (pa)];\r
565\r
566if (n < 0) ABORT (STOP_ILLIOC);\r
567ubmap[n][pa & UMAP_AMASK] = UMAP_POSFL (val) | UMAP_POSPN (val);\r
568return SCPE_OK;\r
569}\r
570\r
571/* Unibus adapter control/status routines */\r
572\r
573t_stat ubs_rd (int32 *val, int32 pa, int32 mode)\r
574{\r
575int32 n = iocmap[GET_IOUBA (pa)];\r
576\r
577if (n < 0) ABORT (STOP_ILLIOC);\r
578if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;\r
579if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;\r
580*val = ubcs[n] = ubcs[n] & ~UBCS_RDZ;\r
581return SCPE_OK;\r
582}\r
583\r
584t_stat ubs_wr (int32 val, int32 pa, int32 mode)\r
585{\r
586int32 n = iocmap[GET_IOUBA (pa)];\r
587\r
588if (n < 0) ABORT (STOP_ILLIOC);\r
589if (val & UBCS_INI) {\r
590 reset_all (5); /* start after UBA */\r
591 ubcs[n] = val & UBCS_DXF;\r
592 }\r
593else ubcs[n] = val & UBCS_RDW;\r
594if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;\r
595if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;\r
596return SCPE_OK;\r
597}\r
598\r
599/* Unibus adapter read zero/write ignore routines */\r
600\r
601t_stat rd_zro (int32 *val, int32 pa, int32 mode)\r
602{\r
603*val = 0;\r
604return SCPE_OK;\r
605}\r
606\r
607t_stat wr_nop (int32 val, int32 pa, int32 mode)\r
608{\r
609return SCPE_OK;\r
610}\r
611\r
612/* Simulator interface routines */\r
613\r
614t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
615{\r
616int32 uba = uptr - uba_unit;\r
617\r
618if (addr >= UMAP_MEMSIZE) return SCPE_NXM;\r
619*vptr = ubmap[uba][addr];\r
620return SCPE_OK;\r
621}\r
622\r
623t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
624{\r
625int32 uba = uptr - uba_unit;\r
626\r
627if (addr >= UMAP_MEMSIZE) return SCPE_NXM;\r
628ubmap[uba][addr] = (int32) val & UMAP_MASK;\r
629return SCPE_OK;\r
630}\r
631\r
632t_stat uba_reset (DEVICE *dptr)\r
633{\r
634int32 i, uba;\r
635\r
636int_req = 0;\r
637for (uba = 0; uba < UBANUM; uba++) {\r
638 ubcs[uba] = 0;\r
639 for (i = 0; i < UMAP_MEMSIZE; i++) ubmap[uba][i] = 0;\r
640 }\r
641pi_eval ();\r
642return SCPE_OK;\r
643}\r
644\r
645/* Change device address */\r
646\r
647t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)\r
648{\r
649DEVICE *dptr;\r
650DIB *dibp;\r
651uint32 newba;\r
652t_stat r;\r
653\r
654if (cptr == NULL) return SCPE_ARG;\r
655if ((val == 0) || (uptr == NULL)) return SCPE_IERR;\r
656dptr = find_dev_from_unit (uptr);\r
657if (dptr == NULL) return SCPE_IERR;\r
658dibp = (DIB *) dptr->ctxt;\r
659if (dibp == NULL) return SCPE_IERR;\r
660newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */\r
661if ((r != SCPE_OK) || (newba == dibp->ba)) return r;\r
662if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;\r
663if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */\r
664if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;\r
665dibp->ba = newba; /* store */\r
666return SCPE_OK;\r
667}\r
668\r
669/* Show device address */\r
670\r
671t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc)\r
672{\r
673DEVICE *dptr;\r
674DIB *dibp;\r
675\r
676if (uptr == NULL) return SCPE_IERR;\r
677dptr = find_dev_from_unit (uptr);\r
678if (dptr == NULL) return SCPE_IERR;\r
679dibp = (DIB *) dptr->ctxt;\r
680if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;\r
681fprintf (st, "address=%07o", dibp->ba);\r
682if (dibp->lnt > 1)\r
683 fprintf (st, "-%07o", dibp->ba + dibp->lnt - 1);\r
684return SCPE_OK;\r
685}\r
686\r
687/* Change device vector */\r
688\r
689t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc)\r
690{\r
691DEVICE *dptr;\r
692DIB *dibp;\r
693uint32 newvec;\r
694t_stat r;\r
695\r
696if (cptr == NULL) return SCPE_ARG;\r
697if (uptr == NULL) return SCPE_IERR;\r
698dptr = find_dev_from_unit (uptr);\r
699if (dptr == NULL) return SCPE_IERR;\r
700dibp = (DIB *) dptr->ctxt;\r
701if (dibp == NULL) return SCPE_IERR;\r
702newvec = (uint32) get_uint (cptr, 8, VEC_Q + 01000, &r);\r
703if ((r != SCPE_OK) || (newvec == VEC_Q) ||\r
704 ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) ||\r
705 (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG;\r
706dibp->vec = newvec;\r
707return SCPE_OK;\r
708}\r
709\r
710/* Show device vector */\r
711\r
712t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc)\r
713{\r
714DEVICE *dptr;\r
715DIB *dibp;\r
716uint32 vec, numvec;\r
717\r
718if (uptr == NULL) return SCPE_IERR;\r
719dptr = find_dev_from_unit (uptr);\r
720if (dptr == NULL) return SCPE_IERR;\r
721dibp = (DIB *) dptr->ctxt;\r
722if (dibp == NULL) return SCPE_IERR;\r
723vec = dibp->vec;\r
724if (arg) numvec = arg;\r
725else numvec = dibp->vnum;\r
726if (vec == 0) fprintf (st, "no vector");\r
727else {\r
728 fprintf (st, "vector=%o", vec);\r
729 if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1)));\r
730 }\r
731return SCPE_OK;\r
732}\r
733\r
734/* Test for conflict in device addresses */\r
735\r
736t_bool dev_conflict (DIB *curr)\r
737{\r
738uint32 i, end;\r
739DEVICE *dptr;\r
740DIB *dibp;\r
741\r
742end = curr->ba + curr->lnt - 1; /* get end */\r
743for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */\r
744 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
745 if ((dibp == NULL) || (dibp == curr) ||\r
746 (dptr->flags & DEV_DIS)) continue;\r
747 if (((curr->ba >= dibp->ba) && /* overlap start? */\r
748 (curr->ba < (dibp->ba + dibp->lnt))) ||\r
749 ((end >= dibp->ba) && /* overlap end? */\r
750 (end < (dibp->ba + dibp->lnt)))) {\r
751 printf ("Device %s address conflict at %08o\n",\r
752 sim_dname (dptr), dibp->ba);\r
753 if (sim_log) fprintf (sim_log,\r
754 "Device %s address conflict at %08o\n",\r
755 sim_dname (dptr), dibp->ba);\r
756 return TRUE;\r
757 }\r
758 }\r
759return FALSE;\r
760}\r
761\r
762/* Build interrupt tables */\r
763\r
764void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) )\r
765{\r
766if (iack != NULL) int_ack[vloc] = iack;\r
767else int_vec[vloc] = ivec;\r
768return;\r
769}\r
770\r
771/* Build dib_tab from device list */\r
772\r
773t_bool build_dib_tab (void)\r
774{\r
775int32 i, j, k;\r
776DEVICE *dptr;\r
777DIB *dibp;\r
778\r
779for (i = 0; i < 32; i++) { /* clear intr tables */\r
780 int_vec[i] = 0;\r
781 int_ack[i] = NULL;\r
782 }\r
783for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */\r
784 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
785 if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */\r
786 if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;\r
787 for (k = 0; k < dibp->vnum; k++) /* loop thru vec */\r
788 build_int_vec (dibp->vloc + k, /* add vector */\r
789 dibp->vec + (k * 4), dibp->ack[k]);\r
790 if (dibp->lnt != 0) { /* I/O addresses? */\r
791 dib_tab[j++] = dibp; /* add DIB to dib_tab */\r
792 if (j >= DIB_MAX) return SCPE_IERR; /* too many? */\r
793 } \r
794 } /* end if enabled */\r
795 } /* end for */\r
796for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */\r
797 dib_tab[j++] = dibp; /* add to dib_tab */\r
798 if (j >= DIB_MAX) return SCPE_IERR; /* too many? */\r
799 }\r
800dib_tab[j] = NULL; /* end with NULL */\r
801for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */\r
802 if (dev_conflict (dibp)) return SCPE_STOP; /* for conflicts */\r
803 }\r
804return SCPE_OK;\r
805}\r
806\r
807/* Show dib_tab */\r
808\r
809t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc)\r
810{\r
811int32 i, j, done = 0;\r
812DEVICE *dptr;\r
813DIB *dibt;\r
814\r
815build_dib_tab (); /* build table */\r
816while (done == 0) { /* sort ascending */\r
817 done = 1; /* assume done */\r
818 for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */\r
819 if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */\r
820 dibt = dib_tab[i]; /* interchange */\r
821 dib_tab[i] = dib_tab[i + 1];\r
822 dib_tab[i + 1] = dibt;\r
823 done = 0; /* not done */\r
824 }\r
825 }\r
826 } /* end while */\r
827for (i = 0; dib_tab[i] != NULL; i++) { /* print table */\r
828 for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {\r
829 if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) {\r
830 dptr = sim_devices[j];\r
831 break;\r
832 }\r
833 }\r
834 fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba,\r
835 dib_tab[i]->ba + dib_tab[i]->lnt - 1,\r
836 dptr? sim_dname (dptr): "CPU");\r
837 }\r
838return SCPE_OK;\r
839}\r
840\r
841/* Stub auto-configure */\r
842\r
843t_stat auto_config (char *name, int32 num)\r
844{\r
845return SCPE_OK;\r
846}\r
847\r
848/* Stub floating address */\r
849\r
850t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc)\r
851{\r
852return SCPE_OK;\r
853}\r