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-2022 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
955 /*NOTREACHED*/ /* unreachable */
956
957 // dcl 1 fnp_channel_meters based aligned,
958 struct fnp_channel_meters //-V779
959 {
960 // 2 header,
961 struct header //-V779
962 { //-V779
963 // 3 dia_request_q_len fixed bin (35), /* cumulative */
964 word36 dia_request_q_len; //-V779
965 // 3 dia_rql_updates fixed bin (35), /* updates to above */
966 word36 dia_rql_updates; //-V779
967 // 3 pending_status fixed bin (35), /* cumulative */
968 word36 pending_status; //-V779
969 // 3 pending_status_updates fixed bin (35), /* updates to above */
970 word36 pending_status_updates; //-V779
971 // 3 output_overlaps fixed bin (18) unsigned unaligned, /* output chained to already-existing chain */
972 // 3 parity_errors fixed bin (18) unsigned unaligned, /* parity on the channel */
973 word36 output_overlaps___parity_errors; //-V779
974 // 3 software_status_overflows fixed bin (18) unsigned unaligned,
975 // 3 hardware_status_overflows fixed bin (18) unsigned unaligned,
976 word36 software_status_overflows___hardware_status_overflows; //-V779
977 // 3 input_alloc_failures fixed bin (18) unsigned unaligned,
978 // 3 dia_current_q_len fixed bin (18) unsigned unaligned, /* current length of dia request queue */
979 word36 input_alloc_failures___dia_current_q_len; //-V779
980 // 3 exhaust fixed bin (35),
981 word36 exhaust; //-V779
982 // 3 software_xte fixed bin (18) unsigned unaligned,
983 // 3 pad bit (18) unaligned,
984 word36 software_xte___sync_or_async; //-V779
985 } header; //-V779
986 // 2 sync_or_async (17) fixed bin; /* placeholder for meters for sync or async channels */
987 word36 sync_or_async; //-V779
988 }; //-V779
989
990 //
991 // dcl 1 fnp_sync_meters based aligned,
992 // 2 header like fnp_channel_meters.header,
993 // 2 input,
994 // 3 message_count fixed bin (35), /* total number of messages */
995 // 3 cum_length fixed bin (35), /* total cumulative length in characters */
996 // 3 min_length fixed bin (18) unsigned unaligned, /* length of shortest message */
997 // 3 max_length fixed bin (18) unsigned unaligned, /* length of longest message */
998 // 2 output like fnp_sync_meters.input,
999 // 2 counters (8) fixed bin (35),
1000 // 2 pad (3) fixed bin;
1001 //
1002 // dcl 1 fnp_async_meters based aligned,
1003 struct fnp_async_meters //-V779
1004 { //-V779
1005 // 2 header like fnp_channel_meters.header,
1006 // 2 pre_exhaust fixed bin (35),
1007 word36 pre_exhaust; //-V779
1008 // 2 echo_buf_overflow fixed bin (35), /* number of times echo buffer has overflowed */
1009 word36 echo_buf_overflow; //-V779
1010 // 2 bell_quits fixed bin (18) unsigned unaligned,
1011 // 2 padb bit (18) unaligned,
1012 word36 bell_quits___pad; //-V779
1013 // 2 pad (14) fixed bin;
1014 word36 pad; //-V779
1015 }; //-V779
1016 //
1017 case 36: // report_meters
1018 {
1019 sim_debug (DBG_TRACE, & fnp_dev, "[%u] report_meters\n", decoded_p->slot_no);
1020 //sim_printf ("fnp report_meters\n");
1021 // XXX Do nothing, the request will timeout...
1022 }
1023 break;
1024
1025 case 0: // terminal_accepted
1026 case 2: // disconnect_all_lines
1027 case 5: // input_accepted
1028 case 7: // enter_receive
1029 case 9: // blast
1030 case 10: // accept_direct_output
1031 case 11: // accept_last_output
1032 //case 13: // ???
1033 case 14: // reject_request_temp
1034 //case 15: // ???
1035 case 16: // terminal_rejected
1036 case 17: // disconnect_accepted
1037 case 18: // init_complete
1038 case 19: // dump_mem
1039 case 20: // patch_mem
1040 case 21: // fnp_break
1041 //case 24: // set_echnego_break_table
1042 //case 25: // start_negotiated_echo
1043 //case 26: // stop_negotiated_echo
1044 //case 27: // init_echo_negotiation
1045 //case 28: // ???
1046 case 29: // break_acknowledged
1047 //case 32: // ???
1048 //case 33: // ???
1049 case 35: // checksum_error
1050 {
1051 sim_debug (DBG_TRACE, & fnp_dev, "[%u] unimplemented opcode\n", decoded_p->slot_no);
1052 sim_warn ("fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1053 //sim_debug (DBG_ERR, & fnp_dev, "fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1054 //sim_printf ("fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1055 // doFNPfault (...) // XXX
1056 //return -1;
1057 }
1058 break;
1059
1060 default:
1061 {
1062 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);
1063 // doFNPfault (...) // XXX
1064 return -1;
1065 }
1066 } // switch decoded_p->op_code
1067
1068 setTIMW (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress, (int) decoded_p->cell);
1069
1070 send_general_interrupt (decoded_p->iom_unit, decoded_p->chan_num, imwTerminatePic);
1071
1072 return 0;
1073 }
1074
1075 #ifdef TUN
1076 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)
*/
1077 {
1078
1079
1080
1081
1082
1083 // XXX this code is buggy; if a buffer is received with an embedded frame start, the embedded frame
1084 // XXX will be lost
1085
1086 for (uint i = 0; i < tally; i ++)
1087 {
1088 // Check for start of frame...
1089 if (data [i] == 0x100)
1090 {
1091 linep->in_frame = true;
1092 linep->frameLen = 0;
1093 continue;
1094 }
1095
1096 if (! linep->in_frame)
1097 continue;
1098
1099 if (linep->frameLen >= 2+1500)
1100 {
1101 sim_printf ("inFrame overrun\n");
1102 break;
1103 }
1104 linep->frame[linep->frameLen ++] = (uint8_t) (data [i] & 0xff);
1105 }
1106
1107 // Is frame complete?
1108
1109 if (linep->frameLen >= 2)
1110 {
1111 uint16_t target = (uint16_t) ((linep->frame[0] & 0xff) << 8) | (linep->frame[1]);
1112 if (target + 2 >= linep->frameLen)
1113 {
1114 sim_printf ("frame received\n");
1115 fnpuv_tun_write (linep);
1116 linep->in_frame = false;
1117 }
1118 }
1119 }
1120 #endif
1121
1122 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)
*/
1123 {
1124 sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd wtx_output\n", decoded_p->slot_no);
1125 struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->slot_no];
1126
1127 uint wordOff = 0;
1128 word36 word = 0;
1129 uint lastWordOff = (uint) -1;
1130 #ifdef TUN
1131 uint16_t data9 [tally];
1132 #endif
1133 unsigned char data [tally];
1134
1135 for (uint i = 0; i < tally; i ++)
1136 {
1137 uint byteOff = i % 4;
1138 uint byte = 0;
1139
1140 wordOff = i / 4;
1141
1142 if (wordOff != lastWordOff)
1143 {
1144 lastWordOff = wordOff;
1145 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, dataAddr + wordOff, & word, direct_load);
1146 }
1147 byte = getbits36_9 (word, byteOff * 9);
1148 data [i] = byte & 0377;
1149 #ifdef TUN
1150 data9 [i] = (uint16_t) byte;
1151 #endif
1152
1153 //sim_printf (" %03o %c\n", data [i], isgraph (data [i]) ? data [i] : '.');
1154 }
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169 #ifdef TUN
1170 if (linep->is_tun && tally > 0)
1171 {
1172 tun_write (linep, data9, tally);
1173 return;
1174 }
1175 #endif
1176 if (tally > 0 && linep->line_client)
1177 {
1178 if (! linep->line_client || ! linep->line_client->data) //-V560
1179 {
1180 sim_warn ("fnp_wtx_output bad client data\r\n");
1181 return;
1182 }
1183 uvClientData * p = linep->line_client->data;
1184 (* p->write_cb) (linep->line_client, data, tally);
1185 }
1186 }
1187
1188 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)
*/
1189 {
1190 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);
1191 //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);
1192 if (decoded_p->op_code != 012 && decoded_p->op_code != 014) //-V536
1193 {
1194 sim_debug (DBG_TRACE, & fnp_dev, "[%u] unimplemented opcode\n", decoded_p->slot_no);
1195 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);
1196 sim_printf ("fnp wtx unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1197 // doFNPfault (...) // XXX
1198 return -1;
1199 }
1200 // op_code is 012
1201 word36 data;
1202 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->smbx+WORD6, & data, direct_load);
1203 uint dcwAddr = getbits36_18 (data, 0);
1204 uint dcwCnt = getbits36_9 (data, 27);
1205 //uint sent = 0;
1206
1207 // For each dcw
1208 for (uint i = 0; i < dcwCnt; i ++)
1209 {
1210 // The address of the dcw in the dcw list
1211 // The dcw
1212 word36 dcw;
1213 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, dcwAddr + i, & dcw, direct_load);
1214
1215 // Get the address and the tally from the dcw
1216 uint dataAddr = getbits36_18 (dcw, 0);
1217 uint tally = getbits36_9 (dcw, 27);
1218 //sim_printf ("%6d %012o\n", tally, dataAddr);
1219 if (! tally)
1220 continue;
1221 fnp_wtx_output (decoded_p, tally, dataAddr);
1222 //sent += tally;
1223 } // for each dcw
1224
1225 setTIMW (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress, (int) decoded_p->cell);
1226
1227 send_general_interrupt (decoded_p->iom_unit, decoded_p->chan_num, imwTerminatePic);
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239 decoded_p->fudp->MState.line[decoded_p->slot_no].send_output = SEND_OUTPUT_DELAY;
1240
1241 return 0;
1242 }
1243
1244 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)
*/
1245 {
1246 // AN85-01 pg 232 A-6
1247 //
1248 // Input Accepted (005)
1249 //
1250 // Purpose:
1251 // Response to an accept input operation by providing the address
1252 // (in the circular buffer) to which input is sent.
1253 //
1254 // Associated Data:
1255 // Word 5: Bits 0..17 contain the beginning absolute address of the
1256 // portion of the circular buffer into which the input is to be placed.
1257 //
1258 // Bits 18...35 contain the number of characters to be placed in the
1259 // specified location.
1260 //
1261 // Word 4: If non-zero, contains the address and tally as described
1262 // above for the remaining data. This word is only used if the input
1263 // request required a wraparound of the circular buffer.
1264 //
1265
1266 word36 word2;
1267 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+WORD2, & word2, direct_load);
1268 uint n_chars = getbits36_18 (word2, 0);
1269
1270 word36 n_buffers;
1271 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+N_BUFFERS, & n_buffers, direct_load);
1272
1273 struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->slot_no];
1274 unsigned char * data_p = linep -> buffer;
1275
1276 n_chars = min(n_chars, linep -> nPos);
1277
1278 uint off = 0;
1279 for (uint j = 0; j < n_buffers && off < n_chars; j++)
1280 {
1281 word36 data;
1282 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+DCWS+j, & data, direct_load);
1283 word24 addr = getbits36_24 (data, 0);
1284 word12 tally = getbits36_12 (data, 24);
1285
1286 if_sim_debug (DBG_TRACE, & fnp_dev) {
1287 { sim_printf ("[%u][FNP emulator: nPos %d long IN: '", decoded_p->slot_no, linep->nPos);
1288 for (uint i = 0; i < linep->nPos; i ++)
1289 {
1290 if (isgraph (linep->buffer [i]))
1291 sim_printf ("%c", linep->buffer [i]);
1292 else
1293 sim_printf ("\\%03o", linep->buffer [i]);
1294 }
1295 sim_printf ("']\n");
1296 }
1297 }
1298
1299 //sim_printf ("long in; line %d tally %d\n", decoded_p->slot_no, linep->nPos);
1300 uint n_chars_in_buf = min(n_chars-off, tally);
1301 for (uint i = 0; i < n_chars_in_buf; i += 4)
1302 {
1303 word36 v = 0;
1304 if (i < n_chars_in_buf) //-V547
1305 putbits36_9 (& v, 0, data_p [off++]);
1306 if (i + 1 < n_chars_in_buf)
1307 putbits36_9 (& v, 9, data_p [off++]);
1308 if (i + 2 < n_chars_in_buf)
1309 putbits36_9 (& v, 18, data_p [off++]);
1310 if (i + 3 < n_chars_in_buf)
1311 putbits36_9 (& v, 27, data_p [off++]);
1312 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, addr, & v, direct_store);
1313 addr ++;
1314 }
1315 }
1316 // XXX temporary until the logic is in place
1317 // This appears to only be used in tty_interrupt.pl1 as
1318 // rtx_info.output_in_fnp as part of echo negotiation:
1319 // if ^rtx_info.output_in_fnp /* if there's no output going on */
1320 // So apparently a flag indicating that there is output queued.
1321 word1 output_chain_present = 1;
1322
1323 word36 v;
1324 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+INP_COMMAND_DATA, &v, direct_load);
1325 l_putbits36_1 (& v, 16, output_chain_present);
1326 l_putbits36_1 (& v, 17, linep->input_break ? 1 : 0);
1327 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+INP_COMMAND_DATA, &v, direct_store);
1328
1329 // Mark the line as ready to receive more data
1330 linep->input_reply_pending = false;
1331 linep->input_break = false;
1332 linep->nPos = 0;
1333
1334 setTIMW (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress, (int) decoded_p->cell);
1335
1336 send_general_interrupt (decoded_p->iom_unit, decoded_p->chan_num, imwTerminatePic);
1337 }
1338
1339 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)
*/
1340 {
1341 uint mbx = decoded_p->cell;
1342 //ASSURE(mbx < 8);
1343 if (mbx >= 8)
1344 {
1345 sim_warn ("bad mbx number in interruptL66_CS_to_FNP; dropping\n");
1346 return -1;
1347 }
1348 decoded_p->smbx = decoded_p->fudp->mailboxAddress + DN355_SUB_MBXES + mbx*DN355_SUB_MBX_SIZE;
1349
1350 word36 word2;
1351 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->smbx+WORD2, & word2, direct_load);
1352 //uint cmd_data_len = getbits36_9 (word2, 9);
1353 decoded_p->op_code = getbits36_9 (word2, 18);
1354 uint io_cmd = getbits36_9 (word2, 27);
1355
1356 word36 word1;
1357 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->smbx+WORD1, & word1, direct_load);
1358 decoded_p->slot_no = getbits36_6 (word1, 12);
1359
1360 sim_debug (DBG_TRACE, & fnp_dev, "io_cmd %u\n", io_cmd);
1361 switch (io_cmd)
1362 {
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372 case 3: // wcd (write control data)
1373 {
1374 int ret = wcd (decoded_p);
1375 if (ret)
1376 return ret;
1377 }
1378 break;
1379
1380 case 4: // wtx (write text)
1381 {
1382 int ret = wtx (decoded_p);
1383 if (ret)
1384 return ret;
1385 }
1386 break;
1387
1388 case 1: // rcd (read control data)
1389 {
1390 sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd unimplemented\n", decoded_p->slot_no);
1391 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp unimplemented io_cmd %d\n", decoded_p->slot_no, io_cmd);
1392 sim_printf ("fnp unimplemented io_cmd %d\n", io_cmd);
1393 // doFNPfault (...) // XXX
1394 return -1;
1395 }
1396 default:
1397 {
1398 sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd illegal opcode\n", decoded_p->slot_no);
1399 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp illegal io_cmd %d\n", decoded_p->slot_no, io_cmd);
1400 sim_printf ("fnp illegal io_cmd %d\n", io_cmd);
1401 // doFNPfault (...) // XXX
1402 return -1;
1403 }
1404 } // switch (io_cmd)
1405 return 0;
1406 }
1407
1408 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)
*/
1409 {
1410 // The CS has updated the FNP sub mailbox; this acknowledges processing
1411 // of the FNP->CS command that was in the submailbox
1412
1413 uint mbx = decoded_p->cell - 8;
1414 //ASSURE(mbx < 4);
1415 if (mbx >= 4)
1416 {
1417 sim_warn ("bad mbx number in interruptL66_FNP_to_CS; dropping\n");
1418 return -1;
1419 }
1420 decoded_p->fsmbx = decoded_p->fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
1421
1422
1423
1424
1425
1426
1427
1428
1429 word36 word2;
1430 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+WORD2, & word2, direct_load);
1431 //uint cmd_data_len = getbits36_9 (word2, 9);
1432 uint op_code = getbits36_9 (word2, 18);
1433 uint io_cmd = getbits36_9 (word2, 27);
1434
1435 word36 word1;
1436 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fsmbx+WORD1, & word1, direct_load);
1437 //uint dn355_no = getbits36_3 (word1, 0);
1438 //uint is_hsla = getbits36_1 (word1, 8);
1439 //uint la_no = getbits36_3 (word1, 9);
1440 decoded_p->slot_no = getbits36_6 (word1, 12);
1441 //uint terminal_id = getbits36_18 (word1, 18);
1442
1443 sim_debug (DBG_TRACE, & fnp_dev, "[%u]fnp interrupt\n", decoded_p->slot_no);
1444 switch (io_cmd)
1445 {
1446 case 2: // rtx (read transmission)
1447 {
1448 sim_debug (DBG_TRACE, & fnp_dev, "[%u] rtx\n", decoded_p->slot_no);
1449 switch (op_code)
1450 {
1451 case 5: // input_accepted
1452 {
1453 sim_debug (DBG_TRACE, & fnp_dev, "[%u] input_accepted\n", decoded_p->slot_no);
1454 fnp_rtx_input_accepted (decoded_p);
1455 }
1456 break;
1457 default:
1458 sim_debug (DBG_TRACE, & fnp_dev, "[%u] illegal rtx ack\n", decoded_p->slot_no);
1459 sim_warn ("rtx %d. %o ack ignored\n", op_code, op_code);
1460 break;
1461 }
1462 break;
1463 }
1464 case 3: // wcd (write control data)
1465 {
1466 sim_debug (DBG_TRACE, & fnp_dev, "[%u] wcd\n", decoded_p->slot_no);
1467 switch (op_code)
1468 {
1469 case 0: // terminal_accepted
1470 {
1471 sim_debug (DBG_TRACE, & fnp_dev, "[%u] terminal accepted\n", decoded_p->slot_no);
1472 // outputBufferThreshold Ignored
1473 //word36 command_data0 = decoded_p->fsmbxp -> mystery [0];
1474 //uint outputBufferThreshold = getbits36_18 (command_data0, 0);
1475 //sim_printf (" outputBufferThreshold %d\n", outputBufferThreshold);
1476
1477 // Prime the pump
1478 //decoded_p->fudp->MState.line[decoded_p->slot_no].send_output = true;
1479 decoded_p->fudp->MState.line[decoded_p->slot_no].send_output = SEND_OUTPUT_DELAY;
1480 // XXX XXX XXX XXX
1481 // For some reason the CS ack of accept_new_terminal is not being seen, causing the line to wedge.
1482 // Since a terminal accepted command always follows, clear the wedge here
1483 decoded_p->fudp->MState.line[decoded_p->slot_no].waitForMbxDone = false;
1484 }
1485 break;
1486
1487 case 1: // disconnect_this_line
1488 {
1489 sim_debug (DBG_TRACE, & fnp_dev, "[%u] disconnect_this_line\n", decoded_p->slot_no);
1490 //sim_printf ("disconnect_this_line ack.\n");
1491 }
1492 break;
1493
1494 case 14: // reject_request_temp
1495 {
1496 sim_printf ("reject_request_temp\r\n");
1497 sim_debug (DBG_TRACE, & fnp_dev, "[%u] reject_request_temp\n", decoded_p->slot_no);
1498 //sim_printf ("fnp reject_request_temp\n");
1499 // Retry in one second;
1500 decoded_p->fudp->MState.line[decoded_p->slot_no].accept_input = 100;
1501 }
1502 break;
1503
1504 case 2: // disconnect_all_lines
1505 case 3: // dont_accept_calls
1506 case 4: // accept_calls
1507 case 5: // input_accepted
1508 case 6: // set_line_type
1509 case 7: // enter_receive
1510 case 8: // set_framing_chars
1511 case 9: // blast
1512 case 10: // accept_direct_output
1513 case 11: // accept_last_output
1514 case 12: // dial
1515 //case 13: // ???
1516 //case 15: // ???
1517 case 16: // terminal_rejected
1518 case 17: // disconnect_accepted
1519 case 18: // init_complete
1520 case 19: // dump_mem
1521 case 20: // patch_mem
1522 case 21: // fnp_break
1523 case 22: // line_control
1524 case 23: // sync_msg_size
1525 case 24: // set_echnego_break_table
1526 case 25: // start_negotiated_echo
1527 case 26: // stop_negotiated_echo
1528 case 27: // init_echo_negotiation
1529 //case 28: // ???
1530 case 29: // break_acknowledged
1531 case 30: // input_fc_chars
1532 case 31: // output_fc_chars
1533 //case 32: // ???
1534 //case 33: // ???
1535 case 34: // alter_parameters
1536 case 35: // checksum_error
1537 case 36: // report_meters
1538 case 37: // set_delay_table
1539 {
1540 sim_debug (DBG_TRACE, & fnp_dev, "[%u] unimplemented opcode\n", decoded_p->slot_no);
1541 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp reply unimplemented opcode %d (%o)\n", decoded_p->slot_no, op_code, op_code);
1542 sim_printf ("fnp reply unimplemented opcode %d (%o)\n", op_code, op_code);
1543 // doFNPfault (...) // XXX
1544 return -1;
1545 }
1546
1547 default:
1548 {
1549 sim_debug (DBG_TRACE, & fnp_dev, "[%u] illegal opcode\n", decoded_p->slot_no);
1550 sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp reply illegal opcode %d (%o)\n", decoded_p->slot_no, op_code, op_code);
1551 sim_printf ("fnp reply illegal opcode %d (%o)\n", op_code, op_code);
1552 // doFNPfault (...) // XXX
1553 return -1;
1554 }
1555 } // switch op_code
1556
1557 // Set the TIMW
1558
1559 // Not sure... XXX
1560 //putbits36_1 (& mbxp -> term_inpt_mpx_wd, cell, 1);
1561 // No; the CS has told us it has updated the mbx, and
1562 // we need to read it; we have done so, so we are finished
1563 // with the mbx, and can mark it so.
1564 decoded_p->fudp->fnpMBXinUse [mbx] = false;
1565
1566 } // case wcd
1567 break;
1568
1569 default:
1570 {
1571 sim_debug (DBG_TRACE, & fnp_dev, "[%u] illegal io_cmd\n", decoded_p->slot_no);
1572 sim_debug (DBG_ERR, & fnp_dev, "[%u]illegal/unimplemented io_cmd (%d) in fnp submbx\n", decoded_p->slot_no, io_cmd);
1573 sim_printf ("illegal/unimplemented io_cmd (%d) in fnp submbx\n", io_cmd);
1574 // doFNPfault (...) // XXX
1575 return -1;
1576 }
1577 } // switch (io_cmd)
1578 return 0;
1579 }
1580
1581 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)
*/
1582 {
1583 uint mbx = decoded_p->cell - 12;
1584 //ASSURE(mbx < 4);
1585 if (mbx >= 4)
1586 {
1587 sim_warn ("bad mbx number in interruptL66_CS_done; dropping\n");
1588 return -1;
1589 }
1590 if (! decoded_p->fudp -> fnpMBXinUse [mbx])
1591 {
1592 sim_debug (DBG_ERR, & fnp_dev, "odd -- Multics marked an unused mbx as unused? cell %d (mbx %d)\n", decoded_p->cell, mbx);
1593 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]);
1594 }
1595 else
1596 {
1597 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]);
1598 decoded_p->fudp -> fnpMBXinUse [mbx] = false;
1599 if (decoded_p->fudp->lineWaiting[mbx])
1600 {
1601 struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->fudp->fnpMBXlineno[mbx]];
1602 sim_debug (DBG_TRACE, & fnp_dev, "clearing wait; was %d\n", linep->waitForMbxDone);
1603 linep->waitForMbxDone = false;
1604 }
1605 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]);
1606 }
1607 return 0;
1608 }
1609
1610 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)
*/
1611 {
1612 struct decoded_t decoded;
1613 struct decoded_t *decoded_p = &decoded;
1614 decoded_p->iom_unit = iomUnitIdx;
1615 decoded_p->chan_num = chan;
1616 decoded_p->devUnitIdx = get_ctlr_idx (iomUnitIdx, chan);
1617 decoded_p->fudp = & fnpData.fnpUnitData [decoded_p->devUnitIdx];
1618 word36 dia_pcw;
1619 iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num, decoded_p->fudp->mailboxAddress+DIA_PCW, & dia_pcw, direct_load);
1620
1621 // AN85, pg 13-5
1622 // When the CS has control information or output data to send
1623 // to the FNP, it fills in a submailbox as described in Section 4
1624 // and sends an interrupt over the DIA. This interrupt is handled
1625 // by dail as described above; when the submailbox is read, the
1626 // transaction control word is set to "submailbox read" so that when
1627 // the I/O completes and dtrans runs, the mailbox decoder (decmbx)
1628 // is called. the I/O command in the submail box is either WCD (for
1629 // control information) or WTX (for output data). If it is WCD,
1630 // decmbx dispatches according to a table of operation codes and
1631 // setting a flag in the IB and calling itest, the "test-state"
1632 // entry of the interpreter. n a few cases, the operation requires
1633 // further DIA I/O, but usually all that remains to be does is to
1634 // "free" the submailbox by turning on the corresponding bit in the
1635 // mailbox terminate interrupt multiplex word (see Section 4) and
1636 // set the transaction control word accordingly. When the I/O to
1637 // update TIMW terminates, the transaction is complete.
1638 //
1639 // If the I/O command is WTX, the submailbox contains the
1640 // address and length of a 'pseudo-DCW" list containing the
1641 // addresses and tallies of data buffers in tty_buf. In this case,
1642 // dia_man connects to a DCW list to read them into a reserved area
1643 // in dia_man. ...
1644
1645 // interrupt level (in "cell"):
1646 //
1647 // mbxs 0-7 are CS -> FNP
1648 // mbxs 8--11 are FNP -> CS
1649 //
1650 // 0-7 Multics has placed a message for the FNP in mbx 0-7.
1651 // 8-11 Multics has updated mbx 8-11
1652 // 12-15 Multics is done with mbx 8-11 (n - 4).
1653
1654 decoded_p->cell = getbits36_6 (dia_pcw, 24);
1655 sim_debug (DBG_TRACE, & fnp_dev, "CS interrupt %u\n", decoded_p->cell);
1656 if (decoded_p->cell < 8)
1657 {
1658 interruptL66_CS_to_FNP (decoded_p);
1659 }
1660 else if (decoded_p->cell >= 8 && decoded_p->cell <= 11) //-V560
1661 {
1662 interruptL66_FNP_to_CS (decoded_p);
1663 }
1664 else if (decoded_p->cell >= 12 && decoded_p->cell <= 15) //-V560
1665 {
1666 interruptL66_CS_done (decoded_p);
1667 }
1668 else
1669 {
1670 sim_debug (DBG_ERR, & fnp_dev, "fnp illegal cell number %d\n", decoded_p->cell);
1671 sim_printf ("fnp illegal cell number %d\n", decoded_p->cell);
1672 // doFNPfault (...) // XXX
1673 return -1;
1674 }
1675 return 0;
1676 }
1677
1678 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)
*/
1679 {
1680 sim_printf("\r[FNP emulation: FNP %c received BOOTLOAD command]\r\n", (int)('a' + (int)devUnitIdx));
1681 fnpData.fnpUnitData[devUnitIdx].MState.accept_calls = false;
1682 bool have3270 = false;
1683 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
1684 {
1685 fnpData.fnpUnitData[devUnitIdx].MState.line [lineno] . listen = false;
1686 if (fnpData.fnpUnitData[devUnitIdx].MState.line [lineno].line_client)
1687 {
1688 fnpuv_start_writestr (fnpData.fnpUnitData[devUnitIdx].MState.line [lineno].line_client,
1689 (unsigned char *) "\r[FNP emulation: FNP restarted]\r\n");
1690 }
1691 if (fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].service == service_3270)
1692 {
1693 sim_debug (DBG_TRACE, & fnp_dev, "3270 controller found at unit %u line %u\r\n", devUnitIdx, lineno);
1694 // XXX assuming only single controller
1695 if (fnpData.ibm3270ctlr[ASSUME0].configured)
1696 {
1697 sim_warn ("Too many 3270 controllers configured");
1698 }
1699 else
1700 {
1701 have3270 = true;
1702 memset (& fnpData.ibm3270ctlr[ASSUME0], 0, sizeof (struct ibm3270ctlr_s));
1703 fnpData.ibm3270ctlr[ASSUME0].configured = true;
1704 fnpData.ibm3270ctlr[ASSUME0].fnpno = devUnitIdx;
1705 fnpData.ibm3270ctlr[ASSUME0].lineno = lineno;
1706
1707 // 3270 controller connects immediately
1708 // Set from CMF data now.
1709 //fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType = 7 /* LINE_BSC */;
1710 if (fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType == 0) /* LINE_NONE */
1711 fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType = 7; /* LINE_BSC */
1712 fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].accept_new_terminal = true;
1713 }
1714 }
1715 }
1716 (void)fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
1717 if (have3270)
1718 (void)fnpuv3270Init (fnpData.telnet3270_port);
1719 }
1720
1721
1722 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)
*/
1723 {
1724 word24 wos = addr / 2;
1725 word36 word;
1726 iom_direct_data_service (iom_unit_idx, chan, l66addr + wos, & word, direct_load);
1727 if (addr & 1)
1728 return (word18) (word & MASK18);
1729 else
1730 return (word18) ((word >> 18) & MASK18);
1731 }
1732
1733
1734 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)
*/
1735 {
1736 uint fnp_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1737 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
1738
1739 // 60132445 FEP Coupler EPS
1740 // 2.2.1 Control Intercommunication
1741 //
1742 // "In Level 66 memory, at a location known to the coupler and
1743 // to Level 6 software is a mailbox area consisting to an Overhead
1744 // mailbox and 7 Channel mailboxes."
1745
1746 bool ok = true;
1747
1748 word36 dia_pcw;
1749 iom_direct_data_service (iomUnitIdx, chan, fudp->mailboxAddress+DIA_PCW, & dia_pcw, direct_load);
1750 sim_debug (DBG_TRACE, & fnp_dev,
1751 "%s: chan %d dia_pcw %012"PRIo64"\n", __func__, chan, dia_pcw);
1752
1753 // Mailbox word 0:
1754 //
1755 // 0-17 A
1756 // 18 I
1757 // 19-20 MBZ
1758 // 21-22 RFU
1759 // 23 0
1760 // 24-26 B
1761 // 27-29 D Channel #
1762 // 30-35 C Command
1763 //
1764 // A6-A23 A0-A2 A3-A5
1765 // Operation C A B D
1766 // Interrupt L6 071 --- Int. Level
1767 // Bootload L6 072 L66 Addr L66 Addr L66 Addr
1768 // A6-A23 A0-A2 A3-A5
1769 // Interrupt L66 073 --- --- Intr Cell
1770 // Data Xfer to L66 075 L66 Addr L66 Addr L66 Addr
1771 // A6-A23 A0-A2 A3-A5
1772 // Data Xfer to L6 076 L66 Addr L66 Addr L66 Addr
1773 // A6-A23 A0-A2 A3-A5
1774
1775 //
1776 // fnp_util.pl1:
1777 // 075 tandd read
1778 // 076 tandd write
1779
1780 // mbx word 1: mailbox_requests fixed bin
1781 // 2: term_inpt_mpx_wd bit (36) aligned
1782 // 3: last_mbx_req_count fixed bin
1783 // 4: num_in_use fixed bin
1784 // 5: mbx_used_flags
1785 // used (0:7) bit (1) unaligned
1786 // pad2 bit (28) unaligned
1787 // 6,7: crash_data
1788 // fault_code fixed bin (18) unal unsigned
1789 // ic fixed bin (18) unal unsigned
1790 // iom_fault_status fixed bin (18) unal unsigned
1791 // fault_word fixed bin (18) unal unsigned
1792 //
1793 // crash_data according to dn355_boot_interrupt.pl1:
1794 //
1795 // dcl 1 fnp_boot_status aligned based (stat_ptr), /* structure of bootload status */
1796 // 2 real_status bit (1) unaligned, /* must be "1"b in valid status */
1797 // 2 pad1 bit (2) unaligned,
1798 // 2 major_status bit (3) unaligned,
1799 // 2 pad2 bit (3) unaligned,
1800 // 2 substatus fixed bin (8) unal, /* code set by 355, only interesting if major_status is 4 */
1801 // 2 channel_no fixed bin (17) unaligned; /* channel no. of LSLA in case of config error */
1802 // only 34 bits???
1803 // major_status:
1804 // dcl BOOTLOAD_OK fixed bin int static options (constant) init (0);
1805 // dcl CHECKSUM_ERROR fixed bin int static options (constant) init (1);
1806 // dcl READ_ERROR fixed bin int static options (constant) init (2);
1807 // dcl GICB_ERROR fixed bin int static options (constant) init (3);
1808 // dcl INIT_ERROR fixed bin int static options (constant) init (4);
1809 // dcl UNWIRE_STATUS fixed bin int static options (constant) init (5);
1810 // dcl MAX_STATUS fixed bin int static options (constant) init (5);
1811
1812 // 3.5.1 Commands Issued by Central System
1813 //
1814 // In the issuing of an order by the Central System to the Coupler, the
1815 // sequence occurs:
1816 //
1817 // 1. The L66 program creates a LPW and Pcw for the Central System Connect
1818 // channel. It also generates and stores a control word containing a command
1819 // int he L66 mailbox. A Connect is then issued to the L66 IOM.
1820 //
1821 // 2. The Connect Channel accesses the PCW to get the channel number of
1822 // the Direct Channel that the coupler is attached to. the direct Channel
1823 // sends a signal to the Coupler that a Connect has been issued.
1824 //
1825 // 3. The Coupler now reads the content of the L66 mailbox, obtaining the
1826 // control word. If the control word is legal, the Coupler will write a
1827 // word of all zeros into the mailbox.
1828 //
1829
1830 // 4.1.1.2 Transfer Control Word.
1831 // The transfer control word, which is pointed to by the
1832 // mailbox word in l66 memory on Op Codes 72, 7, 76 contains
1833 // a starting address which applies to L6 memory an a Tally
1834 // of the number of 36 bit words to be transferred. The l66
1835 // memory locations to/from which the transfers occur are
1836 // those immediately following the location where this word
1837 // was obtained.
1838 //
1839 // 00-02 001
1840 // 03-17 L6 Address
1841 // 18 P
1842 // 19-23 MBZ
1843 // 24-25 Tally
1844 //
1845 // if P = 0 the l6 address:
1846 // 00-07 00000000
1847 // 08-22 L6 address (bits 3-17)
1848 // 23 0
1849 // if P = 1
1850 // 00-14 L6 address (bits 3-17)
1851 // 15-23 0
1852 //
1853
1854 uint command = getbits36_6 (dia_pcw, 30);
1855 word36 bootloadStatus = 0;
1856
1857 if (command == 000) // reset
1858 {
1859 sim_debug (DBG_TRACE, & fnp_dev,
1860 "%s: chan %d reset command\n", __func__, chan);
1861 send_general_interrupt (iomUnitIdx, chan, imwTerminatePic);
1862 }
1863 else if (command == 072) // bootload
1864 {
1865
1866 word24 l66addr = (((word24) getbits36_6 (dia_pcw, 24)) << 18) |
1867 (word24) getbits36_18 (dia_pcw, 0);
1868
1869 // AN85-01 15-2
1870 // 0 boot dcw
1871 // 1 gicb
1872 // ....
1873 // padding to next multiple of 64
1874 // n core image
1875 //
1876 // where n is (in 36 bit words) (gicb len + 1) + 63 / 64
1877
1878 //sim_printf ("l66addr %08o\n", l66addr);
1879 word36 dcw;
1880 iom_direct_data_service (iomUnitIdx, chan, l66addr, & dcw, direct_load);
1881 word12 tally = getbits36_12 (dcw, 24);
1882 // sim_printf ("%o %d.\n", tally, tally);
1883 //sim_printf ("dcw %012llo\n", dcw);
1884
1885 // Calculate start of core image
1886 word24 image_off = (tally + 64) & 077777700;
1887 // sim_printf ("image_off %o %d.\n", image_off, image_off);
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
1918 // comm_ref
1919 // 0640 crldt 72
1920 // 0644 crbdt 72
1921 // 0650 crbuf 18
1922 // 0651 crmem 18
1923 // 0652 crnbf 18
1924 // 0653 criom 18
1925
1926 // 2 comm_reg unal, /* software communications region */
1927 // 0640 3 crldt fixed bin (71) aligned, /* date and time binder */
1928 // 0644 3 crbdt fixed bin (71) aligned, /* date and time image booted */
1929 // 0650 3 crbuf fixed bin (17) unal, /* base of free buffer pool */
1930 // 0651 3 crmem fixed bin (18) unsigned unal, /* last loc of mem configured */
1931 // 0652 3 crnbf fixed bin (17) unal, /* free buffers in pool now */
1932 // 0653 3 criom fixed bin (17) unal, /* pointer to iom table */
1933 // 0654 3 crnhs fixed bin (17) unal, /* number of HSLAs */
1934 // 0655 3 crnls fixed bin (17) unal, /* number of LSLAs */
1935 // 0656 3 crcon bit (18) unal, /* console enable switch */
1936 // 0657 3 crmod fixed bin (17) unal, /* base of module chain */
1937 // 3 crnxa fixed bin (17) unal, /* ptr to head of free space chain */
1938 // 3 crtra bit (18) unal, /* trace entry enable mask */
1939 // 3 crtrb fixed bin (18) unsigned unal, /* base of trace table */
1940 // 3 crtrc fixed bin (18) unsigned unal, /* next trace table entry ptr */
1941 // 3 crreg fixed bin (17) unal, /* ptr to fault reg storage area */
1942 // 3 crttb fixed bin (17) unal, /* ptr to tib table base */
1943 // 3 crtte fixed bin (17) unal, /* last addr in tib table */
1944 // 3 crdly fixed bin (17) unal, /* pointer to delay table chain */
1945 // 3 crver char (4) unal, /* mcs version number */
1946 // 3 crbrk fixed bin (17) unal, /* pointer to breakpoint control table */
1947 // 3 crtsw bit (18) unal, /* trace switch (zero=trace on) */
1948 // 3 crnxs fixed bin (17) unal, /* pointer to next free small block */
1949 // 3 crnbs fixed bin (17) unal, /* number of buffers devoted to small space */
1950 // 3 crcct fixed bin (17) unal, /* pointer to first cct descriptor */
1951 // 3 crskd fixed bin (17) unal, /* pointer to scheduler data block */
1952 // 3 cretb fixed bin (17) unal, /* pointer to list of echo-negotiation bit tables */
1953 // 3 crcpt fixed bin (17) unal, /* pointer to cpu page table */
1954 // 3 crpte fixed bin (17) unal, /* pointer to variable cpu page table entry */
1955 // 3 crtsz fixed bin (17) unal, /* size of trace data buffer */
1956 // 3 crmet bit (18) unal, /* metering enabled */
1957 // 3 crtdt bit (18) unal, /* 0 if no COLTS channel; set to TIB address if it exists */
1958 // 3 crbtm bit (18) unal, /* address of time meters for buffer allocation/freeing */
1959 // 3 crnxe fixed bin (18) unsigned unal, /* next available space in extended memory */
1960 // 3 crbpe fixed bin (17) unal, /* buffer paging window table entry */
1961 // 3 pad (39) bit (18) unal,
1962 // 3 crcpr char (28) unal, /* image copyright notice */
1963 // 3 crash_location bit (18) unal, /* offset used for unresolved REF's */
1964 // 3 crash_opcode bit (18) unal, /* crash instruction */
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
2017 // Number of LSLAs
2018 # ifdef VERBOSE_BOOT
2019 word18 crnls = getl6core (iomUnitIdx, chan, l66addr + image_off, 0655);
2020 sim_printf ("Number of LSLAs (crnls) %d\n", crnls);
2021 # endif
2022
2023 // Address of IOM table
2024 word18 criom = getl6core (iomUnitIdx, chan, l66addr + image_off, 0653);
2025
2026 // Walk the LSLAs in the IOM table
2027 // 2 words/slot (flags, taddr)
2028 // 6 LSLA slots
2029 // first slot at first_lsla_ch 9
2030
2031 bool hdr = false;
2032 # ifdef VERBOSE_BOOT
2033 uint nfound = 0;
2034 # endif /* ifdef VERBOSE_BOOT */
2035 for (uint lsla = 0; lsla < 6; lsla ++)
2036 {
2037 uint slot = lsla + 9;
2038 uint os = slot * 2;
2039 // get flags word
2040 word18 flags = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os);
2041 uint device_type_code = (flags >> 4) & 037;
2042 if (device_type_code == 4)
2043 {
2044 # ifdef VERBOSE_BOOT
2045 nfound ++;
2046 # endif /* ifdef VERBOSE_BOOT */
2047 // get addr word
2048 word18 tblp = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os + 1);
2049 for (uint slot = 0; slot < 52; slot ++)
2050 {
2051 // 2 word18s per entry
2052 // pad bit(11)
2053 // ibm_code bit(1) // if 6-bit odd parity
2054 // pad2 bit(3)
2055 // slot_id bit(3)
2056 //
2057 // ptr bit(18)
2058 word3 slot_id = getl6core (iomUnitIdx, chan, l66addr + image_off, tblp + 2 * slot) & MASK3;
2059 if (slot_id != 7)
2060 {
2061 # ifdef VERBOSE_BOOT
2062 char * slot_ids [8] =
2063 {
2064 "10 cps",
2065 "30 cps, slot 1",
2066 "30 cps, slot 2",
2067 "30 cps, slot 3",
2068 "invalid",
2069 "15 cps, slot 1",
2070 "15 cps, slot 2",
2071 "unused"
2072 };
2073 char * id = slot_ids[slot_id];
2074 # endif /* ifdef VERBOSE_BOOT */
2075 if (! hdr)
2076 {
2077 hdr = true;
2078 # ifdef VERBOSE_BOOT
2079 sim_printf ("LSLA table: card number, slot, slot_id, slot_id string\n");
2080 # endif /* ifdef VERBOSE_BOOT */
2081 }
2082 # ifdef VERBOSE_BOOT
2083 sim_printf ("%d %2d %d %s\n", lsla, slot, slot_id, id);
2084 # endif /* ifdef VERBOSE_BOOT */
2085 }
2086 } // for slot
2087 } // if dev type 4 (LSLA)
2088 } // iom table entry
2089 # ifdef VERBOSE_BOOT
2090 if (nfound != crnls)
2091 sim_printf ("LSLAs configured %d found %d\n", crnls, nfound);
2092 # endif /* ifdef VERBOSE_BOOT */
2093
2094 // Number of HSLAs
2095 # ifdef VERBOSE_BOOT
2096 word18 crnhs = getl6core (iomUnitIdx, chan, l66addr + image_off, 0654);
2097 sim_printf ("Number of HSLAs (crnhs) %d\n", crnhs);
2098 # endif /* ifdef VERBOSE_BOOT */
2099
2100 // Walk the HSLAs in the IOM table
2101 // 2 words/slot (flags, taddr)
2102 // 3 LSLA slots
2103 // first slot at first_hsla_ch 6
2104
2105 hdr = false;
2106 # ifdef VERBOSE_BOOT
2107 nfound = 0;
2108 # endif /* ifdef VERBOSE_BOOT */
2109 for (uint hsla = 0; hsla < 3; hsla ++)
2110 {
2111 uint slot = hsla + 6;
2112 uint os = slot * 2;
2113 // get flags word
2114 word18 flags = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os);
2115 uint device_type_code = (flags >> 4) & 037;
2116 if (device_type_code == 3)
2117 {
2118 # ifdef VERBOSE_BOOT
2119 nfound ++;
2120 # endif /* ifdef VERBOSE_BOOT */
2121 // get addr word
2122 word18 tblp = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os + 1);
2123 for (uint slot = 0; slot < 32; slot ++)
2124 {
2125 // 2 word18s per entry
2126 // conc_chan bit(1)
2127 // private_line bit(1)
2128 // async bit(1)
2129 // option1 bit(1)
2130 // option2 bit(1)
2131 // modem_type bit(4)
2132 // line_type bit(5)
2133 // dev_speed bit(4)
2134 //
2135 // ptr bit(18)
2136
2137 # ifdef VERBOSE_BOOT
2138 char * line_types[23] =
2139 {
2140 "none ",
2141 "ASCII ",
2142 "1050 ",
2143 "2741 ",
2144 "ARDS ",
2145 "Sync ",
2146 "G115 ",
2147 "BSC ",
2148 "202ETX ",
2149 "VIP ",
2150 "ASYNC1 ",
2151 "ASYNC2 ",
2152 "ASYNC3 ",
2153 "SYNC1 ",
2154 "SYNC2 ",
2155 "SYNC3 ",
2156 "POLLED_VIP",
2157 "X25LAP ",
2158 "HDLC ",
2159 "COLTS ",
2160 "DSA ",
2161 "HASP_OPR ",
2162 "invalid "
2163 };
2164 # endif
2165
2166 # ifdef VERBOSE_BOOT
2167 char * modem_types[8] =
2168 {
2169 "invalid ",
2170 "Bell 103A/113",
2171 "Bell 201C ",
2172 "Bell 202C5 ",
2173 "Bell 202C6 ",
2174 "Bell 208A ",
2175 "Bell 208B ",
2176 "Bell 209A "
2177 };
2178 # endif
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
2211 # ifdef VERBOSE_BOOT
2212 char * async_speeds[16] =
2213 {
2214 "invalid",
2215 "110 ",
2216 "133 ",
2217 "150 ",
2218 "300 ",
2219 "600 ",
2220 "1200 ",
2221 "1800 ",
2222 "2400 ",
2223 "4800 ",
2224 "7200 ",
2225 "9600 ",
2226 "19200 ",
2227 "40800 ",
2228 "50000 ",
2229 "72000 "
2230 };
2231
2232 char * sync_speeds[16] =
2233 {
2234 "invalid",
2235 "2000 ",
2236 "2400 ",
2237 "3600 ",
2238 "4800 ",
2239 "5400 ",
2240 "7200 ",
2241 "9600 ",
2242 "19200 ",
2243 "40800 ",
2244 "50000 ",
2245 "invalid",
2246 "invalid",
2247 "invalid",
2248 "invalid",
2249 "invalid"
2250 };
2251 # endif
2252 word18 subch_data = getl6core (iomUnitIdx, chan, l66addr + image_off, tblp + 2 * slot);
2253 # ifdef VERBOSE_BOOT
2254 word1 async = (subch_data >> 15) & 1;
2255 word1 option1 = (subch_data >> 14) & 1;
2256 # endif
2257 word5 line_type = (subch_data >> 4) & MASK5;
2258 if (line_type > 22)
2259 line_type = 22;
2260 word4 modem_type = (subch_data >> 9) & MASK4;
2261 if (modem_type > 7)
2262 modem_type = 0;
2263 # ifdef VERBOSE_BOOT
2264 word4 dev_speed = subch_data & MASK4;
2265 //if (dev_speed > 10)
2266 //dev_speed = 0;
2267 char * speed = async ? async_speeds[dev_speed] : sync_speeds[dev_speed];
2268 if (async && dev_speed == 4 && option1)
2269 speed = "auto ";
2270 # endif
2271 if (! hdr)
2272 {
2273 hdr = true;
2274 # ifdef VERBOSE_BOOT
2275 sim_printf ("HSLA table: card number, slot, "
2276 "sync/async, line type, modem_type, "
2277 "speed\n");
2278 # endif
2279 }
2280 # ifdef VERBOSE_BOOT
2281 sim_printf ("%d %2d %s %s %s %s\n",
2282 hsla, slot, async ? "async" :"sync ",
2283 line_types[line_type],
2284 modem_types[modem_type],
2285 speed);
2286 # endif
2287 uint lineno = hsla * 32u + slot;
2288 struct t_line * linep = & fudp->MState.line[lineno];
2289
2290
2291
2292
2293
2294
2295
2296 //linep->lineType = line_type ? line_type : 1; // Map none to ASCII
2297 linep->lineType = line_type;
2298 } // for slot
2299 } // if dev type 4 (LSLA)
2300 } // iom table entry
2301 # ifdef VERBOSE_BOOT
2302 if (nfound != crnls)
2303 sim_printf ("LSLAs configured %d found %d\n", crnls, nfound);
2304 # endif /* ifdef VERBOSE_BOOT */
2305
2306
2307 #if defined(THREADZ) || defined(LOCKLESS)
2308 lock_libuv ();
2309 #endif
2310 fnpcmdBootload (fnp_unit_idx);
2311 #if defined(THREADZ) || defined(LOCKLESS)
2312 unlock_libuv ();
2313 #endif
2314 send_general_interrupt (iomUnitIdx, chan, imwTerminatePic);
2315 fudp -> fnpIsRunning = true;
2316 }
2317 else if (command == 071) // interrupt L6
2318 {
2319 #if defined(THREADZ) || defined(LOCKLESS)
2320 lock_libuv ();
2321 #endif
2322 ok = interruptL66 (iomUnitIdx, chan) == 0;
2323 #if defined(THREADZ) || defined(LOCKLESS)
2324 unlock_libuv ();
2325 #endif
2326 }
2327 else if (command == 075) // data xfer from L6 to L66
2328 {
2329 // Build the L66 address from the PCW
2330 // 0-17 A
2331 // 24-26 B
2332 // 27-29 D Channel #
2333 // Operation C A B D
2334 // Data Xfer to L66 075 L66 Addr L66 Addr L66 Addr
2335 // A6-A23 A0-A2 A3-A5
2336 // These don't seem to be right; M[L66Add] is always 0.
2337 //word24 A = (word24) getbits36_18 (dia_pcw, 0);
2338 //word24 B = (word24) getbits36_3 (dia_pcw, 24);
2339 //word24 D = (word24) getbits36_3 (dia_pcw, 29);
2340 //word24 L66Addr = (B << (24 - 3)) | (D << (24 - 3 - 3)) | A;
2341
2342 // According to fnp_util:
2343 // dcl 1 a_dia_pcw aligned based (mbxp), /* better declaration than the one used when MCS is running */
2344 // 2 address fixed bin (18) unsigned unaligned,
2345 // 2 error bit (1) unaligned,
2346 // 2 pad1 bit (3) unaligned,
2347 // 2 parity bit (1) unaligned,
2348 // 2 pad2 bit (1) unaligned,
2349 // 2 pad3 bit (3) unaligned, /* if we used address extension this would be important */
2350 // 2 interrupt_level fixed bin (3) unsigned unaligned,
2351 // 2 command bit (6) unaligned;
2352 //
2353 // a_dia_pcw.address = address;
2354 //
2355
2356 //word24 L66Addr = (word24) getbits36_18 (dia_pcw, 0);
2357 //sim_printf ("L66 xfer\n");
2358 //sim_printf ("PCW %012"PRIo64"\n", dia_pcw);
2359 //sim_printf ("L66Addr %08o\n", L66Addr);
2360 //sim_printf ("M[] %012"PRIo64"\n", M[L66Addr]);
2361
2362 // 'dump_mpx d'
2363 //L66 xfer
2364 //PCW 022002000075
2365 //L66Addr 00022002
2366 //M[] 000000401775
2367 //L66 xfer
2368 //PCW 022002000075
2369 //L66Addr 00022002
2370 //M[] 003772401775
2371 //L66 xfer
2372 //PCW 022002000075
2373 //L66Addr 00022002
2374 //M[] 007764401775
2375 //
2376 // The contents of M seem much more reasonable, bit still don't match
2377 // fnp_util$setup_dump_ctl_word. The left octet should be '1', not '0';
2378 // bit 18 should be 0 not 1. But the offsets and tallies match exactly.
2379 // Huh... Looking at 'dump_6670_control' control instead, it matches
2380 // correctly. Apparently fnp_util thinks the FNP is a 6670, not a 335.
2381 // I can't decipher the call path, so I don't know why; but looking at
2382 // multiplexer_types.incl.pl1, I would guess that by MR12.x, all FNPs
2383 // were 6670s.
2384 //
2385 // So:
2386 //
2387 // dcl 1 dump_6670_control aligned based (data_ptr), /* word used to supply DN6670 address and tally for fdump */
2388 // 2 fnp_address fixed bin (18) unsigned unaligned,
2389 // 2 unpaged bit (1) unaligned,
2390 // 2 mbz bit (5) unaligned,
2391 // 2 tally fixed bin (12) unsigned unaligned;
2392
2393 // Since the data is marked 'paged', and I don't understand the
2394 // the paging mechanism or parameters, I'm going to punt here and
2395 // not actually transfer any data.
2396
2397 }
2398 else
2399 {
2400 sim_warn ("bogus fnp command %d (%o)\n", command, command);
2401 ok = false;
2402 }
2403
2404 if (ok)
2405 {
2406 #ifdef TESTING
2407 if_sim_debug (DBG_TRACE, & fnp_dev) dmpmbx (fudp->mailboxAddress);
2408 #endif
2409 //iom_chan_data [iomUnitIdx] [chan] . in_use = false;
2410 dia_pcw = 0;
2411 iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+DIA_PCW, & dia_pcw, direct_store);
2412 putbits36_1 (& bootloadStatus, 0, 1); // real_status = 1
2413 putbits36_3 (& bootloadStatus, 3, 0); // major_status = BOOTLOAD_OK;
2414 putbits36_8 (& bootloadStatus, 9, 0); // substatus = BOOTLOAD_OK;
2415 putbits36_17 (& bootloadStatus, 17, 0); // channel_no = 0;
2416 iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+CRASH_DATA, & bootloadStatus, direct_store);
2417 }
2418 else
2419 {
2420 #ifdef TESTING
2421 if_sim_debug (DBG_TRACE, & fnp_dev) dmpmbx (fudp->mailboxAddress);
2422 #endif
2423 // 3 error bit (1) unaligned, /* set to "1"b if error on connect */
2424 //iom_chan_data [iomUnitIdx] [chan] . in_use = false;
2425 putbits36_1 (& dia_pcw, 18, 1); // set bit 18
2426 iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+DIA_PCW, & dia_pcw, direct_store);
2427 }
2428 }
2429
2430 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)
*/
2431 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
2432
2433 switch (p->IDCW_DEV_CMD) {
2434 case 000: { // CMD 00 Request status
2435 p->stati = 04000;
2436 processMBX (iomUnitIdx, chan);
2437 // no status_service and no additional terminate interrupt
2438 // ???
2439 }
2440 return IOM_CMD_DISCONNECT;
2441
2442 default: {
2443 p->stati = 04501; // cmd reject, invalid opcode
2444 p->chanStatus = chanStatIncorrectDCW;
2445 if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
2446 sim_warn ("%s: FNP unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
2447 }
2448 return IOM_CMD_ERROR;
2449 }
2450 }
2451
2452 /*
2453 * fnp_iom_cmd()
2454 *
2455 */
2456
2457 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)
*/
2458 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
2459 // Is it an IDCW?
2460
2461 if (IS_IDCW (p)) {
2462 return fnpCmd (iomUnitIdx, chan);
2463 }
2464 // else // DDCW/TDCW
2465 sim_warn ("%s expected IDCW\n", __func__);
2466 return IOM_CMD_ERROR;
2467 }