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