Commit | Line | Data |
---|---|---|
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 | |
88 | int32 ubcs[UBANUM] = { 0 }; /* status registers */\r | |
89 | int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */\r | |
90 | int32 int_req = 0; /* interrupt requests */\r | |
91 | \r | |
92 | /* Map IO controller numbers to Unibus adapters: -1 = non-existent */\r | |
93 | \r | |
94 | static 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 | |
98 | static const int32 ubabr76[UBANUM] = {\r | |
99 | INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6)\r | |
100 | };\r | |
101 | static const int32 ubabr54[UBANUM] = {\r | |
102 | INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4)\r | |
103 | };\r | |
104 | static const int32 ubashf[4] = { 18, 26, 0, 8 };\r | |
105 | \r | |
106 | extern d10 *M; /* main memory */\r | |
107 | extern d10 *ac_cur;\r | |
108 | extern d10 pager_word;\r | |
109 | extern int32 flags;\r | |
110 | extern const int32 pi_l2bit[8];\r | |
111 | extern UNIT cpu_unit;\r | |
112 | extern FILE *sim_log;\r | |
113 | extern jmp_buf save_env;\r | |
114 | extern DEVICE *sim_devices[];\r | |
115 | \r | |
116 | extern int32 pi_eval (void);\r | |
117 | extern int32 rp_inta (void);\r | |
118 | extern int32 tu_inta (void);\r | |
119 | extern int32 lp20_inta (void);\r | |
120 | extern int32 dz_rxinta (void);\r | |
121 | extern int32 dz_txinta (void);\r | |
122 | \r | |
123 | t_stat ubmap_rd (int32 *data, int32 addr, int32 access);\r | |
124 | t_stat ubmap_wr (int32 data, int32 addr, int32 access);\r | |
125 | t_stat ubs_rd (int32 *data, int32 addr, int32 access);\r | |
126 | t_stat ubs_wr (int32 data, int32 addr, int32 access);\r | |
127 | t_stat rd_zro (int32 *data, int32 addr, int32 access);\r | |
128 | t_stat wr_nop (int32 data, int32 addr, int32 access);\r | |
129 | t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r | |
130 | t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r | |
131 | t_stat uba_reset (DEVICE *dptr);\r | |
132 | d10 ReadIO (a10 ea);\r | |
133 | void 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 | |
142 | DIB ubmp1_dib = { IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr, 0 };\r | |
143 | DIB ubmp3_dib = { IOBA_UBMAP3, IOLN_UBMAP3, &ubmap_rd, &ubmap_wr, 0 };\r | |
144 | DIB ubcs1_dib = { IOBA_UBCS1, IOLN_UBCS1, &ubs_rd, &ubs_wr, 0 };\r | |
145 | DIB ubcs3_dib = { IOBA_UBCS3, IOLN_UBCS3, &ubs_rd, &ubs_wr, 0 };\r | |
146 | DIB ubmn1_dib = { IOBA_UBMNT1, IOLN_UBMNT1, &rd_zro, &wr_nop, 0 };\r | |
147 | DIB ubmn3_dib = { IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop, 0 };\r | |
148 | DIB msys_dib = { 00100000, 1, &rd_zro, &wr_nop, 0 };\r | |
149 | \r | |
150 | UNIT uba_unit[] = {\r | |
151 | { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) },\r | |
152 | { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) }\r | |
153 | };\r | |
154 | \r | |
155 | REG 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 | |
162 | DEVICE 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 | |
172 | DIB *dib_tab[DIB_MAX]; /* run-time DIBs */\r | |
173 | \r | |
174 | int32 (*int_ack[32])(void); /* int ack routines */\r | |
175 | \r | |
176 | int32 int_vec[32]; /* int vectors */\r | |
177 | \r | |
178 | DIB *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 | |
194 | t_bool io710 (int32 ac, a10 ea)\r | |
195 | {\r | |
196 | d10 val;\r | |
197 | \r | |
198 | if (Q_ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */\r | |
199 | else { /* TIOE */\r | |
200 | val = ReadIO (ea); /* read word */\r | |
201 | if ((AC(ac) & val) == 0) return TRUE;\r | |
202 | }\r | |
203 | return 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 | |
211 | t_bool io711 (int32 ac, a10 ea)\r | |
212 | {\r | |
213 | d10 val;\r | |
214 | \r | |
215 | if (Q_ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */\r | |
216 | else { /* TION */\r | |
217 | val = ReadIO (ea); /* read word */\r | |
218 | if ((AC(ac) & val) != 0) return TRUE;\r | |
219 | }\r | |
220 | return 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 | |
227 | d10 io712 (a10 ea)\r | |
228 | {\r | |
229 | return 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 | |
236 | void io713 (d10 val, a10 ea)\r | |
237 | {\r | |
238 | WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */\r | |
239 | return;\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 | |
246 | void io714 (d10 val, a10 ea)\r | |
247 | {\r | |
248 | d10 temp;\r | |
249 | \r | |
250 | val = val & 0177777;\r | |
251 | if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */\r | |
252 | else {\r | |
253 | temp = ReadIO (ea); /* BSIO */\r | |
254 | temp = temp | val;\r | |
255 | WriteIO (ea, temp, WRITE);\r | |
256 | }\r | |
257 | return;\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 | |
264 | void io715 (d10 val, a10 ea)\r | |
265 | {\r | |
266 | d10 temp;\r | |
267 | \r | |
268 | val = val & 0177777;\r | |
269 | if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */\r | |
270 | else {\r | |
271 | temp = ReadIO (ea); /* BCIO */\r | |
272 | temp = temp & ~val;\r | |
273 | WriteIO (ea, temp, WRITE);\r | |
274 | }\r | |
275 | return;\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 | |
283 | t_bool io720 (int32 ac, a10 ea)\r | |
284 | {\r | |
285 | d10 val;\r | |
286 | \r | |
287 | if (Q_ITS) { /* IORDBI */\r | |
288 | val = ReadIO (IO_UBA3 | eaRB);\r | |
289 | AC(ac) = GETBYTE (ea, val);\r | |
290 | }\r | |
291 | else { /* TIOEB */\r | |
292 | val = ReadIO (eaRB);\r | |
293 | val = GETBYTE (ea, val);\r | |
294 | if ((AC(ac) & val) == 0) return TRUE;\r | |
295 | }\r | |
296 | return 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 | |
304 | t_bool io721 (int32 ac, a10 ea)\r | |
305 | {\r | |
306 | d10 val;\r | |
307 | \r | |
308 | if (Q_ITS) { /* IORDBQ */\r | |
309 | val = ReadIO (IO_UBA1 | eaRB);\r | |
310 | AC(ac) = GETBYTE (ea, val);\r | |
311 | }\r | |
312 | else { /* TIONB */\r | |
313 | val = ReadIO (eaRB);\r | |
314 | val = GETBYTE (ea, val);\r | |
315 | if ((AC(ac) & val) != 0) return TRUE;\r | |
316 | }\r | |
317 | return 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 | |
324 | d10 io722 (a10 ea)\r | |
325 | {\r | |
326 | d10 val;\r | |
327 | \r | |
328 | val = ReadIO (eaRB); /* RDIOB, IORDB */\r | |
329 | return 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 | |
336 | void io723 (d10 val, a10 ea)\r | |
337 | {\r | |
338 | WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */\r | |
339 | return;\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 | |
346 | void io724 (d10 val, a10 ea)\r | |
347 | {\r | |
348 | d10 temp;\r | |
349 | \r | |
350 | val = val & 0377;\r | |
351 | if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */\r | |
352 | else {\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 | |
358 | return;\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 | |
365 | void io725 (d10 val, a10 ea)\r | |
366 | {\r | |
367 | d10 temp;\r | |
368 | \r | |
369 | val = val & 0377;\r | |
370 | if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */\r | |
371 | else {\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 | |
377 | return;\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 | |
385 | d10 ReadIO (a10 ea)\r | |
386 | {\r | |
387 | uint32 pa = (uint32) ea;\r | |
388 | int32 i, n, val;\r | |
389 | DIB *dibp;\r | |
390 | \r | |
391 | for (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 | |
399 | UBNXM_FAIL (pa, READ);\r | |
400 | }\r | |
401 | \r | |
402 | void WriteIO (a10 ea, d10 val, int32 mode)\r | |
403 | {\r | |
404 | uint32 pa = (uint32) ea;\r | |
405 | int32 i, n;\r | |
406 | DIB *dibp;\r | |
407 | \r | |
408 | for (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 | |
416 | UBNXM_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 | |
421 | a10 Map_Addr10 (a10 ba, int32 ub)\r | |
422 | {\r | |
423 | a10 pa10;\r | |
424 | int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */\r | |
425 | \r | |
426 | if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) ||\r | |
427 | ((ubmap[ub][vpn] & UMAP_VLD) == 0)) return -1; /* invalid map? */\r | |
428 | pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;\r | |
429 | return pa10;\r | |
430 | }\r | |
431 | \r | |
432 | int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)\r | |
433 | {\r | |
434 | uint32 lim;\r | |
435 | a10 pa10;\r | |
436 | \r | |
437 | lim = ba + bc;\r | |
438 | for ( ; 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 | |
446 | return 0;\r | |
447 | }\r | |
448 | \r | |
449 | int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)\r | |
450 | {\r | |
451 | uint32 lim;\r | |
452 | a10 pa10;\r | |
453 | \r | |
454 | ba = ba & ~01; /* align start */\r | |
455 | lim = ba + (bc & ~01);\r | |
456 | for ( ; 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 | |
464 | return 0;\r | |
465 | }\r | |
466 | \r | |
467 | int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)\r | |
468 | {\r | |
469 | uint32 lim;\r | |
470 | a10 pa10;\r | |
471 | d10 mask;\r | |
472 | \r | |
473 | lim = ba + bc;\r | |
474 | for ( ; 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 | |
484 | return 0;\r | |
485 | }\r | |
486 | \r | |
487 | int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)\r | |
488 | {\r | |
489 | uint32 lim;\r | |
490 | a10 pa10;\r | |
491 | d10 val;\r | |
492 | \r | |
493 | ba = ba & ~01; /* align start */\r | |
494 | lim = ba + (bc & ~01);\r | |
495 | for ( ; 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 | |
505 | return 0;\r | |
506 | }\r | |
507 | \r | |
508 | /* Evaluate Unibus priority interrupts */\r | |
509 | \r | |
510 | int32 pi_ub_eval ()\r | |
511 | {\r | |
512 | int32 i, lvl;\r | |
513 | \r | |
514 | for (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 | |
520 | return 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 | |
530 | int32 pi_ub_vec (int32 rlvl, int32 *uba)\r | |
531 | {\r | |
532 | int32 i, masked_irq;\r | |
533 | \r | |
534 | for (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 | |
541 | for (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 | |
548 | return 0;\r | |
549 | }\r | |
550 | \r | |
551 | /* Unibus adapter map routines */\r | |
552 | \r | |
553 | t_stat ubmap_rd (int32 *val, int32 pa, int32 mode)\r | |
554 | {\r | |
555 | int32 n = iocmap[GET_IOUBA (pa)];\r | |
556 | \r | |
557 | if (n < 0) ABORT (STOP_ILLIOC);\r | |
558 | *val = ubmap[n][pa & UMAP_AMASK];\r | |
559 | return SCPE_OK;\r | |
560 | }\r | |
561 | \r | |
562 | t_stat ubmap_wr (int32 val, int32 pa, int32 mode)\r | |
563 | {\r | |
564 | int32 n = iocmap[GET_IOUBA (pa)];\r | |
565 | \r | |
566 | if (n < 0) ABORT (STOP_ILLIOC);\r | |
567 | ubmap[n][pa & UMAP_AMASK] = UMAP_POSFL (val) | UMAP_POSPN (val);\r | |
568 | return SCPE_OK;\r | |
569 | }\r | |
570 | \r | |
571 | /* Unibus adapter control/status routines */\r | |
572 | \r | |
573 | t_stat ubs_rd (int32 *val, int32 pa, int32 mode)\r | |
574 | {\r | |
575 | int32 n = iocmap[GET_IOUBA (pa)];\r | |
576 | \r | |
577 | if (n < 0) ABORT (STOP_ILLIOC);\r | |
578 | if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;\r | |
579 | if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;\r | |
580 | *val = ubcs[n] = ubcs[n] & ~UBCS_RDZ;\r | |
581 | return SCPE_OK;\r | |
582 | }\r | |
583 | \r | |
584 | t_stat ubs_wr (int32 val, int32 pa, int32 mode)\r | |
585 | {\r | |
586 | int32 n = iocmap[GET_IOUBA (pa)];\r | |
587 | \r | |
588 | if (n < 0) ABORT (STOP_ILLIOC);\r | |
589 | if (val & UBCS_INI) {\r | |
590 | reset_all (5); /* start after UBA */\r | |
591 | ubcs[n] = val & UBCS_DXF;\r | |
592 | }\r | |
593 | else ubcs[n] = val & UBCS_RDW;\r | |
594 | if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;\r | |
595 | if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;\r | |
596 | return SCPE_OK;\r | |
597 | }\r | |
598 | \r | |
599 | /* Unibus adapter read zero/write ignore routines */\r | |
600 | \r | |
601 | t_stat rd_zro (int32 *val, int32 pa, int32 mode)\r | |
602 | {\r | |
603 | *val = 0;\r | |
604 | return SCPE_OK;\r | |
605 | }\r | |
606 | \r | |
607 | t_stat wr_nop (int32 val, int32 pa, int32 mode)\r | |
608 | {\r | |
609 | return SCPE_OK;\r | |
610 | }\r | |
611 | \r | |
612 | /* Simulator interface routines */\r | |
613 | \r | |
614 | t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r | |
615 | {\r | |
616 | int32 uba = uptr - uba_unit;\r | |
617 | \r | |
618 | if (addr >= UMAP_MEMSIZE) return SCPE_NXM;\r | |
619 | *vptr = ubmap[uba][addr];\r | |
620 | return SCPE_OK;\r | |
621 | }\r | |
622 | \r | |
623 | t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r | |
624 | {\r | |
625 | int32 uba = uptr - uba_unit;\r | |
626 | \r | |
627 | if (addr >= UMAP_MEMSIZE) return SCPE_NXM;\r | |
628 | ubmap[uba][addr] = (int32) val & UMAP_MASK;\r | |
629 | return SCPE_OK;\r | |
630 | }\r | |
631 | \r | |
632 | t_stat uba_reset (DEVICE *dptr)\r | |
633 | {\r | |
634 | int32 i, uba;\r | |
635 | \r | |
636 | int_req = 0;\r | |
637 | for (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 | |
641 | pi_eval ();\r | |
642 | return SCPE_OK;\r | |
643 | }\r | |
644 | \r | |
645 | /* Change device address */\r | |
646 | \r | |
647 | t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
648 | {\r | |
649 | DEVICE *dptr;\r | |
650 | DIB *dibp;\r | |
651 | uint32 newba;\r | |
652 | t_stat r;\r | |
653 | \r | |
654 | if (cptr == NULL) return SCPE_ARG;\r | |
655 | if ((val == 0) || (uptr == NULL)) return SCPE_IERR;\r | |
656 | dptr = find_dev_from_unit (uptr);\r | |
657 | if (dptr == NULL) return SCPE_IERR;\r | |
658 | dibp = (DIB *) dptr->ctxt;\r | |
659 | if (dibp == NULL) return SCPE_IERR;\r | |
660 | newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */\r | |
661 | if ((r != SCPE_OK) || (newba == dibp->ba)) return r;\r | |
662 | if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;\r | |
663 | if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */\r | |
664 | if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;\r | |
665 | dibp->ba = newba; /* store */\r | |
666 | return SCPE_OK;\r | |
667 | }\r | |
668 | \r | |
669 | /* Show device address */\r | |
670 | \r | |
671 | t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
672 | {\r | |
673 | DEVICE *dptr;\r | |
674 | DIB *dibp;\r | |
675 | \r | |
676 | if (uptr == NULL) return SCPE_IERR;\r | |
677 | dptr = find_dev_from_unit (uptr);\r | |
678 | if (dptr == NULL) return SCPE_IERR;\r | |
679 | dibp = (DIB *) dptr->ctxt;\r | |
680 | if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;\r | |
681 | fprintf (st, "address=%07o", dibp->ba);\r | |
682 | if (dibp->lnt > 1)\r | |
683 | fprintf (st, "-%07o", dibp->ba + dibp->lnt - 1);\r | |
684 | return SCPE_OK;\r | |
685 | }\r | |
686 | \r | |
687 | /* Change device vector */\r | |
688 | \r | |
689 | t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc)\r | |
690 | {\r | |
691 | DEVICE *dptr;\r | |
692 | DIB *dibp;\r | |
693 | uint32 newvec;\r | |
694 | t_stat r;\r | |
695 | \r | |
696 | if (cptr == NULL) return SCPE_ARG;\r | |
697 | if (uptr == NULL) return SCPE_IERR;\r | |
698 | dptr = find_dev_from_unit (uptr);\r | |
699 | if (dptr == NULL) return SCPE_IERR;\r | |
700 | dibp = (DIB *) dptr->ctxt;\r | |
701 | if (dibp == NULL) return SCPE_IERR;\r | |
702 | newvec = (uint32) get_uint (cptr, 8, VEC_Q + 01000, &r);\r | |
703 | if ((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 | |
706 | dibp->vec = newvec;\r | |
707 | return SCPE_OK;\r | |
708 | }\r | |
709 | \r | |
710 | /* Show device vector */\r | |
711 | \r | |
712 | t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc)\r | |
713 | {\r | |
714 | DEVICE *dptr;\r | |
715 | DIB *dibp;\r | |
716 | uint32 vec, numvec;\r | |
717 | \r | |
718 | if (uptr == NULL) return SCPE_IERR;\r | |
719 | dptr = find_dev_from_unit (uptr);\r | |
720 | if (dptr == NULL) return SCPE_IERR;\r | |
721 | dibp = (DIB *) dptr->ctxt;\r | |
722 | if (dibp == NULL) return SCPE_IERR;\r | |
723 | vec = dibp->vec;\r | |
724 | if (arg) numvec = arg;\r | |
725 | else numvec = dibp->vnum;\r | |
726 | if (vec == 0) fprintf (st, "no vector");\r | |
727 | else {\r | |
728 | fprintf (st, "vector=%o", vec);\r | |
729 | if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1)));\r | |
730 | }\r | |
731 | return SCPE_OK;\r | |
732 | }\r | |
733 | \r | |
734 | /* Test for conflict in device addresses */\r | |
735 | \r | |
736 | t_bool dev_conflict (DIB *curr)\r | |
737 | {\r | |
738 | uint32 i, end;\r | |
739 | DEVICE *dptr;\r | |
740 | DIB *dibp;\r | |
741 | \r | |
742 | end = curr->ba + curr->lnt - 1; /* get end */\r | |
743 | for (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 | |
759 | return FALSE;\r | |
760 | }\r | |
761 | \r | |
762 | /* Build interrupt tables */\r | |
763 | \r | |
764 | void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) )\r | |
765 | {\r | |
766 | if (iack != NULL) int_ack[vloc] = iack;\r | |
767 | else int_vec[vloc] = ivec;\r | |
768 | return;\r | |
769 | }\r | |
770 | \r | |
771 | /* Build dib_tab from device list */\r | |
772 | \r | |
773 | t_bool build_dib_tab (void)\r | |
774 | {\r | |
775 | int32 i, j, k;\r | |
776 | DEVICE *dptr;\r | |
777 | DIB *dibp;\r | |
778 | \r | |
779 | for (i = 0; i < 32; i++) { /* clear intr tables */\r | |
780 | int_vec[i] = 0;\r | |
781 | int_ack[i] = NULL;\r | |
782 | }\r | |
783 | for (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 | |
796 | for (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 | |
800 | dib_tab[j] = NULL; /* end with NULL */\r | |
801 | for (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 | |
804 | return SCPE_OK;\r | |
805 | }\r | |
806 | \r | |
807 | /* Show dib_tab */\r | |
808 | \r | |
809 | t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
810 | {\r | |
811 | int32 i, j, done = 0;\r | |
812 | DEVICE *dptr;\r | |
813 | DIB *dibt;\r | |
814 | \r | |
815 | build_dib_tab (); /* build table */\r | |
816 | while (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 | |
827 | for (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 | |
838 | return SCPE_OK;\r | |
839 | }\r | |
840 | \r | |
841 | /* Stub auto-configure */\r | |
842 | \r | |
843 | t_stat auto_config (char *name, int32 num)\r | |
844 | {\r | |
845 | return SCPE_OK;\r | |
846 | }\r | |
847 | \r | |
848 | /* Stub floating address */\r | |
849 | \r | |
850 | t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
851 | {\r | |
852 | return SCPE_OK;\r | |
853 | }\r |