Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* hp2100_ipl.c: HP 2000 interprocessor link simulator\r |
2 | \r | |
3 | Copyright (c) 2002-2007, 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 | ipli, iplo 12875A interprocessor link\r | |
27 | \r | |
28 | 01-Mar-07 JDB IPLI EDT delays DMA completion interrupt for TSB\r | |
29 | Added debug printouts\r | |
30 | 28-Dec-06 JDB Added ioCRS state to I/O decoders\r | |
31 | 16-Aug-05 RMS Fixed C++ declaration and cast problems\r | |
32 | 07-Oct-04 JDB Fixed enable/disable from either device\r | |
33 | 26-Apr-04 RMS Fixed SFS x,C and SFC x,C\r | |
34 | Implemented DMA SRQ (follows FLG)\r | |
35 | 21-Dec-03 RMS Adjusted ipl_ptime for TSB (from Mike Gemeny)\r | |
36 | 09-May-03 RMS Added network device flag\r | |
37 | 31-Jan-03 RMS Links are full duplex (found by Mike Gemeny)\r | |
38 | \r | |
39 | The 12875A Processor Interconnect Kit consists four 12566A Microcircuit\r | |
40 | Interface cards. Two are used in each processor. One card in each system is\r | |
41 | used to initiate transmissions to the other, and the second card is used to\r | |
42 | receive transmissions from the other. Each pair of cards forms a\r | |
43 | bidirectional link, as the sixteen data lines are cross-connected, so that\r | |
44 | data sent and status returned are supported. In each processor, data is sent\r | |
45 | on the lower priority card and received on the higher priority card. Two\r | |
46 | sets of cards are used to support simultaneous transmission in both\r | |
47 | directions.\r | |
48 | \r | |
49 | Reference:\r | |
50 | - 12875A Processor Interconnect Kit Operating and Service Manual\r | |
51 | (12875-90002, Jan-1974)\r | |
52 | */\r | |
53 | \r | |
54 | #include "hp2100_defs.h"\r | |
55 | #include "sim_sock.h"\r | |
56 | #include "sim_tmxr.h"\r | |
57 | \r | |
58 | #define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */\r | |
59 | #define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */\r | |
60 | #define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */\r | |
61 | #define UNIT_V_HOLD (UNIT_V_UF + 3) /* character holding */\r | |
62 | #define UNIT_DIAG (1 << UNIT_V_DIAG)\r | |
63 | #define UNIT_ACTV (1 << UNIT_V_ACTV)\r | |
64 | #define UNIT_ESTB (1 << UNIT_V_ESTB)\r | |
65 | #define UNIT_HOLD (1 << UNIT_V_HOLD)\r | |
66 | #define IBUF buf /* input buffer */\r | |
67 | #define OBUF wait /* output buffer */\r | |
68 | #define DSOCKET u3 /* data socket */\r | |
69 | #define LSOCKET u4 /* listening socket */\r | |
70 | \r | |
71 | /* Debug flags */\r | |
72 | \r | |
73 | #define DEB_CMDS (1 << 0) /* Command initiation and completion */\r | |
74 | #define DEB_CPU (1 << 1) /* CPU I/O */\r | |
75 | #define DEB_XFER (1 << 2) /* Socket receive and transmit */\r | |
76 | \r | |
77 | extern uint32 PC;\r | |
78 | extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r | |
79 | extern FILE *sim_log;\r | |
80 | extern FILE *sim_deb;\r | |
81 | int32 ipl_edtdelay = 1; /* EDT delay (msec) */\r | |
82 | int32 ipl_ptime = 31; /* polling interval */\r | |
83 | int32 ipl_stopioe = 0; /* stop on error */\r | |
84 | int32 ipl_hold[2] = { 0 }; /* holding character */\r | |
85 | \r | |
86 | DEVICE ipli_dev, iplo_dev;\r | |
87 | int32 ipliio (int32 inst, int32 IR, int32 dat);\r | |
88 | int32 iploio (int32 inst, int32 IR, int32 dat);\r | |
89 | int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat);\r | |
90 | t_stat ipl_svc (UNIT *uptr);\r | |
91 | t_stat ipl_reset (DEVICE *dptr);\r | |
92 | t_stat ipl_attach (UNIT *uptr, char *cptr);\r | |
93 | t_stat ipl_detach (UNIT *uptr);\r | |
94 | t_stat ipl_boot (int32 unitno, DEVICE *dptr);\r | |
95 | t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
96 | t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
97 | t_bool ipl_check_conn (UNIT *uptr);\r | |
98 | \r | |
99 | /* Debug flags table */\r | |
100 | \r | |
101 | DEBTAB ipl_deb[] = {\r | |
102 | { "CMDS", DEB_CMDS },\r | |
103 | { "CPU", DEB_CPU },\r | |
104 | { "XFER", DEB_XFER },\r | |
105 | { NULL, 0 } };\r | |
106 | \r | |
107 | /* IPLI data structures\r | |
108 | \r | |
109 | ipli_dev IPLI device descriptor\r | |
110 | ipli_unit IPLI unit descriptor\r | |
111 | ipli_reg IPLI register list\r | |
112 | */\r | |
113 | \r | |
114 | DIB ipl_dib[] = {\r | |
115 | { IPLI, 0, 0, 0, 0, 0, &ipliio },\r | |
116 | { IPLO, 0, 0, 0, 0, 0, &iploio }\r | |
117 | };\r | |
118 | \r | |
119 | #define ipli_dib ipl_dib[0]\r | |
120 | #define iplo_dib ipl_dib[1]\r | |
121 | \r | |
122 | UNIT ipl_unit[] = {\r | |
123 | { UDATA (&ipl_svc, UNIT_ATTABLE, 0) },\r | |
124 | { UDATA (&ipl_svc, UNIT_ATTABLE, 0) }\r | |
125 | };\r | |
126 | \r | |
127 | #define ipli_unit ipl_unit[0]\r | |
128 | #define iplo_unit ipl_unit[1]\r | |
129 | \r | |
130 | REG ipli_reg[] = {\r | |
131 | { ORDATA (IBUF, ipli_unit.IBUF, 16) },\r | |
132 | { ORDATA (OBUF, ipli_unit.OBUF, 16) },\r | |
133 | { FLDATA (CMD, ipli_dib.cmd, 0) },\r | |
134 | { FLDATA (CTL, ipli_dib.ctl, 0) },\r | |
135 | { FLDATA (FLG, ipli_dib.flg, 0) },\r | |
136 | { FLDATA (FBF, ipli_dib.fbf, 0) },\r | |
137 | { FLDATA (SRQ, ipli_dib.srq, 0) },\r | |
138 | { ORDATA (HOLD, ipl_hold[0], 8) },\r | |
139 | { DRDATA (TIME, ipl_ptime, 24), PV_LEFT },\r | |
140 | { FLDATA (STOP_IOE, ipl_stopioe, 0) },\r | |
141 | { ORDATA (DEVNO, ipli_dib.devno, 6), REG_HRO },\r | |
142 | { NULL }\r | |
143 | };\r | |
144 | \r | |
145 | MTAB ipl_mod[] = {\r | |
146 | { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag },\r | |
147 | { UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag },\r | |
148 | { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT",\r | |
149 | &ipl_dscln, NULL, NULL },\r | |
150 | { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",\r | |
151 | &hp_setdev, &hp_showdev, &ipli_dev },\r | |
152 | { 0 }\r | |
153 | };\r | |
154 | \r | |
155 | DEVICE ipli_dev = {\r | |
156 | "IPLI", &ipli_unit, ipli_reg, ipl_mod,\r | |
157 | 1, 10, 31, 1, 16, 16,\r | |
158 | &tmxr_ex, &tmxr_dep, &ipl_reset,\r | |
159 | &ipl_boot, &ipl_attach, &ipl_detach,\r | |
160 | &ipli_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG,\r | |
161 | 0, ipl_deb, NULL, NULL\r | |
162 | };\r | |
163 | \r | |
164 | /* IPLO data structures\r | |
165 | \r | |
166 | iplo_dev IPLO device descriptor\r | |
167 | iplo_unit IPLO unit descriptor\r | |
168 | iplo_reg IPLO register list\r | |
169 | */\r | |
170 | \r | |
171 | REG iplo_reg[] = {\r | |
172 | { ORDATA (IBUF, iplo_unit.IBUF, 16) },\r | |
173 | { ORDATA (OBUF, iplo_unit.OBUF, 16) },\r | |
174 | { FLDATA (CMD, iplo_dib.cmd, 0) },\r | |
175 | { FLDATA (CTL, iplo_dib.ctl, 0) },\r | |
176 | { FLDATA (FLG, iplo_dib.flg, 0) },\r | |
177 | { FLDATA (FBF, iplo_dib.fbf, 0) },\r | |
178 | { FLDATA (SRQ, iplo_dib.srq, 0) },\r | |
179 | { ORDATA (HOLD, ipl_hold[1], 8) },\r | |
180 | { DRDATA (TIME, ipl_ptime, 24), PV_LEFT },\r | |
181 | { ORDATA (DEVNO, iplo_dib.devno, 6), REG_HRO },\r | |
182 | { NULL }\r | |
183 | };\r | |
184 | \r | |
185 | DEVICE iplo_dev = {\r | |
186 | "IPLO", &iplo_unit, iplo_reg, ipl_mod,\r | |
187 | 1, 10, 31, 1, 16, 16,\r | |
188 | &tmxr_ex, &tmxr_dep, &ipl_reset,\r | |
189 | &ipl_boot, &ipl_attach, &ipl_detach,\r | |
190 | &iplo_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG,\r | |
191 | 0, ipl_deb, NULL, NULL\r | |
192 | };\r | |
193 | \r | |
194 | /* I/O instructions */\r | |
195 | \r | |
196 | int32 ipliio (int32 inst, int32 IR, int32 dat)\r | |
197 | {\r | |
198 | return iplio (&ipli_unit, inst, IR, dat);\r | |
199 | }\r | |
200 | \r | |
201 | int32 iploio (int32 inst, int32 IR, int32 dat)\r | |
202 | {\r | |
203 | return iplio (&iplo_unit, inst, IR, dat);\r | |
204 | }\r | |
205 | \r | |
206 | /* I/O handler for the IPLI and IPLO devices.\r | |
207 | \r | |
208 | Implementation note: 2000 Access has a race condition that manifests itself\r | |
209 | by an apparently normal boot and operational system console but no PLEASE LOG\r | |
210 | IN response to terminals connected to the multiplexer. The frequency of\r | |
211 | occurrence is higher on multiprocessor host systems, where the SP and IOP\r | |
212 | instances may execute concurrently.\r | |
213 | \r | |
214 | The cause is this code in the SP disc loader source (2883.asm, 7900.asm,\r | |
215 | 790X.asm, 79X3.asm, and 79XX.asm):\r | |
216 | \r | |
217 | LDA SDVTR REQUEST\r | |
218 | JSB IOPMA,I DEVICE TABLE\r | |
219 | [...]\r | |
220 | STC DMAHS,C TURN ON DMA\r | |
221 | SFS DMAHS WAIT FOR\r | |
222 | JMP *-1 DEVICE TABLE\r | |
223 | STC CH2,C SET CORRECT\r | |
224 | CLC CH2 FLAG DIRECTION\r | |
225 | \r | |
226 | The STC/CLC normally would cause a second "request device table" command to\r | |
227 | be recognized by the IOP, except that the IOP DMA setup routine "DMAXF" (in\r | |
228 | D61.asm) has specified an end-of-block CLC that holds off the IPL interrupt,\r | |
229 | and the completion interrupt routine "DMACP" ends with a STC,C that clears\r | |
230 | the IPL flag.\r | |
231 | \r | |
232 | In hardware, the two CPUs are essentially interlocked by the DMA transfer,\r | |
233 | and DMA completion interrupts occur almost simultaneously. Therefore, the\r | |
234 | STC/CLC in the SP is guaranteed to occur before the STC,C in the IOP. Under\r | |
235 | simulation, and especially on multiprocessor hosts, that guarantee does not\r | |
236 | hold. If the STC/CLC occurs after the STC,C, then the IOP starts a second\r | |
237 | device table DMA transfer, which the SP is not expecting. The IOP never\r | |
238 | processes the subsequent "start timesharing" command, and the muxtiplexer is\r | |
239 | non-reponsive.\r | |
240 | \r | |
241 | We employ a workaround that decreases the incidence of the problem: DMA\r | |
242 | output completion interrupts are delayed to allow the other SIMH instance a\r | |
243 | chance to process its own DMA completion. We do this by processing the EDT\r | |
244 | (End Data Transfer) I/O backplane signal and "sleep"ing for a short time if\r | |
245 | the transfer was an output transfer ("dat" contains the DMA channel number\r | |
246 | and direction flag for EDT signals).\r | |
247 | */\r | |
248 | \r | |
249 | int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat)\r | |
250 | {\r | |
251 | uint32 u, dev, odev;\r | |
252 | int32 sta;\r | |
253 | char msg[2], uc;\r | |
254 | DEVICE *dbdev; /* device ptr for debug */\r | |
255 | static const char *iotype[] = { "Status", "Command" };\r | |
256 | \r | |
257 | uc = (uptr == &ipli_unit) ? 'I' : 'O'; /* identify unit for debug */\r | |
258 | dbdev = (uptr == &ipli_unit) ? &ipli_dev : &iplo_dev; /* identify device for debug */\r | |
259 | \r | |
260 | u = (uptr - ipl_unit); /* get unit number */\r | |
261 | dev = IR & I_DEVMASK; /* get device no */\r | |
262 | switch (inst) { /* case on opcode */\r | |
263 | \r | |
264 | case ioFLG: /* flag clear/set */\r | |
265 | if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */\r | |
266 | break;\r | |
267 | \r | |
268 | case ioSFC: /* skip flag clear */\r | |
269 | if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;\r | |
270 | break;\r | |
271 | \r | |
272 | case ioSFS: /* skip flag set */\r | |
273 | if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;\r | |
274 | break;\r | |
275 | \r | |
276 | case ioOTX: /* output */\r | |
277 | uptr->OBUF = dat;\r | |
278 | \r | |
279 | if (DEBUG_PRJ (dbdev, DEB_CPU))\r | |
280 | fprintf (sim_deb, ">>IPL%c OTx: %s = %06o\n", uc, iotype[u], dat);\r | |
281 | break;\r | |
282 | \r | |
283 | case ioLIX: /* load */\r | |
284 | dat = 0;\r | |
285 | \r | |
286 | case ioMIX: /* merge */\r | |
287 | dat = dat | uptr->IBUF; /* get return data */\r | |
288 | \r | |
289 | if (DEBUG_PRJ (dbdev, DEB_CPU))\r | |
290 | fprintf (sim_deb, ">>IPL%c LIx: %s = %06o\n", uc, iotype[u ^ 1], dat);\r | |
291 | break;\r | |
292 | \r | |
293 | case ioCRS: /* control reset */\r | |
294 | clrCMD (dev); /* clear ctl, cmd */\r | |
295 | clrCTL (dev);\r | |
296 | break;\r | |
297 | \r | |
298 | case ioCTL: /* control clear/set */\r | |
299 | if (IR & I_CTL) { /* CLC */\r | |
300 | clrCMD (dev); /* clear ctl, cmd */\r | |
301 | clrCTL (dev);\r | |
302 | \r | |
303 | if (DEBUG_PRJ (dbdev, DEB_CMDS))\r | |
304 | fprintf (sim_deb, ">>IPL%c CLC: Command cleared\n", uc);\r | |
305 | }\r | |
306 | \r | |
307 | else { /* STC */\r | |
308 | setCMD (dev); /* set ctl, cmd */\r | |
309 | setCTL (dev);\r | |
310 | \r | |
311 | if (DEBUG_PRJ (dbdev, DEB_CMDS))\r | |
312 | fprintf (sim_deb, ">>IPL%c STC: Command set\n", uc);\r | |
313 | \r | |
314 | if (uptr->flags & UNIT_ATT) { /* attached? */\r | |
315 | if ((uptr->flags & UNIT_ESTB) == 0) { /* established? */\r | |
316 | if (!ipl_check_conn (uptr)) /* not established? */\r | |
317 | return STOP_NOCONN; /* lose */\r | |
318 | uptr->flags = uptr->flags | UNIT_ESTB;\r | |
319 | }\r | |
320 | msg[0] = (uptr->OBUF >> 8) & 0377;\r | |
321 | msg[1] = uptr->OBUF & 0377;\r | |
322 | sta = sim_write_sock (uptr->DSOCKET, msg, 2);\r | |
323 | \r | |
324 | if (DEBUG_PRJ (dbdev, DEB_XFER))\r | |
325 | fprintf (sim_deb,\r | |
326 | ">>IPL%c STC: Socket write = %06o, status = %d\n",\r | |
327 | uc, uptr->OBUF, sta);\r | |
328 | \r | |
329 | if (sta == SOCKET_ERROR) {\r | |
330 | printf ("IPL: socket write error\n");\r | |
331 | return SCPE_IOERR;\r | |
332 | }\r | |
333 | sim_os_sleep (0);\r | |
334 | }\r | |
335 | else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */\r | |
336 | u = (uptr - ipl_unit) ^ 1; /* find other device */\r | |
337 | ipl_unit[u].IBUF = uptr->OBUF; /* output to other */\r | |
338 | odev = ipl_dib[u].devno; /* other device no */\r | |
339 | setFSR (odev); /* set other flag */\r | |
340 | }\r | |
341 | else return SCPE_UNATT; /* lose */\r | |
342 | }\r | |
343 | break;\r | |
344 | \r | |
345 | case ioEDT: /* End of DMA data transfer */\r | |
346 | if ((dat & DMA2_OI) == 0) { /* output transfer? */\r | |
347 | if (DEBUG_PRJ (dbdev, DEB_CMDS))\r | |
348 | fprintf (sim_deb,\r | |
349 | ">>IPL%c EDT: Delaying DMA completion interrupt for %d msec\n",\r | |
350 | uc, ipl_edtdelay);\r | |
351 | sim_os_ms_sleep (ipl_edtdelay); /* delay completion */\r | |
352 | }\r | |
353 | break;\r | |
354 | \r | |
355 | default:\r | |
356 | break;\r | |
357 | }\r | |
358 | \r | |
359 | if (IR & I_HC) { clrFSR (dev); } /* H/C option */\r | |
360 | return dat;\r | |
361 | }\r | |
362 | \r | |
363 | /* Unit service - poll for input */\r | |
364 | \r | |
365 | t_stat ipl_svc (UNIT *uptr)\r | |
366 | {\r | |
367 | int32 u, nb, dev;\r | |
368 | char msg[2], uc;\r | |
369 | DEVICE *dbdev; /* device ptr for debug */\r | |
370 | \r | |
371 | u = uptr - ipl_unit; /* get link number */\r | |
372 | if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */\r | |
373 | sim_activate (uptr, ipl_ptime); /* reactivate */\r | |
374 | if ((uptr->flags & UNIT_ESTB) == 0) { /* not established? */\r | |
375 | if (!ipl_check_conn (uptr)) return SCPE_OK; /* check for conn */\r | |
376 | uptr->flags = uptr->flags | UNIT_ESTB;\r | |
377 | }\r | |
378 | nb = sim_read_sock (uptr->DSOCKET, msg, ((uptr->flags & UNIT_HOLD)? 1: 2));\r | |
379 | if (nb < 0) { /* connection closed? */\r | |
380 | printf ("IPL: socket read error\n");\r | |
381 | return SCPE_IOERR;\r | |
382 | }\r | |
383 | if (nb == 0) return SCPE_OK; /* no data? */\r | |
384 | if (uptr->flags & UNIT_HOLD) { /* holdover byte? */\r | |
385 | uptr->IBUF = (ipl_hold[u] << 8) | (((int32) msg[0]) & 0377);\r | |
386 | uptr->flags = uptr->flags & ~UNIT_HOLD;\r | |
387 | }\r | |
388 | else if (nb == 1) {\r | |
389 | ipl_hold[u] = ((int32) msg[0]) & 0377;\r | |
390 | uptr->flags = uptr->flags | UNIT_HOLD;\r | |
391 | }\r | |
392 | else uptr->IBUF = ((((int32) msg[0]) & 0377) << 8) |\r | |
393 | (((int32) msg[1]) & 0377);\r | |
394 | dev = ipl_dib[u].devno; /* get device number */\r | |
395 | clrCMD (dev); /* clr cmd, set flag */\r | |
396 | setFSR (dev);\r | |
397 | \r | |
398 | uc = (uptr == &ipli_unit) ? 'I' : 'O'; /* identify unit for debug */\r | |
399 | dbdev = (uptr == &ipli_unit) ? &ipli_dev : &iplo_dev; /* identify device for debug */\r | |
400 | \r | |
401 | if (DEBUG_PRJ (dbdev, DEB_XFER))\r | |
402 | fprintf (sim_deb, ">>IPL%c svc: Socket read = %06o, status = %d\n",\r | |
403 | uc, uptr->IBUF, nb);\r | |
404 | \r | |
405 | return SCPE_OK;\r | |
406 | }\r | |
407 | \r | |
408 | t_bool ipl_check_conn (UNIT *uptr)\r | |
409 | {\r | |
410 | SOCKET sock;\r | |
411 | \r | |
412 | if (uptr->flags & UNIT_ESTB) return TRUE; /* established? */\r | |
413 | if (uptr->flags & UNIT_ACTV) { /* active connect? */\r | |
414 | if (sim_check_conn (uptr->DSOCKET, 0) <= 0) return FALSE;\r | |
415 | }\r | |
416 | else {\r | |
417 | sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */\r | |
418 | if (sock == INVALID_SOCKET) return FALSE; /* got a live one? */\r | |
419 | uptr->DSOCKET = sock; /* save data socket */\r | |
420 | }\r | |
421 | uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */\r | |
422 | return TRUE;\r | |
423 | }\r | |
424 | \r | |
425 | /* Reset routine */\r | |
426 | \r | |
427 | t_stat ipl_reset (DEVICE *dptr)\r | |
428 | {\r | |
429 | DIB *dibp = (DIB *) dptr->ctxt;\r | |
430 | UNIT *uptr = dptr->units;\r | |
431 | \r | |
432 | hp_enbdis_pair (dptr, /* make pair cons */\r | |
433 | (dptr == &ipli_dev)? &iplo_dev: &ipli_dev);\r | |
434 | dibp->cmd = dibp->ctl = 0; /* clear cmd, ctl */\r | |
435 | dibp->flg = dibp->fbf = dibp->srq = 1; /* set flg, fbf, srq */\r | |
436 | uptr->IBUF = uptr->OBUF = 0; /* clr buffers */\r | |
437 | if (uptr->flags & UNIT_ATT) sim_activate (uptr, ipl_ptime);\r | |
438 | else sim_cancel (uptr); /* deactivate unit */\r | |
439 | uptr->flags = uptr->flags & ~UNIT_HOLD;\r | |
440 | return SCPE_OK;\r | |
441 | }\r | |
442 | \r | |
443 | /* Attach routine\r | |
444 | \r | |
445 | attach -l - listen for connection on port\r | |
446 | attach -c - connect to ip address and port\r | |
447 | */\r | |
448 | \r | |
449 | t_stat ipl_attach (UNIT *uptr, char *cptr)\r | |
450 | {\r | |
451 | extern int32 sim_switches;\r | |
452 | SOCKET newsock;\r | |
453 | uint32 i, t, ipa, ipp, oldf;\r | |
454 | char *tptr;\r | |
455 | t_stat r;\r | |
456 | \r | |
457 | r = get_ipaddr (cptr, &ipa, &ipp);\r | |
458 | if ((r != SCPE_OK) || (ipp == 0)) return SCPE_ARG;\r | |
459 | oldf = uptr->flags;\r | |
460 | if (oldf & UNIT_ATT) ipl_detach (uptr);\r | |
461 | if ((sim_switches & SWMASK ('C')) ||\r | |
462 | ((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {\r | |
463 | if (ipa == 0) ipa = 0x7F000001;\r | |
464 | newsock = sim_connect_sock (ipa, ipp);\r | |
465 | if (newsock == INVALID_SOCKET) return SCPE_IOERR;\r | |
466 | printf ("Connecting to IP address %d.%d.%d.%d, port %d\n",\r | |
467 | (ipa >> 24) & 0xff, (ipa >> 16) & 0xff,\r | |
468 | (ipa >> 8) & 0xff, ipa & 0xff, ipp);\r | |
469 | if (sim_log) fprintf (sim_log,\r | |
470 | "Connecting to IP address %d.%d.%d.%d, port %d\n",\r | |
471 | (ipa >> 24) & 0xff, (ipa >> 16) & 0xff,\r | |
472 | (ipa >> 8) & 0xff, ipa & 0xff, ipp);\r | |
473 | uptr->flags = uptr->flags | UNIT_ACTV;\r | |
474 | uptr->LSOCKET = 0;\r | |
475 | uptr->DSOCKET = newsock;\r | |
476 | }\r | |
477 | else {\r | |
478 | if (ipa != 0) return SCPE_ARG;\r | |
479 | newsock = sim_master_sock (ipp);\r | |
480 | if (newsock == INVALID_SOCKET) return SCPE_IOERR;\r | |
481 | printf ("Listening on port %d\n", ipp);\r | |
482 | if (sim_log) fprintf (sim_log, "Listening on port %d\n", ipp);\r | |
483 | uptr->flags = uptr->flags & ~UNIT_ACTV;\r | |
484 | uptr->LSOCKET = newsock;\r | |
485 | uptr->DSOCKET = 0;\r | |
486 | }\r | |
487 | uptr->IBUF = uptr->OBUF = 0;\r | |
488 | uptr->flags = (uptr->flags | UNIT_ATT) & ~(UNIT_ESTB | UNIT_HOLD);\r | |
489 | tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */\r | |
490 | if (tptr == NULL) { /* no memory? */\r | |
491 | ipl_detach (uptr); /* close sockets */\r | |
492 | return SCPE_MEM;\r | |
493 | }\r | |
494 | strcpy (tptr, cptr); /* copy ipaddr:port */\r | |
495 | uptr->filename = tptr; /* save */\r | |
496 | sim_activate (uptr, ipl_ptime); /* activate poll */\r | |
497 | if (sim_switches & SWMASK ('W')) { /* wait? */\r | |
498 | for (i = 0; i < 30; i++) { /* check for 30 sec */\r | |
499 | if (t = ipl_check_conn (uptr)) break; /* established? */\r | |
500 | if ((i % 10) == 0) /* status every 10 sec */\r | |
501 | printf ("Waiting for connnection\n");\r | |
502 | sim_os_sleep (1); /* sleep 1 sec */\r | |
503 | }\r | |
504 | if (t) printf ("Connection established\n");\r | |
505 | }\r | |
506 | return SCPE_OK;\r | |
507 | }\r | |
508 | \r | |
509 | /* Detach routine */\r | |
510 | \r | |
511 | t_stat ipl_detach (UNIT *uptr)\r | |
512 | {\r | |
513 | if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r | |
514 | if (uptr->flags & UNIT_ACTV) sim_close_sock (uptr->DSOCKET, 1);\r | |
515 | else {\r | |
516 | if (uptr->flags & UNIT_ESTB) /* if established, */\r | |
517 | sim_close_sock (uptr->DSOCKET, 0); /* close data socket */\r | |
518 | sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */\r | |
519 | }\r | |
520 | free (uptr->filename); /* free string */\r | |
521 | uptr->filename = NULL;\r | |
522 | uptr->LSOCKET = 0;\r | |
523 | uptr->DSOCKET = 0;\r | |
524 | uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_ACTV | UNIT_ESTB);\r | |
525 | sim_cancel (uptr); /* don't poll */\r | |
526 | return SCPE_OK;\r | |
527 | }\r | |
528 | \r | |
529 | /* Disconnect routine */\r | |
530 | \r | |
531 | t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
532 | {\r | |
533 | if (cptr) return SCPE_ARG;\r | |
534 | if (((uptr->flags & UNIT_ATT) == 0) || (uptr->flags & UNIT_ACTV) ||\r | |
535 | ((uptr->flags & UNIT_ESTB) == 0)) return SCPE_NOFNC;\r | |
536 | sim_close_sock (uptr->DSOCKET, 0);\r | |
537 | uptr->DSOCKET = 0;\r | |
538 | uptr->flags = uptr->flags & ~UNIT_ESTB;\r | |
539 | return SCPE_OK;\r | |
540 | }\r | |
541 | \r | |
542 | /* Diagnostic/normal mode routine */\r | |
543 | \r | |
544 | t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
545 | {\r | |
546 | if (val) {\r | |
547 | ipli_unit.flags = ipli_unit.flags | UNIT_DIAG;\r | |
548 | iplo_unit.flags = iplo_unit.flags | UNIT_DIAG;\r | |
549 | }\r | |
550 | else {\r | |
551 | ipli_unit.flags = ipli_unit.flags & ~UNIT_DIAG;\r | |
552 | iplo_unit.flags = iplo_unit.flags & ~UNIT_DIAG;\r | |
553 | }\r | |
554 | return SCPE_OK;\r | |
555 | }\r | |
556 | \r | |
557 | /* Interprocessor link bootstrap routine (HP Access Manual) */\r | |
558 | \r | |
559 | #define MAX_BASE 073\r | |
560 | #define IPL_PNTR 074\r | |
561 | #define PTR_PNTR 075\r | |
562 | #define IPL_DEVA 076\r | |
563 | #define PTR_DEVA 077\r | |
564 | \r | |
565 | static const uint32 pboot[IBL_LNT] = {\r | |
566 | 0163774, /*BBL LDA ICK,I ; IPL sel code */\r | |
567 | 0027751, /* JMP CFG ; go configure */\r | |
568 | 0107700, /*ST CLC 0,C ; intr off */\r | |
569 | 0002702, /* CLA,CCE,SZA ; skip in */\r | |
570 | 0063772, /*CN LDA M26 ; feed frame */\r | |
571 | 0002307, /*EOC CCE,INA,SZA,RSS ; end of file? */\r | |
572 | 0027760, /* JMP EOT ; yes */\r | |
573 | 0017736, /* JSB READ ; get #char */\r | |
574 | 0007307, /* CMB,CCE,INB,SZB,RSS ; 2's comp; null? */\r | |
575 | 0027705, /* JMP EOC ; read next */\r | |
576 | 0077770, /* STB WC ; word in rec */\r | |
577 | 0017736, /* JSB READ ; get feed frame */\r | |
578 | 0017736, /* JSB READ ; get address */\r | |
579 | 0074000, /* STB 0 ; init csum */\r | |
580 | 0077771, /* STB AD ; save addr */\r | |
581 | 0067771, /*CK LDB AD ; check addr */\r | |
582 | 0047773, /* ADB MAXAD ; below loader */\r | |
583 | 0002040, /* SEZ ; E =0 => OK */\r | |
584 | 0102055, /* HLT 55 */\r | |
585 | 0017736, /* JSB READ ; get word */\r | |
586 | 0040001, /* ADA 1 ; cont checksum */\r | |
587 | 0177771, /* STB AD,I ; store word */\r | |
588 | 0037771, /* ISZ AD */\r | |
589 | 0000040, /* CLE ; force wd read */\r | |
590 | 0037770, /* ISZ WC ; block done? */\r | |
591 | 0027717, /* JMP CK ; no */\r | |
592 | 0017736, /* JSB READ ; get checksum */\r | |
593 | 0054000, /* CPB 0 ; ok? */\r | |
594 | 0027704, /* JMP CN ; next block */\r | |
595 | 0102011, /* HLT 11 ; bad csum */\r | |
596 | 0000000, /*RD 0 */\r | |
597 | 0006600, /* CLB,CME ; E reg byte ptr */\r | |
598 | 0103700, /*IO1 STC RDR,C ; start reader */\r | |
599 | 0102300, /*IO2 SFS RDR ; wait */\r | |
600 | 0027741, /* JMP *-1 */\r | |
601 | 0106400, /*IO3 MIB RDR ; get byte */\r | |
602 | 0002041, /* SEZ,RSS ; E set? */\r | |
603 | 0127736, /* JMP RD,I ; no, done */\r | |
604 | 0005767, /* BLF,CLE,BLF ; shift byte */\r | |
605 | 0027740, /* JMP IO1 ; again */\r | |
606 | 0163775, /* LDA PTR,I ; get ptr code */\r | |
607 | 0043765, /*CFG ADA SFS ; config IO */\r | |
608 | 0073741, /* STA IO2 */\r | |
609 | 0043766, /* ADA STC */\r | |
610 | 0073740, /* STA IO1 */\r | |
611 | 0043767, /* ADA MIB */\r | |
612 | 0073743, /* STA IO3 */\r | |
613 | 0027702, /* JMP ST */\r | |
614 | 0063777, /*EOT LDA PSC ; put select codes */\r | |
615 | 0067776, /* LDB ISC ; where xloader wants */\r | |
616 | 0102077, /* HLT 77 */\r | |
617 | 0027702, /* JMP ST */\r | |
618 | 0000000, /* NOP */\r | |
619 | 0102300, /*SFS SFS 0 */\r | |
620 | 0001400, /*STC 1400 */\r | |
621 | 0002500, /*MIB 2500 */\r | |
622 | 0000000, /*WC 0 */\r | |
623 | 0000000, /*AD 0 */\r | |
624 | 0177746, /*M26 -26 */\r | |
625 | 0000000, /*MAX -BBL */\r | |
626 | 0007776, /*ICK ISC */\r | |
627 | 0007777, /*PTR IPT */\r | |
628 | 0000000, /*ISC 0 */\r | |
629 | 0000000 /*IPT 0 */\r | |
630 | };\r | |
631 | \r | |
632 | t_stat ipl_boot (int32 unitno, DEVICE *dptr)\r | |
633 | {\r | |
634 | int32 i, devi, devp;\r | |
635 | extern DIB ptr_dib;\r | |
636 | extern UNIT cpu_unit;\r | |
637 | extern uint32 SR;\r | |
638 | extern uint16 *M;\r | |
639 | \r | |
640 | devi = ipli_dib.devno; /* get device no */\r | |
641 | devp = ptr_dib.devno;\r | |
642 | PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */\r | |
643 | SR = (devi << IBL_V_DEV) | devp; /* set SR */\r | |
644 | for (i = 0; i < IBL_LNT; i++) M[PC + i] = pboot[i]; /* copy bootstrap */\r | |
645 | M[PC + MAX_BASE] = (~PC + 1) & DMASK; /* fix ups */\r | |
646 | M[PC + IPL_PNTR] = M[PC + IPL_PNTR] | PC;\r | |
647 | M[PC + PTR_PNTR] = M[PC + PTR_PNTR] | PC;\r | |
648 | M[PC + IPL_DEVA] = devi;\r | |
649 | M[PC + PTR_DEVA] = devp;\r | |
650 | return SCPE_OK;\r | |
651 | }\r |