1 /*
2 * vim: filetype=c:tabstop=4:ai:expandtab
3 * SPDX-License-Identifier: ICU
4 * SPDX-License-Identifier: Multics
5 * scspell-id: 55ddc42f-f62e-11ec-ad7c-80ee73e9b8e7
6 *
7 * ---------------------------------------------------------------------------
8 *
9 * Copyright (c) 2007-2013 Michael Mondy
10 * Copyright (c) 2012-2016 Harry Reed
11 * Copyright (c) 2013-2016 Charles Anthony
12 * Copyright (c) 2021-2023 The DPS8M Development Team
13 *
14 * All rights reserved.
15 *
16 * This software is made available under the terms of the ICU
17 * License, version 1.8.1 or later. For more details, see the
18 * LICENSE.md file at the top-level directory of this distribution.
19 *
20 * ---------------------------------------------------------------------------
21 *
22 * This source file may contain code comments that adapt, include, and/or
23 * incorporate Multics program code and/or documentation distributed under
24 * the Multics License. In the event of any discrepancy between code
25 * comments herein and the original Multics materials, the original Multics
26 * materials should be considered authoritative unless otherwise noted.
27 * For more details and historical background, see the LICENSE.md file at
28 * the top-level directory of this distribution.
29 *
30 * ---------------------------------------------------------------------------
31 */
32
33 //
34 // This module contains the code that runs under the IOM channel thread
35 //
36
37 #define ASSUME0 0
38
39 #include <stdio.h>
40 #include <ctype.h>
41
42 #include "dps8.h"
43 #include "dps8_sys.h"
44 #include "dps8_scu.h"
45 #include "dps8_iom.h"
46 #include "dps8_cable.h"
47 #include "dps8_cpu.h"
48 #include "dps8_fnp2.h"
49 #include "dps8_fnp2_iomcmd.h"
50 #include "dps8_utils.h"
51 #include "fnpuv.h"
52
53 #define DBG_CTR 1
54
55 #if defined(THREADZ) || defined(LOCKLESS)
56 # include "threadz.h"
57 #endif
58
59 #ifdef TESTING
60 static inline void fnp_core_read_n (word24 addr, word36 *data, uint n, UNUSED const char * ctx)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
61 {
62 # ifdef THREADZ
63 lock_mem_rd ();
64 # endif /* ifdef THREADZ */
65 for (uint i = 0; i < n; i ++)
66 data [i] = M [addr + i] & DMASK;
67 # ifdef THREADZ
68 unlock_mem ();
69 # endif /* ifdef THREADZ */
70 }
71 #endif /* ifdef TESTING */
72
73 #ifdef THREADZ
74 static inline void l_putbits36_1 (vol word36 * x, uint p, word1 val)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
75 {
76 const int n = 1;
77 int shift = 36 - (int) p - (int) n;
78 if (shift < 0 || shift > 35) {
79 sim_printf ("l_putbits36_1: bad args (%012"PRIo64",pos=%d)\n", *x, p);
80 return;
81 }
82 word36 mask = ~ (~0U<<n); // n low bits on
83 word36 smask = mask << (unsigned) shift; // shift 1s to proper position; result 0*1{n}0*
84 // caller may provide val that is too big, e.g., a word with all bits
85 // set to one, so we mask val
86 lock_mem_wr ();
87 * x = (* x & ~ smask) | (((word36) val & mask) << shift);
88 unlock_mem ();
89 }
90 #else
91 # define l_putbits36_1 putbits36_1
92 #endif /* ifdef THREADZ */
93
94 //
95 // As mailbox messages are processed, decoded data is stashed here
96 ///
97
98 struct decoded_t
99 {
100 uint devUnitIdx;
101 uint op_code;
102 uint slot_no;
103 uint iom_unit;
104 uint chan_num;
105 word24 smbx;
106 word24 fsmbx;
107 struct fnpUnitData_s * fudp;
108 uint cell;
109 };
110
111 //
112 // Debugging...
113 //
114
115 #ifdef TESTING
116 static void dmpmbx (uint mailboxAddress)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
117 {
118 struct mailbox mbx;
119 fnp_core_read_n (mailboxAddress, (word36 *) & mbx, MAILBOX_WORDS, "dmpmbx");
120 sim_printf ("dia_pcw %012llo\n", (long long unsigned int) mbx.dia_pcw);
121 sim_printf ("mailbox_requests %012llo\n", (long long unsigned int) mbx.mailbox_requests);
122 sim_printf ("term_inpt_mpx_wd %012llo\n", (long long unsigned int) mbx.term_inpt_mpx_wd);
123 sim_printf ("last_mbx_req_count %012llo\n", (long long unsigned int) mbx.last_mbx_req_count);
124 sim_printf ("num_in_use %012llo\n", (long long unsigned int) mbx.num_in_use);
125 sim_printf ("mbx_used_flags %012llo\n", (long long unsigned int) mbx.mbx_used_flags);
126 for (uint i = 0; i < 8; i ++)
127 {
128 sim_printf ("CS mbx %d\n", i);
129 sim_printf (" word1 %012llo\n",
130 (long long unsigned int) mbx.dn355_sub_mbxes[i].word1);
131 sim_printf (" word2 %012llo\n",
132 (long long unsigned int) mbx.dn355_sub_mbxes[i].word2);
133 sim_printf (" command_data %012llo\n",
134 (long long unsigned int) mbx.dn355_sub_mbxes[i].command_data [0]);
135 sim_printf (" %012llo\n",
136 (long long unsigned int) mbx.dn355_sub_mbxes[i].command_data [1]);
137 sim_printf (" %012llo\n",
138 (long long unsigned int) mbx.dn355_sub_mbxes[i].command_data [2]);
139 sim_printf (" word6 %012llo\n",
140 (long long unsigned int) mbx.dn355_sub_mbxes[i].word6);
141 }
142 for (uint i = 0; i < 4; i ++)
143 {
144 sim_printf ("FNP mbx %d\n", i);
145 sim_printf (" word1 %012llo\n",
146 (unsigned long long int)mbx.fnp_sub_mbxes[i].word1);
147 sim_printf (" word2 %012llo\n",
148 (unsigned long long int)mbx.fnp_sub_mbxes[i].word2);
149 sim_printf (" mystery %012llo\n",
150 (unsigned long long int)mbx.fnp_sub_mbxes[i].mystery [0]);
151 sim_printf (" %012llo\n",
152 (unsigned long long int)mbx.fnp_sub_mbxes[i].mystery [1]);
153 sim_printf (" %012llo\n",
154 (unsigned long long int)mbx.fnp_sub_mbxes[i].mystery [2]);
155 }
156
157 }
158 #endif
159
160 //
161 // wcd; Multics has sent a Write Control Data command to the FNP
162 //
163
164 static int wcd (struct decoded_t *decoded_p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
165 {
166 struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->slot_no];
167 sim_debug (DBG_TRACE, & fnp_dev, "[%u] wcd op_code %u 0%o\n", decoded_p->slot_no, decoded_p->op_code, decoded_p->op_code);
168
169 word36 command_data[3];
170 for (uint i=0; i < 3; i++)
171 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->smbx+COMMAND_DATA + i, & command_data [i], direct_load);
172
173 switch (decoded_p->op_code)
174 {
175 case 1: // disconnect_this_line
176 {
177 sim_debug (DBG_TRACE, & fnp_dev, "[%u] disconnect_this_line\n", decoded_p->slot_no);
178 if (linep->line_client && linep->service == service_login)
179 fnpuv_start_writestr (linep->line_client, (unsigned char *) "Multics has disconnected you\r\n");
180 #ifdef DISC_DELAY
181 linep -> line_disconnected = DISC_DELAY;
182 #else
183 linep -> line_disconnected = true;
184 #endif
185 linep -> listen = false;
186 if (linep->line_client)
187 {
188 close_connection ((uv_stream_t *) linep->line_client);
189 }
190
191 }
192 break;
193
194 case 3: // dont_accept_calls
195 {
196 sim_debug (DBG_TRACE, & fnp_dev, "[%u] dont_accept_calls\n", decoded_p->slot_no);
197 decoded_p->fudp->MState.accept_calls = false;
198 }
199 break;
200
201 case 4: // accept_calls
202 {
203 sim_debug (DBG_TRACE, & fnp_dev, "[%u] accept_calls\n", decoded_p->slot_no);
204 decoded_p->fudp->MState.accept_calls = true;
205 }
206 break;
207
208 case 6: // set_line_type
209 {
210 linep->lineType = (word9) getbits36_18 (command_data[0], 0);
211 }
212 break;
213
214 case 8: // set_framing_chars
215 {
216 sim_debug (DBG_TRACE, & fnp_dev, "[%u] set_framing_chars\n", decoded_p->slot_no);
217 //sim_printf ("fnp set framing characters\n");
218 uint d1 = getbits36_9 (command_data[0], 0);
219 uint d2 = getbits36_9 (command_data[0], 9);
220 linep->frame_begin = d1;
221 linep->frame_end = d2;
222 }
223 break;
224
225 case 12: // dial out
226 {
227 sim_debug (DBG_TRACE, & fnp_dev, "[%u] dial out\n", decoded_p->slot_no);
228 //sim_printf ("XXX dial_out %d %012"PRIo64" %012"PRIo64" %012"PRIo64"", decoded_p->slot_no, command_data0, command_data1, command_data2);
229 fnpuv_dial_out (decoded_p->devUnitIdx, decoded_p->slot_no, command_data[0], command_data[1], command_data[2]);
230 }
231 break;
232
233 case 22: // line_control
234 {
235 sim_debug (DBG_TRACE, & fnp_dev, "[%u] line_control\n", decoded_p->slot_no);
236 //word36 command_data2 = decoded_p->smbxp -> command_data [2];
237 //sim_printf ("XXX line_control %d %012"PRIo64" %012"PRIo64" %012"PRIo64"\n", decoded_p->slot_no, command_data0, command_data1, command_data2);
238
239 // bisync_line_data.inc.pl1
240 word18 op = getbits36_18 (command_data[0], 0);
241 //word18 val1 = getbits36_18 (command_data[0], 18);
242 //word18 val2 = getbits36_18 (command_data[1], 0);
243 //word18 val3 = getbits36_18 (command_data1, 18);
244 //sim_printf ("line_control %d op %d. %o\r\n", decoded_p->slot_no, op, op);
245 switch (op)
246 {
247 case 1:
248 //if_sim_debug (DBG_TRACE, & fnp_dev) {
249 // word18 val1 = getbits36_18 (command_data[0], 18);
250 // sim_debug (DBG_TRACE, & fnp_dev, "SET_BID_LIMIT\n");
251 // sim_debug (DBG_TRACE, & fnp_dev, " %u\n", val1);
252 //}
253 break;
254 case 2:
255 sim_debug (DBG_TRACE, & fnp_dev, "ACCEPT_BID\n");
256 break;
257 case 3:
258 //if_sim_debug (DBG_TRACE, & fnp_dev) {
259 // word18 val1 = getbits36_18 (command_data[0], 18);
260 // sim_debug (DBG_TRACE, & fnp_dev, "CONFIGURE\n");
261 // if (val1 == 0)
262 // sim_debug (DBG_TRACE, & fnp_dev, " non-transparent ASCII\n");
263 // else if (val1 == 1)
264 // sim_debug (DBG_TRACE, & fnp_dev, " non-transparent EBCDIC\n");
265 // else if (val1 == 2)
266 // sim_debug (DBG_TRACE, & fnp_dev, " transparent ASCII\n");
267 // else if (val1 == 3)
268 // sim_debug (DBG_TRACE, & fnp_dev, " transparent EBCDIC\n");
269 // else
270 // sim_debug (DBG_TRACE, & fnp_dev, " unknown %u. %o\n", val1, val1);
271 //}
272 break;
273 case 4:
274 //if_sim_debug (DBG_TRACE, & fnp_dev) {
275 // word18 val1 = getbits36_18 (command_data[0], 18);
276 // word18 val2 = getbits36_18 (command_data[1], 0);
277 // sim_debug (DBG_TRACE, & fnp_dev, "SET_TTD_PARAMS\n");
278 // sim_debug (DBG_TRACE, & fnp_dev, " ttd_time %u\n", val1);
279 // sim_debug (DBG_TRACE, & fnp_dev, " ttd_limit %u\n", val2);
280 //}
281 break;
282 case 5:
283 sim_debug (DBG_TRACE, & fnp_dev, "REPORT_WRITE_STATUS\n");
284 break;
285 case 6:
286 sim_debug (DBG_TRACE, & fnp_dev, "SET_3270_MODE\n");
287 break;
288 case 7:
289 {
290 sim_debug (DBG_TRACE, & fnp_dev, "SET_POLLING_ADDR\n");
291 //word36 command_data2 = decoded_p->smbxp -> command_data [2];
292 //sim_printf ("XXX line_control %d %012"PRIo64" %012"PRIo64" %012"PRIo64"\n", decoded_p->slot_no, command_data0, command_data1, command_data2);
293 //word9 len = getbits36_9 (command_data0, 18);
294 word9 c1 = getbits36_9 (command_data[0], 27);
295 //word9 c2 = getbits36_9 (command_data1, 0);
296 word9 c3 = getbits36_9 (command_data[1], 9);
297 //word9 c4 = getbits36_9 (command_data1, 18);
298 sim_debug (DBG_TRACE, & fnp_dev, " char1 %u\n", c1);
299 sim_debug (DBG_TRACE, & fnp_dev, " char3 %u\n", c3);
300 fnpData.ibm3270ctlr[ASSUME0].pollCtlrChar = (unsigned char) (c1 & 0xff);
301 fnpData.ibm3270ctlr[ASSUME0].pollDevChar = (unsigned char) (c3 & 0xff);
302 fnpData.
303 fnpUnitData[decoded_p->devUnitIdx].
304 MState.
305 line[decoded_p->slot_no].
306 line_client = NULL;
307 }
308 break;
309 case 8:
310 sim_debug (DBG_TRACE, & fnp_dev, "START_POLL\n");
311 fnpuv3270Poll (true);
312 break;
313 case 9:
314 {
315 sim_debug (DBG_TRACE, & fnp_dev, "SET_SELECT_ADDR\n");
316 //word9 len = getbits36_9 (command_data0, 18);
317 word9 c1 = getbits36_9 (command_data[0], 27);
318 //word9 c2 = getbits36_9 (command_data1, 0);
319 word9 c3 = getbits36_9 (command_data[1], 9);
320 //word9 c4 = getbits36_9 (command_data1, 18);
321 sim_debug (DBG_TRACE, & fnp_dev, " char1 %u\n", c1);
322 sim_debug (DBG_TRACE, & fnp_dev, " char3 %u\n", c3);
323 fnpData.ibm3270ctlr[ASSUME0].selCtlrChar = (unsigned char) (c1 & 0xff);
324 fnpData.ibm3270ctlr[ASSUME0].selDevChar = (unsigned char) (c3 & 0xff);
325
326 // General Poll
327 if (fnpData.ibm3270ctlr[ASSUME0].selDevChar == 127)
328 {
329 fnpData.
330 fnpUnitData[decoded_p->devUnitIdx].
331 MState.
332 line[decoded_p->slot_no].
333 line_client = NULL;
334 break;
335 }
336 // Setup line_client to that wtx can locate the connection
337
338 // Find the client from the device selection call
339
340 uint stn_no;
341 for (stn_no = 0; stn_no < ADDR_MAP_ENTRIES; stn_no ++)
342 if (addr_map [stn_no] == fnpData.ibm3270ctlr[ASSUME0].selDevChar)
343 break;
344 if (stn_no >= ADDR_MAP_ENTRIES)
345 {
346 sim_warn ("SET_POLLING_ADDR couldn't find selDevChar %02x\r\n", (unsigned int) fnpData.ibm3270ctlr[ASSUME0].selDevChar);
347 break;
348 }
349 fnpData.
350 fnpUnitData[decoded_p->devUnitIdx].
351 MState.
352 line[decoded_p->slot_no].
353 line_client =
354 fnpData.
355 ibm3270ctlr[ASSUME0].
356 stations[stn_no].
357 client;
358 }
359 break;
360 case 10:
361 sim_debug (DBG_TRACE, & fnp_dev, "STOP_AUTO_POLL\n");
362 break;
363 case 11:
364 //if_sim_debug (DBG_TRACE, & fnp_dev) {
365 // word18 val1 = getbits36_18 (command_data[0], 18);
366 // sim_debug (DBG_TRACE, & fnp_dev, "SET_MASTER_SLAVE_MODE\n");
367 // if (val1 == 0)
368 // sim_debug (DBG_TRACE, & fnp_dev, " slave\n");
369 // else if (val1 == 1)
370 // sim_debug (DBG_TRACE, & fnp_dev, " master\n");
371 // else
372 // sim_debug (DBG_TRACE, & fnp_dev, " unknown %u. %o\n", val1, val1);
373 //}
374 break;
375 case 12:
376 sim_debug (DBG_TRACE, & fnp_dev, "SET_HASP_MODE\n");
377 break;
378 case 13:
379 sim_debug (DBG_TRACE, & fnp_dev, "SET_NAK_LIMIT\n");
380 break;
381 case 14:
382 sim_debug (DBG_TRACE, & fnp_dev, "SET_HASP_TIMERS\n");
383 break;
384 default:
385 sim_printf ("unknown %u. %o\n", op, op);
386 break;
387 }
388
389
390
391
392
393
394
395
396
397
398
399
400
401 }
402 break;
403
404 case 23: // sync_msg_size
405 {
406 linep->sync_msg_size = (uint) getbits36_18 (command_data[0], 0);
407 //sim_printf ("sync_msg_size %u\n", sz);
408 }
409 break;
410
411 //
412 // 1 echo_neg_data based (echo_neg_datap) aligned,
413 // /* Echo negotiation data */
414 // 2 version fixed bin,
415 // 2 break (0:255) bit (1) unaligned, /* Break table, 1 = break */
416 // 2 pad bit (7) unaligned,
417 // 2 rubout_trigger_chars (2) unaligned, /* Characters that cause rubout action */
418 // 3 char char (1) unaligned,
419 // 2 rubout_sequence_length fixed bin (4) unsigned unaligned, /* Length of rubout sequence, output */
420 // 2 rubout_pad_count fixed bin (4) unsigned unaligned, /* Count of pads needed */
421 // 2 buffer_rubouts bit (1) unaligned, /* 1 = put rubouts and rubbed out in buffer */
422 // 2 rubout_sequence char (12) unaligned; /* Actual rubout sequence */
423 //
424 // 0 version
425 // 1 break(0:35)
426 // 2 break(36:71)
427 // 3 break(72:107)
428 // 4 break(108:143)
429 // 5 break(144:179)
430 // 6 break(180:215)
431 // 7 break(216:251)
432 // 8
433 // 0:3 break(252:255)
434 // 4:10 pad
435 // 11:17 padding inserted by compiler to align to char boundary
436 // 18:35 rubout_trigger_chars
437 // 9 0:3 rubout_sequence_length
438 // 4:7 rubout_pad_count
439 // 8: buffer_rubouts
440 // 9:35 rubout_sequence (1:3)
441 // 10 rubout_sequence (4:7)
442 // 12 rubout_sequence (8:11)
443 // 13 0:8 rubout_sequence (12)
444
445 case 24: // set_echnego_break_table
446 {
447 sim_debug (DBG_TRACE, & fnp_dev,
448 "[%u] set_echnego_break_table\n", decoded_p->slot_no);
449
450 #ifdef ECHNEGO_DEBUG
451 sim_printf ("set_echnego_break_table\r\n");
452 #endif
453 // Get the table pointer and length
454 word36 word6;
455 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num,
456 decoded_p->smbx+WORD6, & word6,
457 direct_load);
458 uint data_addr = getbits36_18 (word6, 0);
459 uint data_len = getbits36_18 (word6, 18);
460
461 //sim_printf ("set_echnego_break_table %d addr %06o len %d\n",
462 // decoded_p->slot_no, data_addr, data_len);
463
464 // According to the MOWSE documentation, length of 0
465 // means no break characters and -1 means all break.
466
467 #define echoTableLen 8
468
469 if (data_len != echoTableLen && data_len != 0 &&
470 data_len != MASK18)
471 {
472 sim_printf ("set_echnego_break_table data_len !=8 (%d)\n", data_len);
473 break;
474 }
475
476 word36 echoTable [echoTableLen];
477 if (data_len == 0)
478 {
479 memset (linep->echnego_break_table, 0,
480 sizeof (linep->echnego_break_table));
481 }
482 else if (data_len == MASK18)
483 {
484 memset (linep->echnego_break_table, 1,
485 sizeof (linep->echnego_break_table));
486 }
487 else
488 {
489 for (uint i = 0; i < echoTableLen; i ++)
490 {
491 iom_direct_data_service (decoded_p->iom_unit,
492 decoded_p->chan_num, data_addr + i, & echoTable [i],
493 direct_load);
494 //sim_printf ("%012llo\n", echoTable[i]);
495 }
496 // Table format is actually
497 // 16 bits 2 pad 15 bits 2 pad
498 uint offset = 0;
499 for (uint i = 0; i < 8; i ++)
500 {
501 word36 w = echoTable [i];
502 for (uint j = 0; j < 16; j ++)
503 linep->echnego_break_table[offset++] =
504 !! getbits36_1 (w, j);
505 for (uint j = 0; j < 16; j ++)
506 linep->echnego_break_table[offset++] =
507 !! getbits36_1 (w, j + 18);
508 }
509 }
510
511
512
513
514
515
516
517
518
519
520
521 }
522 break;
523
524 // MTB418, pg 13:
525 // "When·Ring Zero MCS is called upon to begin negotiated echo (echo negotiate
526 // get chars, as in the previous paper), and has no characters to ·deliver
527 // immediately (already accumulated), it calls upon the inferior multiplexer to
528 // "start negotiated echo'', via a control order, also specifying the number of
529 // characters left on the line, as in the protocol of the previous paper. If
530 // this control order is refused (the multiplexer does not support the new
531 // protocol (of course, fnp multiplexer in specific, does)), ring zero proceeds
532 // as today, with interrupt-side negotiated echo. If the multiplexer goes along
533 // with the order, the channel is marked (in the ring-zero echo data) as having
534 // a multiplexer knowledgeable about the protocol. In either case, ring zero
535 // will enter the ''ring zero echo state" (of the previous paper).
536
537 case 25: // start_negotiated_echo
538 {
539 sim_debug (DBG_TRACE, & fnp_dev,
540 "[%u] start_negotiated_echo\n", decoded_p->slot_no);
541
542 linep->echnego_sync_ctr =
543 getbits36_18 (command_data[0], 0);
544 linep->echnego_screen_left = getbits36_18 (command_data[0], 18);
545
546 #ifdef ECHNEGO_DEBUG
547 sim_printf ("start_negotiated_echo ctr %d screenleft %d "
548 "unechoed cnt %d\n", linep->echnego_sync_ctr,
549 linep->echnego_screen_left,linep->echnego_unechoed_cnt);
550 #endif
551
552 // MTB-418 pg 15
553 // If the counts are not equal, it must be the case that non-echoed characters
554 // are ''in transit'', and the order must not be honored.
555
556 linep->echnego_on =
557 linep->echnego_sync_ctr == linep->echnego_unechoed_cnt;
558
559 #ifdef ECHNEGO_DEBUG
560 sim_printf ("echnego is %s\n", linep->echnego_on ? "on" : "off");
561 #endif
562
563 }
564 break;
565
566 case 26: // stop_negotiated_echo
567 {
568 sim_debug (DBG_TRACE, & fnp_dev,
569 "[%u] stop_negotiated_echo\n", decoded_p->slot_no);
570 #ifdef ECHNEGO_DEBUG
571 sim_printf ("stop_negotiated_echo\r\n");
572 #endif
573 linep->echnego_on = false;
574 // Post a ack echnego stop to MCS
575 linep->ack_echnego_stop = true;
576 }
577 break;
578
579 case 27: // init_echo_negotiation
580 {
581 sim_debug (DBG_TRACE, & fnp_dev,
582 "[%u] init_echo_negotiation\n", decoded_p->slot_no);
583 #ifdef ECHNEGO_DEBUG
584 sim_printf ("init_echo_negotiation\r\n");
585 #endif
586
587 // At the time the multiplexer's input processor (which maintains the (
588 // multiplexer's synchronization counter) receives the init echo negotiation
589 // control order, it zeroes its synchronization counter, begins counting
590 // characters (it must be in the non-echoing state) thereafter, and sends a new
591 // type of interrupt to Ring Zero MCS, ACK ECHNEGO START.
592
593 linep->echnego_unechoed_cnt = 0;
594
595 // Post a ack echnego init to MCS
596 linep->ack_echnego_init = true;
597 }
598 break;
599
600 case 30: // input_fc_chars
601 {
602 // dcl 1 input_flow_control_info aligned based,
603 // 2 suspend_seq unaligned,
604 // 3 count fixed bin (9) unsigned,
605 // 3 chars char (3),
606 // 2 resume_seq unaligned,
607 // 3 count fixed bin (9) unsigned,
608 // 3 chars char (3),
609 // 2 timeout bit (1);
610
611 sim_debug (DBG_TRACE, & fnp_dev, "[%u] input_fc_chars\n", decoded_p->slot_no);
612 word36 suspendStr = command_data[0];
613 linep->inputSuspendStr[0] = getbits36_8 (suspendStr, 10);
614 linep->inputSuspendStr[1] = getbits36_8 (suspendStr, 19);
615 linep->inputSuspendStr[2] = getbits36_8 (suspendStr, 28);
616 uint suspendLen = getbits36_9 (suspendStr, 0);
617 if (suspendLen > 3)
618 {
619 //sim_printf ("input_fc_chars truncating suspend %d to 3\n", suspendLen);
620 suspendLen = 3;
621 }
622 linep->inputSuspendLen = suspendLen;
623
624 word36 resumeStr = command_data[1];
625 linep->inputResumeStr[0] = getbits36_8 (resumeStr, 10);
626 linep->inputResumeStr[1] = getbits36_8 (resumeStr, 19);
627 linep->inputResumeStr[2] = getbits36_8 (resumeStr, 28);
628 uint resumeLen = getbits36_9 (resumeStr, 0);
629 if (resumeLen > 3)
630 {
631 //sim_printf ("input_fc_chars truncating suspend %d to 3\n", suspendLen);
632 resumeLen = 3;
633 }
634 linep->inputResumeLen = resumeLen;
635
636 // XXX timeout ignored
637 }
638 break;
639
640 case 31: // output_fc_chars
641 {
642 sim_debug (DBG_TRACE, & fnp_dev, "[%u] output_fc_chars\n", decoded_p->slot_no);
643 //sim_printf ("fnp output_fc_chars\n");
644
645 word36 suspendStr = command_data[0];
646 linep->outputSuspendStr[0] = getbits36_8 (suspendStr, 10);
647 linep->outputSuspendStr[1] = getbits36_8 (suspendStr, 19);
648 linep->outputSuspendStr[2] = getbits36_8 (suspendStr, 28);
649 uint suspendLen = getbits36_9 (suspendStr, 0);
650 if (suspendLen > 3)
651 {
652 //sim_printf ("output_fc_chars truncating suspend %d to 3\n", suspendLen);
653 suspendLen = 3;
654 }
655 linep->outputSuspendLen = suspendLen;
656
657 word36 resumeStr = command_data[1];
658 linep->outputResumeStr[0] = getbits36_8 (resumeStr, 10);
659 linep->outputResumeStr[1] = getbits36_8 (resumeStr, 19);
660 linep->outputResumeStr[2] = getbits36_8 (resumeStr, 28);
661 uint resumeLen = getbits36_9 (resumeStr, 0);
662 if (resumeLen > 3)
663 {
664 //sim_printf ("output_fc_chars truncating suspend %d to 3\n", suspendLen);
665 resumeLen = 3;
666 }
667 linep->outputResumeLen = resumeLen;
668 }
669 break;
670
671 case 34: // alter_parameters
672 {
673 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters\n", decoded_p->slot_no);
674 //sim_printf ("fnp alter parameters\n");
675 // The docs insist the subtype is in word2, but I think
676 // it is in command data...
677 uint subtype = getbits36_9 (command_data[0], 0);
678 uint flag = getbits36_1 (command_data[0], 17);
679 //sim_printf (" subtype %d\n", subtype);
680 switch (subtype)
681 {
682 case 3: // Fullduplex
683 {
684 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters fullduplex %u\n", decoded_p->slot_no, flag);
685 //sim_printf ("fnp full_duplex\n");
686 linep->fullDuplex = !! flag;
687 }
688 break;
689
690 case 8: // Crecho
691 {
692 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters crecho %u\n", decoded_p->slot_no, flag);
693 //sim_printf ("fnp crecho\n");
694 linep->crecho = !! flag;
695 }
696 break;
697
698 case 9: // Lfecho
699 {
700 //sim_printf ("fnp lfecho\n");
701 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters lfecho %u\n", decoded_p->slot_no, flag);
702 linep->lfecho = !! flag;
703 }
704 break;
705
706 case 13: // Dumpoutput
707 {
708 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters dumpoutput\n", decoded_p->slot_no);
709 //sim_printf ("fnp dumpoutput\n");
710 // XXX ignored
711 //linep -> send_output = true;
712 linep -> send_output = SEND_OUTPUT_DELAY;
713 }
714 break;
715
716 case 14: // Tabecho
717 {
718 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters tabecho %u\n", decoded_p->slot_no, flag);
719 //sim_printf ("fnp tabecho\n");
720 linep->tabecho = !! flag;
721 }
722 break;
723
724 case 16: // Listen
725 {
726 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters listen %u\n", decoded_p->slot_no, flag);
727 //sim_printf ("fnp listen %p %d.%d %d\n", linep->line_client, decoded_p->devUnitIdx,decoded_p->slot_no, flag);
728 uint bufsz = getbits36_18 (command_data[0], 18);
729 linep->listen = !! flag;
730 linep->inputBufferSize = bufsz;
731
732 if (linep->service == service_undefined)
733 linep->service = service_login;
734
735 if (linep->service == service_login && linep -> line_client)
736 {
737 fnpuv_start_writestr (linep->line_client,
738 linep->listen ?
739 (unsigned char *) "Multics is now listening to this line\r\n":
740 (unsigned char *) "Multics is no longer listening to this line\r\n");
741 }
742 if (linep->service == service_slave && ! linep -> line_client)
743 fnpuv_open_slave (decoded_p->devUnitIdx, decoded_p->slot_no);
744 }
745 break;
746
747 case 17: // Hndlquit
748 {
749 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters handlequit%u \n", decoded_p->slot_no, flag);
750 //sim_printf ("fnp handle_quit %d\n", flag);
751 linep->handleQuit = !! flag;
752 }
753 break;
754
755 case 18: // Chngstring
756 {
757 //sim_printf ("fnp Change control string\n");
758 uint idx = getbits36_9 (command_data[0], 9);
759 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters chngstring %u\n", decoded_p->slot_no, flag);
760 linep->ctrlStrIdx = idx;
761 }
762 break;
763
764 case 19: // Wru
765 {
766 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters wru\n", decoded_p->slot_no);
767 linep -> wru_timeout = true;
768 }
769 break;
770
771 case 20: // Echoplex
772 {
773 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters echoplex %u\n", decoded_p->slot_no, flag);
774 //sim_printf ("fnp echoplex\n");
775 linep->echoPlex = !! flag;
776 }
777 break;
778
779 case 22: // Dumpinput
780 {
781 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters dumpinput\n", decoded_p->slot_no);
782 // XXX
783 // dump input should discard whatever input buffers it can
784
785 //sim_printf ("fnp dump input\n");
786 // dump the input
787 //int muxLineNo = MState[fnpUnitNum].line [lineno] . muxLineNum;
788 //sim_printf ("dumping mux line %d\n");
789 //ttys [muxLineNo] . nPos = 0;
790 }
791 break;
792
793 case 23: // Replay
794 {
795 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters replay %u\n", decoded_p->slot_no, flag);
796 //sim_printf ("fnp replay\n");
797 linep->replay = !! flag;
798 }
799 break;
800
801 case 24: // Polite
802 {
803 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters polite %u\n", decoded_p->slot_no, flag);
804 //sim_printf ("fnp polite\n");
805 linep->polite = !! flag;
806 }
807 break;
808
809 case 25: // Block_xfer
810 {
811 uint bufsiz1 = getbits36_18 (command_data[0], 18);
812 uint bufsiz2 = getbits36_18 (command_data[1], 0);
813 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters block_xfer %u %u\n", decoded_p->slot_no, bufsiz1, bufsiz2);
814 linep->block_xfer_out_frame_sz = bufsiz1;
815 linep->block_xfer_in_frame_sz = bufsiz2;
816 //sim_printf ("in frame sz %u out frame sz %u\n", linep->block_xfer_in_frame_sz, linep->block_xfer_out_frame_sz);
817 //sim_printf ("fnp block_xfer %d %d\n", bufsiz1, bufsiz2);
818 }
819 break;
820
821 case 26: // Set_buffer_size
822 {
823 // Word 2: Bit 17 is "1"b.
824 //uint mb1 = getbits36_1 (decoded_p->smbxp -> command_data [0], 17);
825 // Bits 18...35 contain the size, in characters,
826 // of input buffers to be allocated for the
827 // channel.
828 uint sz = getbits36_18 (command_data[0], 18);
829 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters set_buffer_size %u\n", decoded_p->slot_no, flag);
830 linep->inputBufferSize = sz;
831 //sim_printf ("Set_buffer_size %u\n", sz);
832 }
833 break;
834
835 case 27: // Breakall
836 {
837 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters breakall %u\n", decoded_p->slot_no, flag);
838 //sim_printf ("fnp break_all\n");
839 linep->breakAll = !! flag;
840 }
841 break;
842
843 case 28: // Prefixnl
844 {
845 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters prefixnl %u\n", decoded_p->slot_no, flag);
846 //sim_printf ("fnp prefixnl\n");
847 linep->prefixnl = !! flag;
848 }
849 break;
850
851 case 29: // Input_flow_control
852 {
853 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters input_flow_control %u\n", decoded_p->slot_no, flag);
854 //sim_printf ("fnp input_flow_control\n");
855 linep->input_flow_control = !! flag;
856 }
857 break;
858
859 case 30: // Output_flow_control
860 {
861 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters output_flow_control %u\n", decoded_p->slot_no, flag);
862 //sim_printf ("fnp output_flow_control\n");
863 linep->output_flow_control = !! flag;
864 }
865 break;
866
867 case 31: // Odd_parity
868 {
869 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters odd_parity %u\n", decoded_p->slot_no, flag);
870 //sim_printf ("fnp odd_parity\n");
871 linep->odd_parity = !! flag;
872 }
873 break;
874
875 case 32: // Eight_bit_in
876 {
877 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters eight_bit_in %u\n", decoded_p->slot_no, flag);
878 //sim_printf ("fnp eight_bit_in\n");
879 linep->eight_bit_in = !! flag;
880 }
881 break;
882
883 case 33: // Eight_bit_out
884 {
885 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters eight_bit_out %u\n", decoded_p->slot_no, flag);
886 //sim_printf ("fnp eight_bit_out\n");
887 linep->eight_bit_out = !! flag;
888 }
889 break;
890
891 case 1: // Breakchar
892 case 2: // Nocontrol
893 case 4: // Break
894 case 5: // Errormsg
895 case 6: // Meter
896 case 7: // Sensepos
897 case 10: // Lock
898 case 11: // Msg
899 case 12: // Upstate
900 case 15: // Setbusy
901 case 21: // Xmit_hold
902 {
903 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters unimplemented\n", decoded_p->slot_no);
904 sim_printf ("fnp unimplemented subtype %d (%o)\n", subtype, subtype);
905 // doFNPfault (...) // XXX
906 return -1;
907 }
908
909 default:
910 {
911 sim_debug (DBG_TRACE, & fnp_dev, "[%u] alter_parameters illegal\n", decoded_p->slot_no);
912 sim_printf ("fnp illegal subtype %d (%o)\n", subtype, subtype);
913 // doFNPfault (...) // XXX
914 return -1;
915 }
916 } // switch (subtype)
917 }
918 break; // alter_parameters
919
920 case 37: // set_delay_table
921 {
922 sim_debug (DBG_TRACE, & fnp_dev, "[%u] set_delay_table\n", decoded_p->slot_no);
923 //sim_printf ("fnp set delay table\n");
924 uint d1 = getbits36_18 (command_data[0], 0);
925 uint d2 = getbits36_18 (command_data[0], 18);
926
927 uint d3 = getbits36_18 (command_data[1], 0);
928 uint d4 = getbits36_18 (command_data[1], 18);
929
930 uint d5 = getbits36_18 (command_data[2], 0);
931 uint d6 = getbits36_18 (command_data[2], 18);
932
933 linep->delay_table[0] = d1;
934 linep->delay_table[1] = d2;
935 linep->delay_table[2] = d3;
936 linep->delay_table[3] = d4;
937 linep->delay_table[4] = d5;
938 linep->delay_table[5] = d6;
939 }
940 break;
941
942 // dcl fnp_chan_meterp pointer;
943 // dcl FNP_CHANNEL_METERS_VERSION_1 fixed bin int static options (constant) init (1);
944 //
945 // dcl 1 fnp_chan_meter_struc based (fnp_chan_meterp) aligned,
946 // 2 version fixed bin,
947 // 2 flags,
948 // 3 synchronous bit (1) unaligned,
949 // 3 reserved bit (35) unaligned,
950 // 2 current_meters like fnp_channel_meters,
951 // 2 saved_meters like fnp_channel_meters;
952 //
953
954 /*NOTREACHED*/ /* unreachable */
955
956 // dcl 1 fnp_channel_meters based aligned,
957 struct fnp_channel_meters //-V779
958 {
959 // 2 header,
960 struct header //-V779
961 { //-V779
962 // 3 dia_request_q_len fixed bin (35), /* cumulative */
963 word36 dia_request_q_len; //-V779
964 // 3 dia_rql_updates fixed bin (35), /* updates to above */
965 word36 dia_rql_updates; //-V779
966 // 3 pending_status fixed bin (35), /* cumulative */
967 word36 pending_status; //-V779
968 // 3 pending_status_updates fixed bin (35), /* updates to above */
969 word36 pending_status_updates; //-V779
970 // 3 output_overlaps fixed bin (18) unsigned unaligned, /* output chained to already-existing chain */
971 // 3 parity_errors fixed bin (18) unsigned unaligned, /* parity on the channel */
972 word36 output_overlaps___parity_errors; //-V779
973 // 3 software_status_overflows fixed bin (18) unsigned unaligned,
974 // 3 hardware_status_overflows fixed bin (18) unsigned unaligned,
975 word36 software_status_overflows___hardware_status_overflows; //-V779
976 // 3 input_alloc_failures fixed bin (18) unsigned unaligned,
977 // 3 dia_current_q_len fixed bin (18) unsigned unaligned, /* current length of dia request queue */
978 word36 input_alloc_failures___dia_current_q_len; //-V779
979 // 3 exhaust fixed bin (35),
980 word36 exhaust; //-V779
981 // 3 software_xte fixed bin (18) unsigned unaligned,
982 // 3 pad bit (18) unaligned,
983 word36 software_xte___sync_or_async; //-V779
984 } header; //-V779
985 // 2 sync_or_async (17) fixed bin; /* placeholder for meters for sync or async channels */
986 word36 sync_or_async; //-V779
987 }; //-V779
988
989 //
990 // dcl 1 fnp_sync_meters based aligned,
991 // 2 header like fnp_channel_meters.header,
992 // 2 input,
993 // 3 message_count fixed bin (35), /* total number of messages */
994 // 3 cum_length fixed bin (35), /* total cumulative length in characters */
995 // 3 min_length fixed bin (18) unsigned unaligned, /* length of shortest message */
996 // 3 max_length fixed bin (18) unsigned unaligned, /* length of longest message */
997 // 2 output like fnp_sync_meters.input,
998 // 2 counters (8) fixed bin (35),
999 // 2 pad (3) fixed bin;
1000 //
1001 // dcl 1 fnp_async_meters based aligned,
1002 struct fnp_async_meters //-V779
1003 { //-V779
1004 // 2 header like fnp_channel_meters.header,
1005 // 2 pre_exhaust fixed bin (35),
1006 word36 pre_exhaust; //-V779
1007 // 2 echo_buf_overflow fixed bin (35), /* number of times echo buffer has overflowed */
1008 word36 echo_buf_overflow; //-V779
1009 // 2 bell_quits fixed bin (18) unsigned unaligned,
1010 // 2 padb bit (18) unaligned,
1011 word36 bell_quits___pad; //-V779
1012 // 2 pad (14) fixed bin;
1013 word36 pad; //-V779
1014 }; //-V779
1015 //
1016 case 36: // report_meters
1017 {
1018 sim_debug (DBG_TRACE, & fnp_dev, "[%u] report_meters\n", decoded_p->slot_no);
1019 //sim_printf ("fnp report_meters\n");
1020 // XXX Do nothing, the request will timeout...
1021 }
1022 break;
1023
1024 case 0: // terminal_accepted
1025 case 2: // disconnect_all_lines
1026 case 5: // input_accepted
1027 case 7: // enter_receive
1028 case 9: // blast
1029 case 10: // accept_direct_output
1030 case 11: // accept_last_output
1031 //case 13: // ???
1032 case 14: // reject_request_temp
1033 //case 15: // ???
1034 case 16: // terminal_rejected
1035 case 17: // disconnect_accepted
1036 case 18: // init_complete
1037 case 19: // dump_mem
1038 case 20: // patch_mem
1039 case 21: // fnp_break
1040 //case 24: // set_echnego_break_table
1041 //case 25: // start_negotiated_echo
1042 //case 26: // stop_negotiated_echo
1043 //case 27: // init_echo_negotiation
1044 //case 28: // ???
1045 case 29: // break_acknowledged
1046 //case 32: // ???
1047 //case 33: // ???
1048 case 35: // checksum_error
1049 {
1050 sim_debug (DBG_TRACE, & fnp_dev, "[%u] unimplemented opcode\n", decoded_p->slot_no);
1051 sim_warn ("fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1052 //sim_debug (DBG_ERR, & fnp_dev, "fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1053 //sim_printf ("fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1054 // doFNPfault (...) // XXX
1055 //return -1;
1056 }
1057 break;
1058
1059 default:
1060 {
1061 sim_debug (DBG_TRACE, & fnp_dev, "[%u]fnp illegal opcode %d (%o)\n", decoded_p->slot_no, decoded_p->op_code, decoded_p->op_code);
1062 // doFNPfault (...) // XXX
1063 return -1;
1064 }
1065 } // switch decoded_p->op_code
1066
1067 setTIMW (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress, (int) decoded_p->cell);
1068
1069 send_general_interrupt (decoded_p->iom_unit, decoded_p->chan_num, imwTerminatePic);
1070
1071 return 0;
1072 }
1073
1074 #ifdef TUN
1075 static void tun_write (struct t_line * linep, uint16_t * data, uint tally)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1076 {
1077
1078
1079
1080
1081
1082 // XXX this code is buggy; if a buffer is received with an embedded frame start, the embedded frame
1083 // XXX will be lost
1084
1085 for (uint i = 0; i < tally; i ++)
1086 {
1087 // Check for start of frame...
1088 if (data [i] == 0x100)
1089 {
1090 linep->in_frame = true;
1091 linep->frameLen = 0;
1092 continue;
1093 }
1094
1095 if (! linep->in_frame)
1096 continue;
1097
1098 if (linep->frameLen >= 2+1500)
1099 {
1100 sim_printf ("inFrame overrun\n");
1101 break;
1102 }
1103 linep->frame[linep->frameLen ++] = (uint8_t) (data [i] & 0xff);
1104 }
1105
1106 // Is frame complete?
1107
1108 if (linep->frameLen >= 2)
1109 {
1110 uint16_t target = (uint16_t) ((linep->frame[0] & 0xff) << 8) | (linep->frame[1]);
1111 if (target + 2 >= linep->frameLen)
1112 {
1113 sim_printf ("frame received\n");
1114 fnpuv_tun_write (linep);
1115 linep->in_frame = false;
1116 }
1117 }
1118 }
1119 #endif
1120
1121 static void fnp_wtx_output (struct decoded_t *decoded_p, uint tally, uint dataAddr)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1122 {
1123 sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd wtx_output\n", decoded_p->slot_no);
1124 struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->slot_no];
1125
1126 uint wordOff = 0;
1127 word36 word = 0;
1128 uint lastWordOff = (uint) -1;
1129 #ifdef TUN
1130 uint16_t data9 [tally];
1131 #endif
1132 unsigned char data [tally];
1133
1134 for (uint i = 0; i < tally; i ++)
1135 {
1136 uint byteOff = i % 4;
1137 uint byte = 0;
1138
1139 wordOff = i / 4;
1140
1141 if (wordOff != lastWordOff)
1142 {
1143 lastWordOff = wordOff;
1144 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, dataAddr + wordOff, & word, direct_load);
1145 }
1146 byte = getbits36_9 (word, byteOff * 9);
1147 data [i] = byte & 0377;
1148 #ifdef TUN
1149 data9 [i] = (uint16_t) byte;
1150 #endif
1151
1152 //sim_printf (" %03o %c\n", data [i], isgraph (data [i]) ? data [i] : '.');
1153 }
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168 #ifdef TUN
1169 if (linep->is_tun && tally > 0)
1170 {
1171 tun_write (linep, data9, tally);
1172 return;
1173 }
1174 #endif
1175 if (tally > 0 && linep->line_client)
1176 {
1177 if (! linep->line_client || ! linep->line_client->data) //-V560
1178 {
1179 sim_warn ("fnp_wtx_output bad client data\r\n");
1180 return;
1181 }
1182 uvClientData * p = linep->line_client->data;
1183 (* p->write_cb) (linep->line_client, data, tally);
1184 }
1185 }
1186
1187 static int wtx (struct decoded_t *decoded_p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1188 {
1189 sim_debug (DBG_TRACE, & fnp_dev, "[%u]wtx op_code %u 0%o\n", decoded_p->slot_no, decoded_p->op_code, decoded_p->op_code);
1190 //sim_printf ("wtx op_code %o (%d.) %c.h%03d\n", decoded_p->op_code, decoded_p->op_code, decoded_p->devUnitIdx+'a', decoded_p->slot_no);
1191 if (decoded_p->op_code != 012 && decoded_p->op_code != 014) //-V536
1192 {
1193 sim_debug (DBG_TRACE, & fnp_dev, "[%u] unimplemented opcode\n", decoded_p->slot_no);
1194 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp wtx unimplemented opcode %d (%o)\n", decoded_p->slot_no, decoded_p->op_code, decoded_p->op_code);
1195 sim_printf ("fnp wtx unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1196 // doFNPfault (...) // XXX
1197 return -1;
1198 }
1199 // op_code is 012
1200 word36 data;
1201 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->smbx+WORD6, & data, direct_load);
1202 uint dcwAddr = getbits36_18 (data, 0);
1203 uint dcwCnt = getbits36_9 (data, 27);
1204 //uint sent = 0;
1205
1206 // For each dcw
1207 for (uint i = 0; i < dcwCnt; i ++)
1208 {
1209 // The address of the dcw in the dcw list
1210 // The dcw
1211 word36 dcw;
1212 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, dcwAddr + i, & dcw, direct_load);
1213
1214 // Get the address and the tally from the dcw
1215 uint dataAddr = getbits36_18 (dcw, 0);
1216 uint tally = getbits36_9 (dcw, 27);
1217 //sim_printf ("%6d %012o\n", tally, dataAddr);
1218 if (! tally)
1219 continue;
1220 fnp_wtx_output (decoded_p, tally, dataAddr);
1221 //sent += tally;
1222 } // for each dcw
1223
1224 setTIMW (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress, (int) decoded_p->cell);
1225
1226 send_general_interrupt (decoded_p->iom_unit, decoded_p->chan_num, imwTerminatePic);
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238 decoded_p->fudp->MState.line[decoded_p->slot_no].send_output = SEND_OUTPUT_DELAY;
1239
1240 return 0;
1241 }
1242
1243 static void fnp_rtx_input_accepted (struct decoded_t *decoded_p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1244 {
1245 // AN85-01 pg 232 A-6
1246 //
1247 // Input Accepted (005)
1248 //
1249 // Purpose:
1250 // Response to an accept input operation by providing the address
1251 // (in the circular buffer) to which input is sent.
1252 //
1253 // Associated Data:
1254 // Word 5: Bits 0..17 contain the beginning absolute address of the
1255 // portion of the circular buffer into which the input is to be placed.
1256 //
1257 // Bits 18...35 contain the number of characters to be placed in the
1258 // specified location.
1259 //
1260 // Word 4: If non-zero, contains the address and tally as described
1261 // above for the remaining data. This word is only used if the input
1262 // request required a wraparound of the circular buffer.
1263 //
1264
1265 word36 word2;
1266 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+WORD2, & word2, direct_load);
1267 uint n_chars = getbits36_18 (word2, 0);
1268
1269 word36 n_buffers;
1270 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+N_BUFFERS, & n_buffers, direct_load);
1271
1272 struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->slot_no];
1273 unsigned char * data_p = linep -> buffer;
1274
1275 n_chars = min(n_chars, linep -> nPos);
1276
1277 uint off = 0;
1278 for (uint j = 0; j < n_buffers && off < n_chars; j++)
1279 {
1280 word36 data;
1281 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+DCWS+j, & data, direct_load);
1282 word24 addr = getbits36_24 (data, 0);
1283 word12 tally = getbits36_12 (data, 24);
1284
1285 if_sim_debug (DBG_TRACE, & fnp_dev) {
1286 { sim_printf ("[%u][FNP emulator: nPos %d long IN: '", decoded_p->slot_no, linep->nPos);
1287 for (uint i = 0; i < linep->nPos; i ++)
1288 {
1289 if (isgraph (linep->buffer [i]))
1290 sim_printf ("%c", linep->buffer [i]);
1291 else
1292 sim_printf ("\\%03o", linep->buffer [i]);
1293 }
1294 sim_printf ("']\n");
1295 }
1296 }
1297
1298 //sim_printf ("long in; line %d tally %d\n", decoded_p->slot_no, linep->nPos);
1299 uint n_chars_in_buf = min(n_chars-off, tally);
1300 for (uint i = 0; i < n_chars_in_buf; i += 4)
1301 {
1302 word36 v = 0;
1303 if (i < n_chars_in_buf) //-V547
1304 putbits36_9 (& v, 0, data_p [off++]);
1305 if (i + 1 < n_chars_in_buf)
1306 putbits36_9 (& v, 9, data_p [off++]);
1307 if (i + 2 < n_chars_in_buf)
1308 putbits36_9 (& v, 18, data_p [off++]);
1309 if (i + 3 < n_chars_in_buf)
1310 putbits36_9 (& v, 27, data_p [off++]);
1311 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, addr, & v, direct_store);
1312 addr ++;
1313 }
1314 }
1315 // XXX temporary until the logic is in place
1316 // This appears to only be used in tty_interrupt.pl1 as
1317 // rtx_info.output_in_fnp as part of echo negotiation:
1318 // if ^rtx_info.output_in_fnp /* if there's no output going on */
1319 // So apparently a flag indicating that there is output queued.
1320 word1 output_chain_present = 1;
1321
1322 word36 v;
1323 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+INP_COMMAND_DATA, &v, direct_load);
1324 l_putbits36_1 (& v, 16, output_chain_present);
1325 l_putbits36_1 (& v, 17, linep->input_break ? 1 : 0);
1326 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+INP_COMMAND_DATA, &v, direct_store);
1327
1328 // Mark the line as ready to receive more data
1329 linep->input_reply_pending = false;
1330 linep->input_break = false;
1331 linep->nPos = 0;
1332
1333 setTIMW (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress, (int) decoded_p->cell);
1334
1335 send_general_interrupt (decoded_p->iom_unit, decoded_p->chan_num, imwTerminatePic);
1336 }
1337
1338 static int interruptL66_CS_to_FNP (struct decoded_t *decoded_p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1339 {
1340 uint mbx = decoded_p->cell;
1341 //ASSURE(mbx < 8);
1342 if (mbx >= 8)
1343 {
1344 sim_warn ("bad mbx number in interruptL66_CS_to_FNP; dropping\n");
1345 return -1;
1346 }
1347 decoded_p->smbx = decoded_p->fudp->mailboxAddress + DN355_SUB_MBXES + mbx*DN355_SUB_MBX_SIZE;
1348
1349 word36 word2;
1350 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->smbx+WORD2, & word2, direct_load);
1351 //uint cmd_data_len = getbits36_9 (word2, 9);
1352 decoded_p->op_code = getbits36_9 (word2, 18);
1353 uint io_cmd = getbits36_9 (word2, 27);
1354
1355 word36 word1;
1356 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->smbx+WORD1, & word1, direct_load);
1357 decoded_p->slot_no = getbits36_6 (word1, 12);
1358
1359 sim_debug (DBG_TRACE, & fnp_dev, "io_cmd %u\n", io_cmd);
1360 switch (io_cmd)
1361 {
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371 case 3: // wcd (write control data)
1372 {
1373 int ret = wcd (decoded_p);
1374 if (ret)
1375 return ret;
1376 }
1377 break;
1378
1379 case 4: // wtx (write text)
1380 {
1381 int ret = wtx (decoded_p);
1382 if (ret)
1383 return ret;
1384 }
1385 break;
1386
1387 case 1: // rcd (read control data)
1388 {
1389 sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd unimplemented\n", decoded_p->slot_no);
1390 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp unimplemented io_cmd %d\n", decoded_p->slot_no, io_cmd);
1391 sim_printf ("fnp unimplemented io_cmd %d\n", io_cmd);
1392 // doFNPfault (...) // XXX
1393 return -1;
1394 }
1395 default:
1396 {
1397 sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd illegal opcode\n", decoded_p->slot_no);
1398 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp illegal io_cmd %d\n", decoded_p->slot_no, io_cmd);
1399 sim_printf ("fnp illegal io_cmd %d\n", io_cmd);
1400 // doFNPfault (...) // XXX
1401 return -1;
1402 }
1403 } // switch (io_cmd)
1404 return 0;
1405 }
1406
1407 static int interruptL66_FNP_to_CS (struct decoded_t *decoded_p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1408 {
1409 // The CS has updated the FNP sub mailbox; this acknowledges processing
1410 // of the FNP->CS command that was in the submailbox
1411
1412 uint mbx = decoded_p->cell - 8;
1413 //ASSURE(mbx < 4);
1414 if (mbx >= 4)
1415 {
1416 sim_warn ("bad mbx number in interruptL66_FNP_to_CS; dropping\n");
1417 return -1;
1418 }
1419 decoded_p->fsmbx = decoded_p->fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
1420
1421
1422
1423
1424
1425
1426
1427
1428 word36 word2;
1429 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+WORD2, & word2, direct_load);
1430 //uint cmd_data_len = getbits36_9 (word2, 9);
1431 uint op_code = getbits36_9 (word2, 18);
1432 uint io_cmd = getbits36_9 (word2, 27);
1433
1434 word36 word1;
1435 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+WORD1, & word1, direct_load);
1436 //uint dn355_no = getbits36_3 (word1, 0);
1437 //uint is_hsla = getbits36_1 (word1, 8);
1438 //uint la_no = getbits36_3 (word1, 9);
1439 decoded_p->slot_no = getbits36_6 (word1, 12);
1440 //uint terminal_id = getbits36_18 (word1, 18);
1441
1442 sim_debug (DBG_TRACE, & fnp_dev, "[%u]fnp interrupt\n", decoded_p->slot_no);
1443 switch (io_cmd)
1444 {
1445 case 2: // rtx (read transmission)
1446 {
1447 sim_debug (DBG_TRACE, & fnp_dev, "[%u] rtx\n", decoded_p->slot_no);
1448 switch (op_code)
1449 {
1450 case 5: // input_accepted
1451 {
1452 sim_debug (DBG_TRACE, & fnp_dev, "[%u] input_accepted\n", decoded_p->slot_no);
1453 fnp_rtx_input_accepted (decoded_p);
1454 }
1455 break;
1456 default:
1457 sim_debug (DBG_TRACE, & fnp_dev, "[%u] illegal rtx ack\n", decoded_p->slot_no);
1458 sim_warn ("rtx %d. %o ack ignored\n", op_code, op_code);
1459 break;
1460 }
1461 break;
1462 }
1463 case 3: // wcd (write control data)
1464 {
1465 sim_debug (DBG_TRACE, & fnp_dev, "[%u] wcd\n", decoded_p->slot_no);
1466 switch (op_code)
1467 {
1468 case 0: // terminal_accepted
1469 {
1470 sim_debug (DBG_TRACE, & fnp_dev, "[%u] terminal accepted\n", decoded_p->slot_no);
1471 // outputBufferThreshold Ignored
1472 //word36 command_data0 = decoded_p->fsmbxp -> mystery [0];
1473 //uint outputBufferThreshold = getbits36_18 (command_data0, 0);
1474 //sim_printf (" outputBufferThreshold %d\n", outputBufferThreshold);
1475
1476 // Prime the pump
1477 //decoded_p->fudp->MState.line[decoded_p->slot_no].send_output = true;
1478 decoded_p->fudp->MState.line[decoded_p->slot_no].send_output = SEND_OUTPUT_DELAY;
1479 // XXX XXX XXX XXX
1480 // For some reason the CS ack of accept_new_terminal is not being seen, causing the line to wedge.
1481 // Since a terminal accepted command always follows, clear the wedge here
1482 decoded_p->fudp->MState.line[decoded_p->slot_no].waitForMbxDone = false;
1483 }
1484 break;
1485
1486 case 1: // disconnect_this_line
1487 {
1488 sim_debug (DBG_TRACE, & fnp_dev, "[%u] disconnect_this_line\n", decoded_p->slot_no);
1489 //sim_printf ("disconnect_this_line ack.\n");
1490 }
1491 break;
1492
1493 case 14: // reject_request_temp
1494 {
1495 sim_printf ("reject_request_temp\r\n");
1496 sim_debug (DBG_TRACE, & fnp_dev, "[%u] reject_request_temp\n", decoded_p->slot_no);
1497 //sim_printf ("fnp reject_request_temp\n");
1498 // Retry in one second;
1499 decoded_p->fudp->MState.line[decoded_p->slot_no].accept_input = 100;
1500 }
1501 break;
1502
1503 case 2: // disconnect_all_lines
1504 case 3: // dont_accept_calls
1505 case 4: // accept_calls
1506 case 5: // input_accepted
1507 case 6: // set_line_type
1508 case 7: // enter_receive
1509 case 8: // set_framing_chars
1510 case 9: // blast
1511 case 10: // accept_direct_output
1512 case 11: // accept_last_output
1513 case 12: // dial
1514 //case 13: // ???
1515 //case 15: // ???
1516 case 16: // terminal_rejected
1517 case 17: // disconnect_accepted
1518 case 18: // init_complete
1519 case 19: // dump_mem
1520 case 20: // patch_mem
1521 case 21: // fnp_break
1522 case 22: // line_control
1523 case 23: // sync_msg_size
1524 case 24: // set_echnego_break_table
1525 case 25: // start_negotiated_echo
1526 case 26: // stop_negotiated_echo
1527 case 27: // init_echo_negotiation
1528 //case 28: // ???
1529 case 29: // break_acknowledged
1530 case 30: // input_fc_chars
1531 case 31: // output_fc_chars
1532 //case 32: // ???
1533 //case 33: // ???
1534 case 34: // alter_parameters
1535 case 35: // checksum_error
1536 case 36: // report_meters
1537 case 37: // set_delay_table
1538 {
1539 sim_debug (DBG_TRACE, & fnp_dev, "[%u] unimplemented opcode\n", decoded_p->slot_no);
1540 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp reply unimplemented opcode %d (%o)\n", decoded_p->slot_no, op_code, op_code);
1541 sim_printf ("fnp reply unimplemented opcode %d (%o)\n", op_code, op_code);
1542 // doFNPfault (...) // XXX
1543 return -1;
1544 }
1545
1546 default:
1547 {
1548 sim_debug (DBG_TRACE, & fnp_dev, "[%u] illegal opcode\n", decoded_p->slot_no);
1549 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp reply illegal opcode %d (%o)\n", decoded_p->slot_no, op_code, op_code);
1550 sim_printf ("fnp reply illegal opcode %d (%o)\n", op_code, op_code);
1551 // doFNPfault (...) // XXX
1552 return -1;
1553 }
1554 } // switch op_code
1555
1556 // Set the TIMW
1557
1558 // Not sure... XXX
1559 //putbits36_1 (& mbxp -> term_inpt_mpx_wd, cell, 1);
1560 // No; the CS has told us it has updated the mbx, and
1561 // we need to read it; we have done so, so we are finished
1562 // with the mbx, and can mark it so.
1563 decoded_p->fudp->fnpMBXinUse [mbx] = false;
1564
1565 } // case wcd
1566 break;
1567
1568 default:
1569 {
1570 sim_debug (DBG_TRACE, & fnp_dev, "[%u] illegal io_cmd\n", decoded_p->slot_no);
1571 sim_debug (DBG_ERR, & fnp_dev, "[%u]illegal/unimplemented io_cmd (%d) in fnp submbx\n", decoded_p->slot_no, io_cmd);
1572 sim_printf ("illegal/unimplemented io_cmd (%d) in fnp submbx\n", io_cmd);
1573 // doFNPfault (...) // XXX
1574 return -1;
1575 }
1576 } // switch (io_cmd)
1577 return 0;
1578 }
1579
1580 static int interruptL66_CS_done (struct decoded_t *decoded_p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1581 {
1582 uint mbx = decoded_p->cell - 12;
1583 //ASSURE(mbx < 4);
1584 if (mbx >= 4)
1585 {
1586 sim_warn ("bad mbx number in interruptL66_CS_done; dropping\n");
1587 return -1;
1588 }
1589 if (! decoded_p->fudp -> fnpMBXinUse [mbx])
1590 {
1591 sim_debug (DBG_ERR, & fnp_dev, "odd -- Multics marked an unused mbx as unused? cell %d (mbx %d)\n", decoded_p->cell, mbx);
1592 sim_debug (DBG_ERR, & fnp_dev, " %d %d %d %d\n", decoded_p->fudp -> fnpMBXinUse [0], decoded_p->fudp -> fnpMBXinUse [1], decoded_p->fudp -> fnpMBXinUse [2], decoded_p->fudp -> fnpMBXinUse [3]);
1593 }
1594 else
1595 {
1596 sim_debug (DBG_TRACE, & fnp_dev, "Multics marked cell %d (mbx %d) as unused; was %o\n", decoded_p->cell, mbx, decoded_p->fudp -> fnpMBXinUse [mbx]);
1597 decoded_p->fudp -> fnpMBXinUse [mbx] = false;
1598 if (decoded_p->fudp->lineWaiting[mbx])
1599 {
1600 struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->fudp->fnpMBXlineno[mbx]];
1601 sim_debug (DBG_TRACE, & fnp_dev, "clearing wait; was %d\n", linep->waitForMbxDone);
1602 linep->waitForMbxDone = false;
1603 }
1604 sim_debug (DBG_TRACE, & fnp_dev, " %d %d %d %d\n", decoded_p->fudp->fnpMBXinUse [0], decoded_p->fudp->fnpMBXinUse [1], decoded_p->fudp->fnpMBXinUse [2], decoded_p->fudp->fnpMBXinUse [3]);
1605 }
1606 return 0;
1607 }
1608
1609 static int interruptL66 (uint iomUnitIdx, uint chan)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1610 {
1611 struct decoded_t decoded;
1612 struct decoded_t *decoded_p = &decoded;
1613 decoded_p->iom_unit = iomUnitIdx;
1614 decoded_p->chan_num = chan;
1615 decoded_p->devUnitIdx = get_ctlr_idx (iomUnitIdx, chan);
1616 decoded_p->fudp = & fnpData.fnpUnitData [decoded_p->devUnitIdx];
1617 word36 dia_pcw;
1618 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress+DIA_PCW, & dia_pcw, direct_load);
1619
1620 // AN85, pg 13-5
1621 // When the CS has control information or output data to send
1622 // to the FNP, it fills in a submailbox as described in Section 4
1623 // and sends an interrupt over the DIA. This interrupt is handled
1624 // by dail as described above; when the submailbox is read, the
1625 // transaction control word is set to "submailbox read" so that when
1626 // the I/O completes and dtrans runs, the mailbox decoder (decmbx)
1627 // is called. the I/O command in the submail box is either WCD (for
1628 // control information) or WTX (for output data). If it is WCD,
1629 // decmbx dispatches according to a table of operation codes and
1630 // setting a flag in the IB and calling itest, the "test-state"
1631 // entry of the interpreter. n a few cases, the operation requires
1632 // further DIA I/O, but usually all that remains to be does is to
1633 // "free" the submailbox by turning on the corresponding bit in the
1634 // mailbox terminate interrupt multiplex word (see Section 4) and
1635 // set the transaction control word accordingly. When the I/O to
1636 // update TIMW terminates, the transaction is complete.
1637 //
1638 // If the I/O command is WTX, the submailbox contains the
1639 // address and length of a 'pseudo-DCW" list containing the
1640 // addresses and tallies of data buffers in tty_buf. In this case,
1641 // dia_man connects to a DCW list to read them into a reserved area
1642 // in dia_man. ...
1643
1644 // interrupt level (in "cell"):
1645 //
1646 // mbxs 0-7 are CS -> FNP
1647 // mbxs 8--11 are FNP -> CS
1648 //
1649 // 0-7 Multics has placed a message for the FNP in mbx 0-7.
1650 // 8-11 Multics has updated mbx 8-11
1651 // 12-15 Multics is done with mbx 8-11 (n - 4).
1652
1653 decoded_p->cell = getbits36_6 (dia_pcw, 24);
1654 sim_debug (DBG_TRACE, & fnp_dev, "CS interrupt %u\n", decoded_p->cell);
1655 if (decoded_p->cell < 8)
1656 {
1657 interruptL66_CS_to_FNP (decoded_p);
1658 }
1659 else if (decoded_p->cell >= 8 && decoded_p->cell <= 11) //-V560
1660 {
1661 interruptL66_FNP_to_CS (decoded_p);
1662 }
1663 else if (decoded_p->cell >= 12 && decoded_p->cell <= 15) //-V560
1664 {
1665 interruptL66_CS_done (decoded_p);
1666 }
1667 else
1668 {
1669 sim_debug (DBG_ERR, & fnp_dev, "fnp illegal cell number %d\n", decoded_p->cell);
1670 sim_printf ("fnp illegal cell number %d\n", decoded_p->cell);
1671 // doFNPfault (...) // XXX
1672 return -1;
1673 }
1674 return 0;
1675 }
1676
1677 static void fnpcmdBootload (uint devUnitIdx)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1678 {
1679 sim_printf("\r[FNP emulation: FNP %c received BOOTLOAD command]\r\n", (int)('a' + (int)devUnitIdx));
1680 fnpData.fnpUnitData[devUnitIdx].MState.accept_calls = false;
1681 bool have3270 = false;
1682 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
1683 {
1684 fnpData.fnpUnitData[devUnitIdx].MState.line [lineno] . listen = false;
1685 if (fnpData.fnpUnitData[devUnitIdx].MState.line [lineno].line_client)
1686 {
1687 fnpuv_start_writestr (fnpData.fnpUnitData[devUnitIdx].MState.line [lineno].line_client,
1688 (unsigned char *) "\r[FNP emulation: FNP restarted]\r\n");
1689 }
1690 if (fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].service == service_3270)
1691 {
1692 sim_debug (DBG_TRACE, & fnp_dev, "3270 controller found at unit %u line %u\r\n", devUnitIdx, lineno);
1693 // XXX assuming only single controller
1694 if (fnpData.ibm3270ctlr[ASSUME0].configured)
1695 {
1696 sim_warn ("Too many 3270 controllers configured");
1697 }
1698 else
1699 {
1700 have3270 = true;
1701 memset (& fnpData.ibm3270ctlr[ASSUME0], 0, sizeof (struct ibm3270ctlr_s));
1702 fnpData.ibm3270ctlr[ASSUME0].configured = true;
1703 fnpData.ibm3270ctlr[ASSUME0].fnpno = devUnitIdx;
1704 fnpData.ibm3270ctlr[ASSUME0].lineno = lineno;
1705
1706 // 3270 controller connects immediately
1707 // Set from CMF data now.
1708 //fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType = 7 /* LINE_BSC */;
1709 if (fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType == 0) /* LINE_NONE */
1710 fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType = 7; /* LINE_BSC */
1711 fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].accept_new_terminal = true;
1712 }
1713 }
1714 }
1715 (void)fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
1716 if (have3270)
1717 (void)fnpuv3270Init (fnpData.telnet3270_port);
1718 }
1719
1720
1721 static word18 getl6core (uint iom_unit_idx, uint chan, word24 l66addr, uint addr)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1722 {
1723 word24 wos = addr / 2;
1724 word36 word;
1725 iom_direct_data_service (iom_unit_idx, chan, l66addr + wos, & word, direct_load);
1726 if (addr & 1)
1727 return (word18) (word & MASK18);
1728 else
1729 return (word18) ((word >> 18) & MASK18);
1730 }
1731
1732
1733 static void processMBX (uint iomUnitIdx, uint chan)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1734 {
1735 uint fnp_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1736 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
1737
1738 // 60132445 FEP Coupler EPS
1739 // 2.2.1 Control Intercommunication
1740 //
1741 // "In Level 66 memory, at a location known to the coupler and
1742 // to Level 6 software is a mailbox area consisting to an Overhead
1743 // mailbox and 7 Channel mailboxes."
1744
1745 bool ok = true;
1746
1747 word36 dia_pcw;
1748 iom_direct_data_service (iomUnitIdx, chan, fudp->mailboxAddress+DIA_PCW, & dia_pcw, direct_load);
1749 sim_debug (DBG_TRACE, & fnp_dev,
1750 "%s: chan %d dia_pcw %012"PRIo64"\n", __func__, chan, dia_pcw);
1751
1752 // Mailbox word 0:
1753 //
1754 // 0-17 A
1755 // 18 I
1756 // 19-20 MBZ
1757 // 21-22 RFU
1758 // 23 0
1759 // 24-26 B
1760 // 27-29 D Channel #
1761 // 30-35 C Command
1762 //
1763 // A6-A23 A0-A2 A3-A5
1764 // Operation C A B D
1765 // Interrupt L6 071 --- Int. Level
1766 // Bootload L6 072 L66 Addr L66 Addr L66 Addr
1767 // A6-A23 A0-A2 A3-A5
1768 // Interrupt L66 073 --- --- Intr Cell
1769 // Data Xfer to L66 075 L66 Addr L66 Addr L66 Addr
1770 // A6-A23 A0-A2 A3-A5
1771 // Data Xfer to L6 076 L66 Addr L66 Addr L66 Addr
1772 // A6-A23 A0-A2 A3-A5
1773
1774 //
1775 // fnp_util.pl1:
1776 // 075 tandd read
1777 // 076 tandd write
1778
1779 // mbx word 1: mailbox_requests fixed bin
1780 // 2: term_inpt_mpx_wd bit (36) aligned
1781 // 3: last_mbx_req_count fixed bin
1782 // 4: num_in_use fixed bin
1783 // 5: mbx_used_flags
1784 // used (0:7) bit (1) unaligned
1785 // pad2 bit (28) unaligned
1786 // 6,7: crash_data
1787 // fault_code fixed bin (18) unal unsigned
1788 // ic fixed bin (18) unal unsigned
1789 // iom_fault_status fixed bin (18) unal unsigned
1790 // fault_word fixed bin (18) unal unsigned
1791 //
1792 // crash_data according to dn355_boot_interrupt.pl1:
1793 //
1794 // dcl 1 fnp_boot_status aligned based (stat_ptr), /* structure of bootload status */
1795 // 2 real_status bit (1) unaligned, /* must be "1"b in valid status */
1796 // 2 pad1 bit (2) unaligned,
1797 // 2 major_status bit (3) unaligned,
1798 // 2 pad2 bit (3) unaligned,
1799 // 2 substatus fixed bin (8) unal, /* code set by 355, only interesting if major_status is 4 */
1800 // 2 channel_no fixed bin (17) unaligned; /* channel no. of LSLA in case of config error */
1801 // only 34 bits???
1802 // major_status:
1803 // dcl BOOTLOAD_OK fixed bin int static options (constant) init (0);
1804 // dcl CHECKSUM_ERROR fixed bin int static options (constant) init (1);
1805 // dcl READ_ERROR fixed bin int static options (constant) init (2);
1806 // dcl GICB_ERROR fixed bin int static options (constant) init (3);
1807 // dcl INIT_ERROR fixed bin int static options (constant) init (4);
1808 // dcl UNWIRE_STATUS fixed bin int static options (constant) init (5);
1809 // dcl MAX_STATUS fixed bin int static options (constant) init (5);
1810
1811 // 3.5.1 Commands Issued by Central System
1812 //
1813 // In the issuing of an order by the Central System to the Coupler, the
1814 // sequence occurs:
1815 //
1816 // 1. The L66 program creates a LPW and Pcw for the Central System Connect
1817 // channel. It also generates and stores a control word containing a command
1818 // int he L66 mailbox. A Connect is then issued to the L66 IOM.
1819 //
1820 // 2. The Connect Channel accesses the PCW to get the channel number of
1821 // the Direct Channel that the coupler is attached to. the direct Channel
1822 // sends a signal to the Coupler that a Connect has been issued.
1823 //
1824 // 3. The Coupler now reads the content of the L66 mailbox, obtaining the
1825 // control word. If the control word is legal, the Coupler will write a
1826 // word of all zeros into the mailbox.
1827 //
1828
1829 // 4.1.1.2 Transfer Control Word.
1830 // The transfer control word, which is pointed to by the
1831 // mailbox word in l66 memory on Op Codes 72, 7, 76 contains
1832 // a starting address which applies to L6 memory an a Tally
1833 // of the number of 36 bit words to be transferred. The l66
1834 // memory locations to/from which the transfers occur are
1835 // those immediately following the location where this word
1836 // was obtained.
1837 //
1838 // 00-02 001
1839 // 03-17 L6 Address
1840 // 18 P
1841 // 19-23 MBZ
1842 // 24-25 Tally
1843 //
1844 // if P = 0 the l6 address:
1845 // 00-07 00000000
1846 // 08-22 L6 address (bits 3-17)
1847 // 23 0
1848 // if P = 1
1849 // 00-14 L6 address (bits 3-17)
1850 // 15-23 0
1851 //
1852
1853 uint command = getbits36_6 (dia_pcw, 30);
1854 word36 bootloadStatus = 0;
1855
1856 if (command == 000) // reset
1857 {
1858 sim_debug (DBG_TRACE, & fnp_dev,
1859 "%s: chan %d reset command\n", __func__, chan);
1860 send_general_interrupt (iomUnitIdx, chan, imwTerminatePic);
1861 }
1862 else if (command == 072) // bootload
1863 {
1864
1865 word24 l66addr = (((word24) getbits36_6 (dia_pcw, 24)) << 18) |
1866 (word24) getbits36_18 (dia_pcw, 0);
1867
1868 // AN85-01 15-2
1869 // 0 boot dcw
1870 // 1 gicb
1871 // ....
1872 // padding to next multiple of 64
1873 // n core image
1874 //
1875 // where n is (in 36 bit words) (gicb len + 1) + 63 / 64
1876
1877 //sim_printf ("l66addr %08o\n", l66addr);
1878 word36 dcw;
1879 iom_direct_data_service (iomUnitIdx, chan, l66addr, & dcw, direct_load);
1880 word12 tally = getbits36_12 (dcw, 24);
1881 // sim_printf ("%o %d.\n", tally, tally);
1882 //sim_printf ("dcw %012llo\n", dcw);
1883
1884 // Calculate start of core image
1885 word24 image_off = (tally + 64) & 077777700;
1886 // sim_printf ("image_off %o %d.\n", image_off, image_off);
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917 // comm_ref
1918 // 0640 crldt 72
1919 // 0644 crbdt 72
1920 // 0650 crbuf 18
1921 // 0651 crmem 18
1922 // 0652 crnbf 18
1923 // 0653 criom 18
1924
1925 // 2 comm_reg unal, /* software communications region */
1926 // 0640 3 crldt fixed bin (71) aligned, /* date and time binder */
1927 // 0644 3 crbdt fixed bin (71) aligned, /* date and time image booted */
1928 // 0650 3 crbuf fixed bin (17) unal, /* base of free buffer pool */
1929 // 0651 3 crmem fixed bin (18) unsigned unal, /* last loc of mem configured */
1930 // 0652 3 crnbf fixed bin (17) unal, /* free buffers in pool now */
1931 // 0653 3 criom fixed bin (17) unal, /* pointer to iom table */
1932 // 0654 3 crnhs fixed bin (17) unal, /* number of HSLAs */
1933 // 0655 3 crnls fixed bin (17) unal, /* number of LSLAs */
1934 // 0656 3 crcon bit (18) unal, /* console enable switch */
1935 // 0657 3 crmod fixed bin (17) unal, /* base of module chain */
1936 // 3 crnxa fixed bin (17) unal, /* ptr to head of free space chain */
1937 // 3 crtra bit (18) unal, /* trace entry enable mask */
1938 // 3 crtrb fixed bin (18) unsigned unal, /* base of trace table */
1939 // 3 crtrc fixed bin (18) unsigned unal, /* next trace table entry ptr */
1940 // 3 crreg fixed bin (17) unal, /* ptr to fault reg storage area */
1941 // 3 crttb fixed bin (17) unal, /* ptr to tib table base */
1942 // 3 crtte fixed bin (17) unal, /* last addr in tib table */
1943 // 3 crdly fixed bin (17) unal, /* pointer to delay table chain */
1944 // 3 crver char (4) unal, /* mcs version number */
1945 // 3 crbrk fixed bin (17) unal, /* pointer to breakpoint control table */
1946 // 3 crtsw bit (18) unal, /* trace switch (zero=trace on) */
1947 // 3 crnxs fixed bin (17) unal, /* pointer to next free small block */
1948 // 3 crnbs fixed bin (17) unal, /* number of buffers devoted to small space */
1949 // 3 crcct fixed bin (17) unal, /* pointer to first cct descriptor */
1950 // 3 crskd fixed bin (17) unal, /* pointer to scheduler data block */
1951 // 3 cretb fixed bin (17) unal, /* pointer to list of echo-negotiation bit tables */
1952 // 3 crcpt fixed bin (17) unal, /* pointer to cpu page table */
1953 // 3 crpte fixed bin (17) unal, /* pointer to variable cpu page table entry */
1954 // 3 crtsz fixed bin (17) unal, /* size of trace data buffer */
1955 // 3 crmet bit (18) unal, /* metering enabled */
1956 // 3 crtdt bit (18) unal, /* 0 if no COLTS channel; set to TIB address if it exists */
1957 // 3 crbtm bit (18) unal, /* address of time meters for buffer allocation/freeing */
1958 // 3 crnxe fixed bin (18) unsigned unal, /* next available space in extended memory */
1959 // 3 crbpe fixed bin (17) unal, /* buffer paging window table entry */
1960 // 3 pad (39) bit (18) unal,
1961 // 3 crcpr char (28) unal, /* image copyright notice */
1962 // 3 crash_location bit (18) unal, /* offset used for unresolved REF's */
1963 // 3 crash_opcode bit (18) unal, /* crash instruction */
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016 // Number of LSLAs
2017 # ifdef VERBOSE_BOOT
2018 word18 crnls = getl6core (iomUnitIdx, chan, l66addr + image_off, 0655);
2019 sim_printf ("Number of LSLAs (crnls) %d\n", crnls);
2020 # endif
2021
2022 // Address of IOM table
2023 word18 criom = getl6core (iomUnitIdx, chan, l66addr + image_off, 0653);
2024
2025 // Walk the LSLAs in the IOM table
2026 // 2 words/slot (flags, taddr)
2027 // 6 LSLA slots
2028 // first slot at first_lsla_ch 9
2029
2030 bool hdr = false;
2031 # ifdef VERBOSE_BOOT
2032 uint nfound = 0;
2033 # endif /* ifdef VERBOSE_BOOT */
2034 for (uint lsla = 0; lsla < 6; lsla ++)
2035 {
2036 uint slot = lsla + 9;
2037 uint os = slot * 2;
2038 // get flags word
2039 word18 flags = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os);
2040 uint device_type_code = (flags >> 4) & 037;
2041 if (device_type_code == 4)
2042 {
2043 # ifdef VERBOSE_BOOT
2044 nfound ++;
2045 # endif /* ifdef VERBOSE_BOOT */
2046 // get addr word
2047 word18 tblp = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os + 1);
2048 for (uint slot = 0; slot < 52; slot ++)
2049 {
2050 // 2 word18s per entry
2051 // pad bit(11)
2052 // ibm_code bit(1) // if 6-bit odd parity
2053 // pad2 bit(3)
2054 // slot_id bit(3)
2055 //
2056 // ptr bit(18)
2057 word3 slot_id = getl6core (iomUnitIdx, chan, l66addr + image_off, tblp + 2 * slot) & MASK3;
2058 if (slot_id != 7)
2059 {
2060 # ifdef VERBOSE_BOOT
2061 char * slot_ids [8] =
2062 {
2063 "10 cps",
2064 "30 cps, slot 1",
2065 "30 cps, slot 2",
2066 "30 cps, slot 3",
2067 "invalid",
2068 "15 cps, slot 1",
2069 "15 cps, slot 2",
2070 "unused"
2071 };
2072 char * id = slot_ids[slot_id];
2073 # endif /* ifdef VERBOSE_BOOT */
2074 if (! hdr)
2075 {
2076 hdr = true;
2077 # ifdef VERBOSE_BOOT
2078 sim_printf ("LSLA table: card number, slot, slot_id, slot_id string\n");
2079 # endif /* ifdef VERBOSE_BOOT */
2080 }
2081 # ifdef VERBOSE_BOOT
2082 sim_printf ("%d %2d %d %s\n", lsla, slot, slot_id, id);
2083 # endif /* ifdef VERBOSE_BOOT */
2084 }
2085 } // for slot
2086 } // if dev type 4 (LSLA)
2087 } // iom table entry
2088 # ifdef VERBOSE_BOOT
2089 if (nfound != crnls)
2090 sim_printf ("LSLAs configured %d found %d\n", crnls, nfound);
2091 # endif /* ifdef VERBOSE_BOOT */
2092
2093 // Number of HSLAs
2094 # ifdef VERBOSE_BOOT
2095 word18 crnhs = getl6core (iomUnitIdx, chan, l66addr + image_off, 0654);
2096 sim_printf ("Number of HSLAs (crnhs) %d\n", crnhs);
2097 # endif /* ifdef VERBOSE_BOOT */
2098
2099 // Walk the HSLAs in the IOM table
2100 // 2 words/slot (flags, taddr)
2101 // 3 LSLA slots
2102 // first slot at first_hsla_ch 6
2103
2104 hdr = false;
2105 # ifdef VERBOSE_BOOT
2106 nfound = 0;
2107 # endif /* ifdef VERBOSE_BOOT */
2108 for (uint hsla = 0; hsla < 3; hsla ++)
2109 {
2110 uint slot = hsla + 6;
2111 uint os = slot * 2;
2112 // get flags word
2113 word18 flags = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os);
2114 uint device_type_code = (flags >> 4) & 037;
2115 if (device_type_code == 3)
2116 {
2117 # ifdef VERBOSE_BOOT
2118 nfound ++;
2119 # endif /* ifdef VERBOSE_BOOT */
2120 // get addr word
2121 word18 tblp = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os + 1);
2122 for (uint slot = 0; slot < 32; slot ++)
2123 {
2124 // 2 word18s per entry
2125 // conc_chan bit(1)
2126 // private_line bit(1)
2127 // async bit(1)
2128 // option1 bit(1)
2129 // option2 bit(1)
2130 // modem_type bit(4)
2131 // line_type bit(5)
2132 // dev_speed bit(4)
2133 //
2134 // ptr bit(18)
2135
2136 # ifdef VERBOSE_BOOT
2137 char * line_types[23] =
2138 {
2139 "none ",
2140 "ASCII ",
2141 "1050 ",
2142 "2741 ",
2143 "ARDS ",
2144 "Sync ",
2145 "G115 ",
2146 "BSC ",
2147 "202ETX ",
2148 "VIP ",
2149 "ASYNC1 ",
2150 "ASYNC2 ",
2151 "ASYNC3 ",
2152 "SYNC1 ",
2153 "SYNC2 ",
2154 "SYNC3 ",
2155 "POLLED_VIP",
2156 "X25LAP ",
2157 "HDLC ",
2158 "COLTS ",
2159 "DSA ",
2160 "HASP_OPR ",
2161 "invalid "
2162 };
2163 # endif
2164
2165 # ifdef VERBOSE_BOOT
2166 char * modem_types[8] =
2167 {
2168 "invalid ",
2169 "Bell 103A/113",
2170 "Bell 201C ",
2171 "Bell 202C5 ",
2172 "Bell 202C6 ",
2173 "Bell 208A ",
2174 "Bell 208B ",
2175 "Bell 209A "
2176 };
2177 # endif
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210 # ifdef VERBOSE_BOOT
2211 char * async_speeds[16] =
2212 {
2213 "invalid",
2214 "110 ",
2215 "133 ",
2216 "150 ",
2217 "300 ",
2218 "600 ",
2219 "1200 ",
2220 "1800 ",
2221 "2400 ",
2222 "4800 ",
2223 "7200 ",
2224 "9600 ",
2225 "19200 ",
2226 "40800 ",
2227 "50000 ",
2228 "72000 "
2229 };
2230
2231 char * sync_speeds[16] =
2232 {
2233 "invalid",
2234 "2000 ",
2235 "2400 ",
2236 "3600 ",
2237 "4800 ",
2238 "5400 ",
2239 "7200 ",
2240 "9600 ",
2241 "19200 ",
2242 "40800 ",
2243 "50000 ",
2244 "invalid",
2245 "invalid",
2246 "invalid",
2247 "invalid",
2248 "invalid"
2249 };
2250 # endif
2251 word18 subch_data = getl6core (iomUnitIdx, chan, l66addr + image_off, tblp + 2 * slot);
2252 # ifdef VERBOSE_BOOT
2253 word1 async = (subch_data >> 15) & 1;
2254 word1 option1 = (subch_data >> 14) & 1;
2255 # endif
2256 word5 line_type = (subch_data >> 4) & MASK5;
2257 if (line_type > 22)
2258 line_type = 22;
2259 word4 modem_type = (subch_data >> 9) & MASK4;
2260 if (modem_type > 7)
2261 modem_type = 0;
2262 # ifdef VERBOSE_BOOT
2263 word4 dev_speed = subch_data & MASK4;
2264 //if (dev_speed > 10)
2265 //dev_speed = 0;
2266 char * speed = async ? async_speeds[dev_speed] : sync_speeds[dev_speed];
2267 if (async && dev_speed == 4 && option1)
2268 speed = "auto ";
2269 # endif
2270 if (! hdr)
2271 {
2272 hdr = true;
2273 # ifdef VERBOSE_BOOT
2274 sim_printf ("HSLA table: card number, slot, "
2275 "sync/async, line type, modem_type, "
2276 "speed\n");
2277 # endif
2278 }
2279 # ifdef VERBOSE_BOOT
2280 sim_printf ("%d %2d %s %s %s %s\n",
2281 hsla, slot, async ? "async" :"sync ",
2282 line_types[line_type],
2283 modem_types[modem_type],
2284 speed);
2285 # endif
2286 uint lineno = hsla * 32u + slot;
2287 struct t_line * linep = & fudp->MState.line[lineno];
2288
2289
2290
2291
2292
2293
2294
2295 //linep->lineType = line_type ? line_type : 1; // Map none to ASCII
2296 linep->lineType = line_type;
2297 } // for slot
2298 } // if dev type 4 (LSLA)
2299 } // iom table entry
2300 # ifdef VERBOSE_BOOT
2301 if (nfound != crnls)
2302 sim_printf ("LSLAs configured %d found %d\n", crnls, nfound);
2303 # endif /* ifdef VERBOSE_BOOT */
2304
2305
2306 #if defined(THREADZ) || defined(LOCKLESS)
2307 lock_libuv ();
2308 #endif
2309 fnpcmdBootload (fnp_unit_idx);
2310 #if defined(THREADZ) || defined(LOCKLESS)
2311 unlock_libuv ();
2312 #endif
2313 send_general_interrupt (iomUnitIdx, chan, imwTerminatePic);
2314 fudp -> fnpIsRunning = true;
2315 }
2316 else if (command == 071) // interrupt L6
2317 {
2318 #if defined(THREADZ) || defined(LOCKLESS)
2319 lock_libuv ();
2320 #endif
2321 ok = interruptL66 (iomUnitIdx, chan) == 0;
2322 #if defined(THREADZ) || defined(LOCKLESS)
2323 unlock_libuv ();
2324 #endif
2325 }
2326 else if (command == 075) // data xfer from L6 to L66
2327 {
2328 // Build the L66 address from the PCW
2329 // 0-17 A
2330 // 24-26 B
2331 // 27-29 D Channel #
2332 // Operation C A B D
2333 // Data Xfer to L66 075 L66 Addr L66 Addr L66 Addr
2334 // A6-A23 A0-A2 A3-A5
2335 // These don't seem to be right; M[L66Add] is always 0.
2336 //word24 A = (word24) getbits36_18 (dia_pcw, 0);
2337 //word24 B = (word24) getbits36_3 (dia_pcw, 24);
2338 //word24 D = (word24) getbits36_3 (dia_pcw, 29);
2339 //word24 L66Addr = (B << (24 - 3)) | (D << (24 - 3 - 3)) | A;
2340
2341 // According to fnp_util:
2342 // dcl 1 a_dia_pcw aligned based (mbxp), /* better declaration than the one used when MCS is running */
2343 // 2 address fixed bin (18) unsigned unaligned,
2344 // 2 error bit (1) unaligned,
2345 // 2 pad1 bit (3) unaligned,
2346 // 2 parity bit (1) unaligned,
2347 // 2 pad2 bit (1) unaligned,
2348 // 2 pad3 bit (3) unaligned, /* if we used address extension this would be important */
2349 // 2 interrupt_level fixed bin (3) unsigned unaligned,
2350 // 2 command bit (6) unaligned;
2351 //
2352 // a_dia_pcw.address = address;
2353 //
2354
2355 //word24 L66Addr = (word24) getbits36_18 (dia_pcw, 0);
2356 //sim_printf ("L66 xfer\n");
2357 //sim_printf ("PCW %012"PRIo64"\n", dia_pcw);
2358 //sim_printf ("L66Addr %08o\n", L66Addr);
2359 //sim_printf ("M[] %012"PRIo64"\n", M[L66Addr]);
2360
2361 // 'dump_mpx d'
2362 //L66 xfer
2363 //PCW 022002000075
2364 //L66Addr 00022002
2365 //M[] 000000401775
2366 //L66 xfer
2367 //PCW 022002000075
2368 //L66Addr 00022002
2369 //M[] 003772401775
2370 //L66 xfer
2371 //PCW 022002000075
2372 //L66Addr 00022002
2373 //M[] 007764401775
2374 //
2375 // The contents of M seem much more reasonable, bit still don't match
2376 // fnp_util$setup_dump_ctl_word. The left octet should be '1', not '0';
2377 // bit 18 should be 0 not 1. But the offsets and tallies match exactly.
2378 // Huh... Looking at 'dump_6670_control' control instead, it matches
2379 // correctly. Apparently fnp_util thinks the FNP is a 6670, not a 335.
2380 // I can't decipher the call path, so I don't know why; but looking at
2381 // multiplexer_types.incl.pl1, I would guess that by MR12.x, all FNPs
2382 // were 6670s.
2383 //
2384 // So:
2385 //
2386 // dcl 1 dump_6670_control aligned based (data_ptr), /* word used to supply DN6670 address and tally for fdump */
2387 // 2 fnp_address fixed bin (18) unsigned unaligned,
2388 // 2 unpaged bit (1) unaligned,
2389 // 2 mbz bit (5) unaligned,
2390 // 2 tally fixed bin (12) unsigned unaligned;
2391
2392 // Since the data is marked 'paged', and I don't understand the
2393 // the paging mechanism or parameters, I'm going to punt here and
2394 // not actually transfer any data.
2395
2396 }
2397 else
2398 {
2399 sim_warn ("bogus fnp command %d (%o)\n", command, command);
2400 ok = false;
2401 }
2402
2403 if (ok)
2404 {
2405 #ifdef TESTING
2406 if_sim_debug (DBG_TRACE, & fnp_dev) dmpmbx (fudp->mailboxAddress);
2407 #endif
2408 //iom_chan_data [iomUnitIdx] [chan] . in_use = false;
2409 dia_pcw = 0;
2410 iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+DIA_PCW, & dia_pcw, direct_store);
2411 putbits36_1 (& bootloadStatus, 0, 1); // real_status = 1
2412 putbits36_3 (& bootloadStatus, 3, 0); // major_status = BOOTLOAD_OK;
2413 putbits36_8 (& bootloadStatus, 9, 0); // substatus = BOOTLOAD_OK;
2414 putbits36_17 (& bootloadStatus, 17, 0); // channel_no = 0;
2415 iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+CRASH_DATA, & bootloadStatus, direct_store);
2416 }
2417 else
2418 {
2419 #ifdef TESTING
2420 if_sim_debug (DBG_TRACE, & fnp_dev) dmpmbx (fudp->mailboxAddress);
2421 #endif
2422 // 3 error bit (1) unaligned, /* set to "1"b if error on connect */
2423 //iom_chan_data [iomUnitIdx] [chan] . in_use = false;
2424 putbits36_1 (& dia_pcw, 18, 1); // set bit 18
2425 iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+DIA_PCW, & dia_pcw, direct_store);
2426 }
2427 }
2428
2429 static int fnpCmd (uint iomUnitIdx, uint chan) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
2430 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
2431
2432 switch (p->IDCW_DEV_CMD) {
2433 case 000: { // CMD 00 Request status
2434 p->stati = 04000;
2435 processMBX (iomUnitIdx, chan);
2436 // no status_service and no additional terminate interrupt
2437 // ???
2438 }
2439 return IOM_CMD_DISCONNECT;
2440
2441 default: {
2442 p->stati = 04501; // cmd reject, invalid opcode
2443 p->chanStatus = chanStatIncorrectDCW;
2444 if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
2445 sim_warn ("%s: FNP unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
2446 }
2447 return IOM_CMD_ERROR;
2448 }
2449 }
2450
2451 /*
2452 * fnp_iom_cmd()
2453 *
2454 */
2455
2456 iom_cmd_rc_t fnp_iom_cmd (uint iomUnitIdx, uint chan) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
2457 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
2458 // Is it an IDCW?
2459
2460 if (IS_IDCW (p)) {
2461 return fnpCmd (iomUnitIdx, chan);
2462 }
2463 // else // DDCW/TDCW
2464 sim_warn ("%s expected IDCW\n", __func__);
2465 return IOM_CMD_ERROR;
2466 }