root/src/dps8/dps8_fnp2_iomcmd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fnp_core_read_n
  2. l_putbits36_1
  3. dmpmbx
  4. wcd
  5. tun_write
  6. fnp_wtx_output
  7. wtx
  8. fnp_rtx_input_accepted
  9. interruptL66_CS_to_FNP
  10. interruptL66_FNP_to_CS
  11. interruptL66_CS_done
  12. interruptL66
  13. fnpcmdBootload
  14. getl6core
  15. processMBX
  16. fnpCmd
  17. fnp_iom_cmd

   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-2024 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][next][first][last][top][bottom][index][help] */
  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][next][first][last][top][bottom][index][help] */
  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)\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][next][first][last][top][bottom][index][help] */
 114   {
 115     struct mailbox mbx;
 116     fnp_core_read_n (mailboxAddress, (word36 *) & mbx, MAILBOX_WORDS, "dmpmbx");
 117     sim_printf ("dia_pcw            %012llo\n", (long long unsigned int) mbx.dia_pcw);
 118     sim_printf ("mailbox_requests   %012llo\n", (long long unsigned int) mbx.mailbox_requests);
 119     sim_printf ("term_inpt_mpx_wd   %012llo\n", (long long unsigned int) mbx.term_inpt_mpx_wd);
 120     sim_printf ("last_mbx_req_count %012llo\n", (long long unsigned int) mbx.last_mbx_req_count);
 121     sim_printf ("num_in_use         %012llo\n", (long long unsigned int) mbx.num_in_use);
 122     sim_printf ("mbx_used_flags     %012llo\n", (long long unsigned int) mbx.mbx_used_flags);
 123     for (uint i = 0; i < 8; i ++)
 124       {
 125         sim_printf ("CS  mbx %d\n", i);
 126         sim_printf ("    word1        %012llo\n",
 127                     (long long unsigned int) mbx.dn355_sub_mbxes[i].word1);
 128         sim_printf ("    word2        %012llo\n",
 129                     (long long unsigned int) mbx.dn355_sub_mbxes[i].word2);
 130         sim_printf ("    command_data %012llo\n",
 131                     (long long unsigned int) mbx.dn355_sub_mbxes[i].command_data [0]);
 132         sim_printf ("                 %012llo\n",
 133                     (long long unsigned int) mbx.dn355_sub_mbxes[i].command_data [1]);
 134         sim_printf ("                 %012llo\n",
 135                     (long long unsigned int) mbx.dn355_sub_mbxes[i].command_data [2]);
 136         sim_printf ("    word6        %012llo\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\n", i);
 142         sim_printf ("    word1        %012llo\n",
 143                     (unsigned long long int)mbx.fnp_sub_mbxes[i].word1);
 144         sim_printf ("    word2        %012llo\n",
 145                     (unsigned long long int)mbx.fnp_sub_mbxes[i].word2);
 146         sim_printf ("    mystery      %012llo\n",
 147                     (unsigned long long int)mbx.fnp_sub_mbxes[i].mystery [0]);
 148         sim_printf ("                 %012llo\n",
 149                     (unsigned long long int)mbx.fnp_sub_mbxes[i].mystery [1]);
 150         sim_printf ("                 %012llo\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][next][first][last][top][bottom][index][help] */
 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\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\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\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\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\n", decoded_p->slot_no);
 219             //sim_printf ("fnp set framing characters\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\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\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"\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\n");
 256                   //    sim_debug (DBG_TRACE, & fnp_dev, "    %u\n", val1);
 257                   //}
 258                   break;
 259                 case 2:
 260                   sim_debug (DBG_TRACE, & fnp_dev, "ACCEPT_BID\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\n");
 266                   //    if (val1 == 0)
 267                   //      sim_debug (DBG_TRACE, & fnp_dev, "    non-transparent ASCII\n");
 268                   //    else if (val1 == 1)
 269                   //      sim_debug (DBG_TRACE, & fnp_dev, "    non-transparent EBCDIC\n");
 270                   //    else if (val1 == 2)
 271                   //      sim_debug (DBG_TRACE, & fnp_dev, "    transparent ASCII\n");
 272                   //    else if (val1 == 3)
 273                   //      sim_debug (DBG_TRACE, & fnp_dev, "    transparent EBCDIC\n");
 274                   //    else
 275                   //      sim_debug (DBG_TRACE, & fnp_dev, "    unknown %u. %o\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\n");
 283                   //    sim_debug (DBG_TRACE, & fnp_dev, "    ttd_time  %u\n", val1);
 284                   //    sim_debug (DBG_TRACE, & fnp_dev, "    ttd_limit %u\n", val2);
 285                   //}
 286                   break;
 287                 case 5:
 288                   sim_debug (DBG_TRACE, & fnp_dev, "REPORT_WRITE_STATUS\n");
 289                   break;
 290                 case 6:
 291                   sim_debug (DBG_TRACE, & fnp_dev, "SET_3270_MODE\n");
 292                   break;
 293                 case 7:
 294                   {
 295                     sim_debug (DBG_TRACE, & fnp_dev, "SET_POLLING_ADDR\n");
 296 //word36 command_data2 = decoded_p->smbxp -> command_data [2];
 297 //sim_printf ("XXX line_control %d %012"PRIo64" %012"PRIo64" %012"PRIo64"\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\n", c1);
 305                     sim_debug (DBG_TRACE, & fnp_dev, "    char3 %u\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\n");
 317                   fnpuv3270Poll (true);
 318                   break;
 319                 case 9:
 320                   {
 321                     sim_debug (DBG_TRACE, & fnp_dev, "SET_SELECT_ADDR\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\n", c1);
 328                     sim_debug (DBG_TRACE, & fnp_dev, "    char3 %u\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\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\n");
 374                   //    if (val1 == 0)
 375                   //      sim_debug (DBG_TRACE, & fnp_dev, "    slave\n");
 376                   //    else if (val1 == 1)
 377                   //      sim_debug (DBG_TRACE, & fnp_dev, "    master\n");
 378                   //    else
 379                   //      sim_debug (DBG_TRACE, & fnp_dev, "    unknown %u. %o\n", val1, val1);
 380                   //}
 381                   break;
 382                 case 12:
 383                   sim_debug (DBG_TRACE, & fnp_dev, "SET_HASP_MODE\n");
 384                   break;
 385                 case 13:
 386                   sim_debug (DBG_TRACE, & fnp_dev, "SET_NAK_LIMIT\n");
 387                   break;
 388                 case 14:
 389                   sim_debug (DBG_TRACE, & fnp_dev, "SET_HASP_TIMERS\n");
 390                   break;
 391                 default:
 392                   sim_printf ("unknown %u. %o\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\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\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\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)\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\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\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\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\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\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\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\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\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\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\n",
 656                        decoded_p->slot_no);
 657             //sim_printf ("fnp output_fc_chars\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\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\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\n",
 690                        decoded_p->slot_no);
 691             //sim_printf ("fnp alter parameters\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\n", subtype);
 697             switch (subtype)
 698               {
 699                 case  3: // Fullduplex
 700                   {
 701                     sim_debug (DBG_TRACE, & fnp_dev, "[%u]        alter_parameters fullduplex %u\n",
 702                                decoded_p->slot_no, flag);
 703                     //sim_printf ("fnp full_duplex\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\n",
 711                                decoded_p->slot_no, flag);
 712                     //sim_printf ("fnp crecho\n");
 713                     linep->crecho = !! flag;
 714                   }
 715                   break;
 716 
 717                 case  9: // Lfecho
 718                   {
 719                     //sim_printf ("fnp lfecho\n");
 720                     sim_debug (DBG_TRACE, & fnp_dev, "[%u]        alter_parameters lfecho %u\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\n",
 729                                decoded_p->slot_no);
 730                     //sim_printf ("fnp dumpoutput\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\n",
 740                                decoded_p->slot_no, flag);
 741                     //sim_printf ("fnp tabecho\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\n",
 749                                decoded_p->slot_no, flag);
 750                     //sim_printf ("fnp listen %p %d.%d %d\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 \n",
 774                                decoded_p->slot_no, flag);
 775                     //sim_printf ("fnp handle_quit %d\n", flag);
 776                     linep->handleQuit = !! flag;
 777                   }
 778                   break;
 779 
 780                 case 18: // Chngstring
 781                   {
 782                     //sim_printf ("fnp Change control string\n");
 783                     uint idx =  getbits36_9 (command_data[0], 9);
 784                     sim_debug (DBG_TRACE, & fnp_dev, "[%u]        alter_parameters chngstring %u\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\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\n",
 801                                decoded_p->slot_no, flag);
 802                     //sim_printf ("fnp echoplex\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\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\n");
 815         // dump the input
 816        //int muxLineNo = MState[fnpUnitNum].line [lineno] . muxLineNum;
 817        //sim_printf ("dumping mux line %d\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\n",
 825                                decoded_p->slot_no, flag);
 826                     //sim_printf ("fnp replay\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\n",
 834                                decoded_p->slot_no, flag);
 835                     //sim_printf ("fnp polite\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\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\n", linep->block_xfer_in_frame_sz, linep->block_xfer_out_frame_sz);
 849                     //sim_printf ("fnp block_xfer %d %d\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\n",
 862                                decoded_p->slot_no, flag);
 863                     linep->inputBufferSize = sz;
 864 //sim_printf ("Set_buffer_size %u\n", sz);
 865                   }
 866                   break;
 867 
 868                 case 27: // Breakall
 869                   {
 870                     sim_debug (DBG_TRACE, & fnp_dev, "[%u]        alter_parameters breakall %u\n",
 871                                decoded_p->slot_no, flag);
 872                     //sim_printf ("fnp break_all\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\n",
 880                                decoded_p->slot_no, flag);
 881                     //sim_printf ("fnp prefixnl\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\n",
 889                                decoded_p->slot_no, flag);
 890                     //sim_printf ("fnp input_flow_control\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\n",
 898                                decoded_p->slot_no, flag);
 899                     //sim_printf ("fnp output_flow_control\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\n",
 907                                decoded_p->slot_no, flag);
 908                     //sim_printf ("fnp odd_parity\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\n",
 916                                decoded_p->slot_no, flag);
 917                     //sim_printf ("fnp eight_bit_in\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\n",
 925                                decoded_p->slot_no, flag);
 926                     //sim_printf ("fnp eight_bit_out\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\n",
 944                                decoded_p->slot_no);
 945                     sim_printf ("fnp unimplemented subtype %d (%o)\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\n",
 953                                decoded_p->slot_no);
 954                     sim_printf ("fnp illegal subtype %d (%o)\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\n", decoded_p->slot_no);
 965             //sim_printf ("fnp set delay table\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\n", decoded_p->slot_no);
1061             //sim_printf ("fnp report_meters\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\n", decoded_p->slot_no);
1093             sim_warn ("fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1094             //sim_debug (DBG_ERR, & fnp_dev, "fnp unimplemented opcode %d (%o)\n", decoded_p->op_code, decoded_p->op_code);
1095             //sim_printf ("fnp unimplemented opcode %d (%o)\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)\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][next][first][last][top][bottom][index][help] */
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\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\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][next][first][last][top][bottom][index][help] */
1165   {
1166 #if defined(TESTING)
1167     cpu_state_t * cpup = _cpup;
1168     sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd wtx_output\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\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][next][first][last][top][bottom][index][help] */
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\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\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\n", decoded_p->slot_no);
1245         sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp wtx unimplemented opcode %d (%o)\n",
1246                    decoded_p->slot_no, decoded_p->op_code, decoded_p->op_code);
1247          sim_printf ("fnp wtx unimplemented opcode %d (%o)\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\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][next][first][last][top][bottom][index][help] */
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 ("']\n");
1350 }
1351 }
1352 
1353 //sim_printf ("long  in; line %d tally %d\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][next][first][last][top][bottom][index][help] */
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\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\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\n", decoded_p->slot_no);
1448             sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp unimplemented io_cmd %d\n", decoded_p->slot_no, io_cmd);
1449              sim_printf ("fnp unimplemented io_cmd %d\n", io_cmd);
1450             // doFNPfault (...) // XXX
1451             return -1;
1452           }
1453         default:
1454           {
1455             sim_debug (DBG_TRACE, & fnp_dev, "[%u]rcd illegal opcode\n", decoded_p->slot_no);
1456             sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp illegal io_cmd %d\n", decoded_p->slot_no, io_cmd);
1457             sim_printf ("fnp illegal io_cmd %d\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][next][first][last][top][bottom][index][help] */
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\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\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\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\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\n", decoded_p->slot_no);
1519                   sim_warn ("rtx %d. %o ack ignored\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\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\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\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\n", decoded_p->slot_no);
1550                     //sim_printf ("disconnect_this_line ack.\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\n", decoded_p->slot_no);
1558                     //sim_printf ("fnp reject_request_temp\n");
1559                     // Retry in one second;
1560                     decoded_p->fudp->MState.line[decoded_p->slot_no].accept_input = 100;
1561                   }
1562                   break;
1563 
1564                 case  2: // disconnect_all_lines
1565                 case  3: // dont_accept_calls
1566                 case  4: // accept_calls
1567                 case  5: // input_accepted
1568                 case  6: // set_line_type
1569                 case  7: // enter_receive
1570                 case  8: // set_framing_chars
1571                 case  9: // blast
1572                 case 10: // accept_direct_output
1573                 case 11: // accept_last_output
1574                 case 12: // dial
1575               //case 13: // ???
1576               //case 15: // ???
1577                 case 16: // terminal_rejected
1578                 case 17: // disconnect_accepted
1579                 case 18: // init_complete
1580                 case 19: // dump_mem
1581                 case 20: // patch_mem
1582                 case 21: // fnp_break
1583                 case 22: // line_control
1584                 case 23: // sync_msg_size
1585                 case 24: // set_echnego_break_table
1586                 case 25: // start_negotiated_echo
1587                 case 26: // stop_negotiated_echo
1588                 case 27: // init_echo_negotiation
1589               //case 28: // ???
1590                 case 29: // break_acknowledged
1591                 case 30: // input_fc_chars
1592                 case 31: // output_fc_chars
1593               //case 32: // ???
1594               //case 33: // ???
1595                 case 34: // alter_parameters
1596                 case 35: // checksum_error
1597                 case 36: // report_meters
1598                 case 37: // set_delay_table
1599                   {
1600                     sim_debug (DBG_TRACE, & fnp_dev, "[%u]        unimplemented opcode\n", decoded_p->slot_no);
1601                     sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp reply unimplemented opcode %d (%o)\n",
1602                                decoded_p->slot_no, op_code, op_code);
1603                     sim_printf ("fnp reply unimplemented opcode %d (%o)\n", op_code, op_code);
1604                     // doFNPfault (...) // XXX
1605                     return -1;
1606                   }
1607 
1608                 default:
1609                   {
1610                     sim_debug (DBG_TRACE, & fnp_dev, "[%u]        illegal opcode\n", decoded_p->slot_no);
1611                     sim_debug (DBG_ERR, & fnp_dev, "[%u]fnp reply illegal opcode %d (%o)\n",
1612                                decoded_p->slot_no, op_code, op_code);
1613                     sim_printf ("fnp reply illegal opcode %d (%o)\n", op_code, op_code);
1614                     // doFNPfault (...) // XXX
1615                     return -1;
1616                   }
1617               } // switch op_code
1618 
1619             // Set the TIMW
1620 
1621             // Not sure... XXX
1622             //putbits36_1 (& mbxp -> term_inpt_mpx_wd, cell, 1);
1623             // No; the CS has told us it has updated the mbx, and
1624             // we need to read it; we have done so, so we are finished
1625             // with the mbx, and can mark it so.
1626             decoded_p->fudp->fnpMBXinUse [mbx] = false;
1627 
1628           } // case wcd
1629           break;
1630 
1631         default:
1632           {
1633             sim_debug (DBG_TRACE, & fnp_dev, "[%u]        illegal io_cmd\n", decoded_p->slot_no);
1634             sim_debug (DBG_ERR, & fnp_dev, "[%u]illegal/unimplemented io_cmd (%d) in fnp submbx\n",
1635                        decoded_p->slot_no, io_cmd);
1636             sim_printf ("illegal/unimplemented io_cmd (%d) in fnp submbx\n", io_cmd);
1637             // doFNPfault (...) // XXX
1638             return -1;
1639           }
1640       } // switch (io_cmd)
1641     return 0;
1642   }
1643 
1644 static int interruptL66_CS_done (struct decoded_t *decoded_p)
     /* [previous][next][first][last][top][bottom][index][help] */
1645   {
1646 #if defined(TESTING)
1647     cpu_state_t * cpup = _cpup;
1648 #endif
1649     uint mbx = decoded_p->cell - 12;
1650     //ASSURE(mbx < 4);
1651     if (mbx >= 4)
1652       {
1653         sim_warn ("bad mbx number in interruptL66_CS_done; dropping\n");
1654         return -1;
1655       }
1656     if (! decoded_p->fudp -> fnpMBXinUse [mbx])
1657       {
1658         sim_debug (DBG_ERR, & fnp_dev, "odd -- Multics marked an unused mbx as unused? cell %d (mbx %d)\n",
1659                    decoded_p->cell, mbx);
1660         sim_debug (DBG_ERR, & fnp_dev, "  %d %d %d %d\n",
1661                    decoded_p->fudp -> fnpMBXinUse [0], decoded_p->fudp -> fnpMBXinUse [1],
1662                    decoded_p->fudp -> fnpMBXinUse [2], decoded_p->fudp -> fnpMBXinUse [3]);
1663       }
1664     else
1665       {
1666         sim_debug (DBG_TRACE, & fnp_dev, "Multics marked cell %d (mbx %d) as unused; was %o\n",
1667                    decoded_p->cell, mbx, decoded_p->fudp -> fnpMBXinUse [mbx]);
1668         decoded_p->fudp -> fnpMBXinUse [mbx] = false;
1669         if (decoded_p->fudp->lineWaiting[mbx])
1670           {
1671             struct t_line * linep = & decoded_p->fudp->MState.line[decoded_p->fudp->fnpMBXlineno[mbx]];
1672             sim_debug (DBG_TRACE, & fnp_dev, "clearing wait; was %d\n", linep->waitForMbxDone);
1673             linep->waitForMbxDone = false;
1674           }
1675           sim_debug (DBG_TRACE, & fnp_dev, "  %d %d %d %d\n",
1676                      decoded_p->fudp->fnpMBXinUse [0], decoded_p->fudp->fnpMBXinUse [1],
1677                      decoded_p->fudp->fnpMBXinUse [2], decoded_p->fudp->fnpMBXinUse [3]);
1678       }
1679     return 0;
1680   }
1681 
1682 static int interruptL66 (uint iomUnitIdx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1683   {
1684 #if defined(TESTING)
1685     cpu_state_t * cpup = _cpup;
1686 #endif
1687     struct decoded_t decoded;
1688     struct decoded_t *decoded_p = &decoded;
1689     decoded_p->iom_unit = iomUnitIdx;
1690     decoded_p->chan_num = chan;
1691     decoded_p->devUnitIdx = get_ctlr_idx (iomUnitIdx, chan);
1692     decoded_p->fudp = & fnpData.fnpUnitData [decoded_p->devUnitIdx];
1693     word36 dia_pcw;
1694     iom_direct_data_service (decoded_p->iom_unit, decoded_p->chan_num,
1695                              decoded_p->fudp->mailboxAddress+DIA_PCW, & dia_pcw, direct_load);
1696 
1697 // AN85, pg 13-5
1698 // When the CS has control information or output data to send
1699 // to the FNP, it fills in a submailbox as described in Section 4
1700 // and sends an interrupt over the DIA. This interrupt is handled
1701 // by dail as described above; when the submailbox is read, the
1702 // transaction control word is set to "submailbox read" so that when
1703 // the I/O completes and dtrans runs, the mailbox decoder (decmbx)
1704 // is called. the I/O command in the submail box is either WCD (for
1705 // control information) or WTX (for output data). If it is WCD,
1706 // decmbx dispatches according to a table of operation codes and
1707 // setting a flag in the IB and calling itest, the "test-state"
1708 // entry of the interpreter. n a few cases, the operation requires
1709 // further DIA I/O, but usually all that remains to be does is to
1710 // "free" the submailbox by turning on the corresponding bit in the
1711 // mailbox terminate interrupt multiplex word (see Section 4) and
1712 // set the transaction control word accordingly. When the I/O to
1713 // update TIMW terminates, the transaction is complete.
1714 //
1715 // If the I/O command is WTX, the submailbox contains the
1716 // address and length of a 'pseudo-DCW" list containing the
1717 // addresses and tallies of data buffers in tty_buf. In this case,
1718 // dia_man connects to a DCW list to read them into a reserved area
1719 // in dia_man. ...
1720 
1721 // interrupt level (in "cell"):
1722 //
1723 // mbxs 0-7 are CS -> FNP
1724 // mbxs 8--11 are FNP -> CS
1725 //
1726 //   0-7 Multics has placed a message for the FNP in mbx 0-7.
1727 //   8-11 Multics has updated mbx 8-11
1728 //   12-15 Multics is done with mbx 8-11  (n - 4).
1729 
1730     decoded_p->cell = getbits36_6 (dia_pcw, 24);
1731     sim_debug (DBG_TRACE, & fnp_dev, "CS interrupt %u\n", decoded_p->cell);
1732     if (decoded_p->cell < 8)
1733       {
1734         interruptL66_CS_to_FNP (decoded_p);
1735       }
1736     else if (decoded_p->cell >= 8 && decoded_p->cell <= 11) //-V560
1737       {
1738         interruptL66_FNP_to_CS (decoded_p);
1739       }
1740     else if (decoded_p->cell >= 12 && decoded_p->cell <= 15) //-V560
1741       {
1742         interruptL66_CS_done (decoded_p);
1743       }
1744     else
1745       {
1746         sim_debug (DBG_ERR, & fnp_dev, "fnp illegal cell number %d\n", decoded_p->cell);
1747         sim_printf ("fnp illegal cell number %d\n", decoded_p->cell);
1748         // doFNPfault (...) // XXX
1749         return -1;
1750       }
1751     return 0;
1752   }
1753 
1754 static void fnpcmdBootload (uint devUnitIdx)
     /* [previous][next][first][last][top][bottom][index][help] */
1755   {
1756 #if defined(TESTING)
1757     cpu_state_t * cpup = _cpup;
1758 #endif
1759     sim_printf("\r[FNP emulation: FNP %c received BOOTLOAD command]\r\n", (int)('a' + (int)devUnitIdx));
1760     fnpData.fnpUnitData[devUnitIdx].MState.accept_calls = false;
1761     bool have3270 = false;
1762     for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
1763       {
1764         fnpData.fnpUnitData[devUnitIdx].MState.line [lineno] . listen = false;
1765         if (fnpData.fnpUnitData[devUnitIdx].MState.line [lineno].line_client)
1766           {
1767             fnpuv_start_writestr (fnpData.fnpUnitData[devUnitIdx].MState.line [lineno].line_client,
1768               (unsigned char *) "\r[FNP emulation: FNP restarted]\r\n");
1769           }
1770         if (fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].service == service_3270)
1771           {
1772               sim_debug (DBG_TRACE, & fnp_dev, "3270 controller found at unit %u line %u\r\n", devUnitIdx, lineno);
1773             // XXX assuming only single controller
1774             if (fnpData.ibm3270ctlr[ASSUME0].configured)
1775               {
1776                 sim_warn ("Too many 3270 controllers configured");
1777               }
1778             else
1779               {
1780                 have3270 = true;
1781                 (void)memset (& fnpData.ibm3270ctlr[ASSUME0], 0, sizeof (struct ibm3270ctlr_s));
1782                 fnpData.ibm3270ctlr[ASSUME0].configured = true;
1783                 fnpData.ibm3270ctlr[ASSUME0].fnpno = devUnitIdx;
1784                 fnpData.ibm3270ctlr[ASSUME0].lineno = lineno;
1785 
1786                 // 3270 controller connects immediately
1787                 // Set from CMF data now.
1788                 //fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType  = 7 /* LINE_BSC */;
1789                 if (fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType == 0) /* LINE_NONE */
1790                   fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].lineType = 7; /* LINE_BSC */
1791                 fnpData.fnpUnitData[devUnitIdx].MState.line[lineno].accept_new_terminal = true;
1792               }
1793           }
1794       }
1795     (void)fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
1796     if (have3270)
1797       (void)fnpuv3270Init (fnpData.telnet3270_port);
1798   }
1799 
1800 
1801 static word18 getl6core (uint iom_unit_idx, uint chan, word24 l66addr, uint addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1802   {
1803     word24 wos = addr / 2;
1804     word36 word;
1805     iom_direct_data_service (iom_unit_idx, chan, l66addr + wos, & word, direct_load);
1806     if (addr & 1)
1807       return (word18) (word & MASK18);
1808     else
1809       return (word18) ((word >> 18) & MASK18);
1810   }
1811 
1812 
1813 static void processMBX (uint iomUnitIdx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1814   {
1815 #if defined(TESTING)
1816     cpu_state_t * cpup = _cpup;
1817 #endif
1818     uint fnp_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1819     struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
1820 
1821 // 60132445 FEP Coupler EPS
1822 // 2.2.1 Control Intercommunication
1823 //
1824 // "In Level 66 memory, at a location known to the coupler and
1825 // to Level 6 software is a mailbox area consisting to an Overhead
1826 // mailbox and 7 Channel mailboxes."
1827 
1828     bool ok = true;
1829 
1830     word36 dia_pcw;
1831     iom_direct_data_service (iomUnitIdx, chan, fudp->mailboxAddress+DIA_PCW, & dia_pcw, direct_load);
1832     sim_debug (DBG_TRACE, & fnp_dev,
1833                "%s: chan %d dia_pcw %012"PRIo64"\n", __func__, chan, dia_pcw);
1834 
1835 // Mailbox word 0:
1836 //
1837 //   0-17 A
1838 //     18 I
1839 //  19-20 MBZ
1840 //  21-22 RFU
1841 //     23 0
1842 //  24-26 B
1843 //  27-29 D Channel #
1844 //  30-35 C Command
1845 //
1846 //                          A6-A23    A0-A2     A3-A5
1847 // Operation          C         A        B        D
1848 // Interrupt L6      071       ---      Int.     Level
1849 // Bootload L6       072    L66 Addr  L66 Addr  L66 Addr
1850 //                           A6-A23    A0-A2     A3-A5
1851 // Interrupt L66     073      ---      ---     Intr Cell
1852 // Data Xfer to L66  075    L66 Addr  L66 Addr  L66 Addr
1853 //                           A6-A23    A0-A2     A3-A5
1854 // Data Xfer to L6   076    L66 Addr  L66 Addr  L66 Addr
1855 //                           A6-A23    A0-A2     A3-A5
1856 
1857 //
1858 // fnp_util.pl1:
1859 //    075 tandd read
1860 //    076 tandd write
1861 
1862 // mbx word 1: mailbox_requests fixed bin
1863 //          2: term_inpt_mpx_wd bit (36) aligned
1864 //          3: last_mbx_req_count fixed bin
1865 //          4: num_in_use fixed bin
1866 //          5: mbx_used_flags
1867 //                used (0:7) bit (1) unaligned
1868 //                pad2 bit (28) unaligned
1869 //          6,7: crash_data
1870 //                fault_code fixed bin (18) unal unsigned
1871 //                ic fixed bin (18) unal unsigned
1872 //                iom_fault_status fixed bin (18) unal unsigned
1873 //                fault_word fixed bin (18) unal unsigned
1874 //
1875 //    crash_data according to dn355_boot_interrupt.pl1:
1876 //
1877 //   dcl  1 fnp_boot_status aligned based (stat_ptr),            /* structure of bootload status */
1878 //          2 real_status bit (1) unaligned,                     /* must be "1"b in valid status */
1879 //          2 pad1 bit (2) unaligned,
1880 //          2 major_status bit (3) unaligned,
1881 //          2 pad2 bit (3) unaligned,
1882 //          2 substatus fixed bin (8) unal,                      /* code set by 355, only interesting if major_status is 4 */
1883 //          2 channel_no fixed bin (17) unaligned;               /* channel no. of LSLA in case of config error */
1884 //    only 34 bits???
1885 // major_status:
1886 //  dcl  BOOTLOAD_OK fixed bin int static options (constant) init (0);
1887 //  dcl  CHECKSUM_ERROR fixed bin int static options (constant) init (1);
1888 //  dcl  READ_ERROR fixed bin int static options (constant) init (2);
1889 //  dcl  GICB_ERROR fixed bin int static options (constant) init (3);
1890 //  dcl  INIT_ERROR fixed bin int static options (constant) init (4);
1891 //  dcl  UNWIRE_STATUS fixed bin int static options (constant) init (5);
1892 //  dcl  MAX_STATUS fixed bin int static options (constant) init (5);
1893 
1894 // 3.5.1 Commands Issued by Central System
1895 //
1896 // In the issuing of an order by the Central System to the Coupler, the
1897 // sequence occurs:
1898 //
1899 // 1. The L66 program creates a LPW and Pcw for the Central System Connect
1900 // channel. It also generates and stores a control word containing a command
1901 // int he L66 mailbox. A Connect is then issued to the L66 IOM.
1902 //
1903 // 2. The Connect Channel accesses the PCW to get the channel number of
1904 // the Direct Channel that the coupler is attached to. the direct Channel
1905 // sends a signal to the Coupler that a Connect has been issued.
1906 //
1907 // 3. The Coupler now reads the content of the L66 mailbox, obtaining the
1908 // control word. If the control word is legal, the Coupler will write a
1909 // word of all zeros into the mailbox.
1910 //
1911 
1912 // 4.1.1.2 Transfer Control Word.
1913 // The transfer control word, which is pointed to by the
1914 // mailbox word in l66 memory on Op Codes 72, 7, 76 contains
1915 // a starting address which applies to L6 memory an a Tally
1916 // of the number of 36 bit words to be transferred. The l66
1917 // memory locations to/from which the transfers occur are
1918 // those immediately following the location where this word
1919 // was obtained.
1920 //
1921 //    00-02  001
1922 //    03-17 L6 Address
1923 //       18 P
1924 //    19-23 MBZ
1925 //    24-25 Tally
1926 //
1927 //     if P = 0 the l6 address:
1928 //        00-07 00000000
1929 //        08-22 L6 address (bits 3-17)
1930 //           23 0
1931 //     if P = 1
1932 //        00-14 L6 address (bits 3-17)
1933 //        15-23 0
1934 //
1935 
1936     uint command = getbits36_6 (dia_pcw, 30);
1937     word36 bootloadStatus = 0;
1938 
1939     if (command == 000) // reset
1940       {
1941         sim_debug (DBG_TRACE, & fnp_dev,
1942                    "%s: chan %d reset command\n", __func__, chan);
1943         send_general_interrupt (iomUnitIdx, chan, imwTerminatePic);
1944       }
1945     else if (command == 072) // bootload
1946       {
1947 
1948         word24 l66addr = (((word24) getbits36_6 (dia_pcw, 24)) << 18) |
1949                            (word24) getbits36_18 (dia_pcw, 0);
1950 
1951 // AN85-01 15-2
1952 //   0 boot dcw
1953 //   1  gicb
1954 //      ....
1955 //      padding to next multiple of 64
1956 //   n  core image
1957 //
1958 // where n is (in 36 bit words) (gicb len + 1) + 63 / 64
1959 
1960 //sim_printf ("l66addr %08o\n", l66addr);
1961         word36 dcw;
1962         iom_direct_data_service (iomUnitIdx, chan, l66addr, & dcw, direct_load);
1963         word12 tally = getbits36_12 (dcw, 24);
1964         // sim_printf ("%o %d.\n", tally, tally);
1965 //sim_printf ("dcw %012llo\n", dcw);
1966 
1967         // Calculate start of core image
1968         word24 image_off = (tally + 64) & 077777700;
1969         // sim_printf ("image_off %o %d.\n", image_off, image_off);
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 // comm_ref
2001 //   0640   crldt  72
2002 //   0644   crbdt  72
2003 //   0650   crbuf  18
2004 //   0651   crmem  18
2005 //   0652   crnbf  18
2006 //   0653   criom  18
2007 
2008 //     2 comm_reg unal,                   /* software communications region */
2009 // 0640  3 crldt fixed bin (71) aligned,  /* date and time binder */
2010 // 0644  3 crbdt fixed bin (71) aligned,  /* date and time image booted */
2011 // 0650  3 crbuf fixed bin (17) unal,     /* base of free buffer pool */
2012 // 0651  3 crmem fixed bin (18) unsigned unal, /* last loc of mem configured */
2013 // 0652  3 crnbf fixed bin (17) unal,     /* free buffers in pool now */
2014 // 0653  3 criom fixed bin (17) unal,     /* pointer to iom table */
2015 // 0654  3 crnhs fixed bin (17) unal,     /* number of HSLAs */
2016 // 0655  3 crnls fixed bin (17) unal,     /* number of LSLAs */
2017 // 0656  3 crcon bit (18) unal,           /* console enable switch */
2018 // 0657  3 crmod fixed bin (17) unal,     /* base of module chain */
2019 //       3 crnxa fixed bin (17) unal,     /* ptr to head of free space chain */
2020 //       3 crtra bit (18) unal,           /* trace entry enable mask */
2021 //       3 crtrb fixed bin (18) unsigned unal, /* base of trace table */
2022 //       3 crtrc fixed bin (18) unsigned unal, /* next trace table entry ptr */
2023 //       3 crreg fixed bin (17) unal,    /* ptr to fault reg storage area */
2024 //       3 crttb fixed bin (17) unal,    /* ptr to tib table base */
2025 //       3 crtte fixed bin (17) unal,    /* last addr in tib table */
2026 //       3 crdly fixed bin (17) unal,    /* pointer to delay table chain */
2027 //       3 crver char (4) unal, /* mcs version number */
2028 //       3 crbrk fixed bin (17) unal,    /* pointer to breakpoint control table */
2029 //       3 crtsw bit (18) unal, /* trace switch (zero=trace on) */
2030 //       3 crnxs fixed bin (17) unal,    /* pointer to next free small block */
2031 //       3 crnbs fixed bin (17) unal,    /* number of buffers devoted to small space */
2032 //       3 crcct fixed bin (17) unal,    /* pointer to first cct descriptor */
2033 //       3 crskd fixed bin (17) unal,    /* pointer to scheduler data block */
2034 //       3 cretb fixed bin (17) unal,    /* pointer to list of echo-negotiation bit tables */
2035 //       3 crcpt fixed bin (17) unal,    /* pointer to cpu page table */
2036 //       3 crpte fixed bin (17) unal,    /* pointer to variable cpu page table entry */
2037 //       3 crtsz fixed bin (17) unal,    /* size of trace data buffer */
2038 //       3 crmet bit (18) unal,          /* metering enabled */
2039 //       3 crtdt bit (18) unal,          /* 0 if no COLTS channel; set to TIB address if it exists */
2040 //       3 crbtm bit (18) unal,          /* address of time meters for buffer allocation/freeing */
2041 //       3 crnxe fixed bin (18) unsigned unal, /* next available space in extended memory */
2042 //       3 crbpe fixed bin (17) unal,    /* buffer paging window table entry */
2043 //       3 pad (39) bit (18) unal,
2044 //       3 crcpr char (28) unal,         /* image copyright notice */
2045 //       3 crash_location bit (18) unal, /* offset used for unresolved REF's */
2046 //       3 crash_opcode bit (18) unal,   /* crash instruction */
2047 
2048 
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         // Number of LSLAs
2101 # if defined(VERBOSE_BOOT)
2102         word18 crnls = getl6core (iomUnitIdx, chan, l66addr + image_off, 0655);
2103         sim_printf ("Number of LSLAs (crnls) %d\n", crnls);
2104 # endif /* if defined(VERBOSE_BOOT) */
2105 
2106         // Address of IOM table
2107         word18 criom = getl6core (iomUnitIdx, chan, l66addr + image_off, 0653);
2108 
2109         // Walk the LSLAs in the IOM table
2110         //  2 words/slot (flags, taddr)
2111         //  6 LSLA slots
2112         //  first slot at first_lsla_ch 9
2113 
2114         bool hdr = false;
2115 # if defined(VERBOSE_BOOT)
2116         uint nfound = 0;
2117 # endif /* if defined(VERBOSE_BOOT) */
2118         for (uint lsla = 0; lsla < 6; lsla ++)
2119           {
2120             uint slot = lsla + 9;
2121             uint os = slot * 2;
2122             // get flags word
2123             word18 flags = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os);
2124             uint device_type_code = (flags >> 4) & 037;
2125             if (device_type_code == 4)
2126               {
2127 # if defined (VERBOSE_BOOT)
2128                 nfound ++;
2129 # endif /* if defined(VERBOSE_BOOT) */
2130                 // get addr word
2131                 word18 tblp = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os + 1);
2132                 for (uint slot = 0; slot < 52; slot ++)
2133                   {
2134                     // 2 word18s per entry
2135                     //   pad bit(11)
2136                     //   ibm_code bit(1)   // if 6-bit odd parity
2137                     //   pad2 bit(3)
2138                     //   slot_id bit(3)
2139                     //
2140                     //   ptr bit(18)
2141                     word3 slot_id = getl6core (iomUnitIdx, chan, l66addr + image_off, tblp + 2 * slot) & MASK3;
2142                     if (slot_id != 7)
2143                       {
2144 # if defined(VERBOSE_BOOT)
2145                         char * slot_ids [8] =
2146                           {
2147                             "10 cps",
2148                             "30 cps, slot 1",
2149                             "30 cps, slot 2",
2150                             "30 cps, slot 3",
2151                             "invalid",
2152                             "15 cps, slot 1",
2153                             "15 cps, slot 2",
2154                             "unused"
2155                           };
2156                         char * id = slot_ids[slot_id];
2157 # endif /* if defined(VERBOSE_BOOT) */
2158                         if (! hdr)
2159                           {
2160                             hdr = true;
2161 # if defined(VERBOSE_BOOT)
2162                             sim_printf ("LSLA table: card number, slot, slot_id, slot_id string\n");
2163 # endif /* if defined(VERBOSE_BOOT) */
2164                           }
2165 # if defined(VERBOSE_BOOT)
2166                         sim_printf ("%d %2d %d %s\n", lsla, slot, slot_id, id);
2167 # endif /* if defined(VERBOSE_BOOT) */
2168                       }
2169                   } // for slot
2170               } // if dev type 4 (LSLA)
2171           } // iom table entry
2172 # if defined(VERBOSE_BOOT)
2173         if (nfound != crnls)
2174           sim_printf ("LSLAs configured %d found %d\n", crnls, nfound);
2175 # endif /* if defined(VERBOSE_BOOT) */
2176 
2177         // Number of HSLAs
2178 # if defined(VERBOSE_BOOT)
2179         word18 crnhs = getl6core (iomUnitIdx, chan, l66addr + image_off, 0654);
2180         sim_printf ("Number of HSLAs (crnhs) %d\n", crnhs);
2181 # endif /* if defined(VERBOSE_BOOT) */
2182 
2183         // Walk the HSLAs in the IOM table
2184         //  2 words/slot (flags, taddr)
2185         //  3 LSLA slots
2186         //  first slot at first_hsla_ch 6
2187 
2188         hdr = false;
2189 # if defined(VERBOSE_BOOT)
2190         nfound = 0;
2191 # endif /* if defined(VERBOSE_BOOT) */
2192         for (uint hsla = 0; hsla < 3; hsla ++)
2193           {
2194             uint slot = hsla + 6;
2195             uint os = slot * 2;
2196             // get flags word
2197             word18 flags = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os);
2198             uint device_type_code = (flags >> 4) & 037;
2199             if (device_type_code == 3)
2200               {
2201 # if defined(VERBOSE_BOOT)
2202                 nfound ++;
2203 # endif /* if defined(VERBOSE_BOOT) */
2204                 // get addr word
2205                 word18 tblp = getl6core (iomUnitIdx, chan, l66addr + image_off, criom + os + 1);
2206                 for (uint slot = 0; slot < 32; slot ++)
2207                   {
2208                     // 2 word18s per entry
2209                     //   conc_chan bit(1)
2210                     //   private_line bit(1)
2211                     //   async bit(1)
2212                     //   option1 bit(1)
2213                     //   option2 bit(1)
2214                     //   modem_type bit(4)
2215                     //   line_type bit(5)
2216                     //   dev_speed bit(4)
2217                     //
2218                     //   ptr bit(18)
2219 
2220 # if defined(VERBOSE_BOOT)
2221                     char * line_types[23] =
2222                       {
2223                         "none      ",
2224                         "ASCII     ",
2225                         "1050      ",
2226                         "2741      ",
2227                         "ARDS      ",
2228                         "Sync      ",
2229                         "G115      ",
2230                         "BSC       ",
2231                         "202ETX    ",
2232                         "VIP       ",
2233                         "ASYNC1    ",
2234                         "ASYNC2    ",
2235                         "ASYNC3    ",
2236                         "SYNC1     ",
2237                         "SYNC2     ",
2238                         "SYNC3     ",
2239                         "POLLED_VIP",
2240                         "X25LAP    ",
2241                         "HDLC      ",
2242                         "COLTS     ",
2243                         "DSA       ",
2244                         "HASP_OPR  ",
2245                         "invalid   "
2246                       };
2247 # endif
2248 
2249 # if defined(VERBOSE_BOOT)
2250                     char * modem_types[8] =
2251                       {
2252                         "invalid      ",
2253                         "Bell 103A/113",
2254                         "Bell 201C    ",
2255                         "Bell 202C5   ",
2256                         "Bell 202C6   ",
2257                         "Bell 208A    ",
2258                         "Bell 208B    ",
2259                         "Bell 209A    "
2260                       };
2261 # endif
2262 
2263 
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 # if defined(VERBOSE_BOOT)
2295                     char * async_speeds[16] =
2296                       {
2297                         "invalid",
2298                         "110    ",
2299                         "133    ",
2300                         "150    ",
2301                         "300    ",
2302                         "600    ",
2303                         "1200   ",
2304                         "1800   ",
2305                         "2400   ",
2306                         "4800   ",
2307                         "7200   ",
2308                         "9600   ",
2309                         "19200  ",
2310                         "40800  ",
2311                         "50000  ",
2312                         "72000  "
2313                       };
2314 
2315                     char * sync_speeds[16] =
2316                       {
2317                         "invalid",
2318                         "2000   ",
2319                         "2400   ",
2320                         "3600   ",
2321                         "4800   ",
2322                         "5400   ",
2323                         "7200   ",
2324                         "9600   ",
2325                         "19200  ",
2326                         "40800  ",
2327                         "50000  ",
2328                         "invalid",
2329                         "invalid",
2330                         "invalid",
2331                         "invalid",
2332                         "invalid"
2333                       };
2334 # endif
2335                     word18 subch_data = getl6core (iomUnitIdx, chan, l66addr + image_off, tblp + 2 * slot);
2336 # if defined(VERBOSE_BOOT)
2337                     word1 async = (subch_data >> 15) & 1;
2338                     word1 option1 = (subch_data >> 14) & 1;
2339 # endif
2340                     word5 line_type = (subch_data >> 4)  & MASK5;
2341                     if (line_type > 22)
2342                       line_type = 22;
2343                     word4 modem_type = (subch_data >> 9)  & MASK4;
2344                     if (modem_type > 7)
2345                       modem_type = 0;
2346 # if defined(VERBOSE_BOOT)
2347                     word4 dev_speed = subch_data  & MASK4;
2348                     //if (dev_speed > 10)
2349                       //dev_speed = 0;
2350                     char * speed = async ? async_speeds[dev_speed] : sync_speeds[dev_speed];
2351                     if (async && dev_speed == 4 && option1)
2352                       speed = "auto   ";
2353 # endif
2354                     if (! hdr)
2355                       {
2356                         hdr = true;
2357 # if defined(VERBOSE_BOOT)
2358                         sim_printf ("HSLA table: card number, slot, "
2359                                     "sync/async, line type, modem_type, "
2360                                     "speed\n");
2361 # endif
2362                       }
2363 # if defined(VERBOSE_BOOT)
2364                     sim_printf ("%d %2d %s %s %s %s\n",
2365                                  hsla, slot, async ? "async" :"sync ",
2366                                  line_types[line_type],
2367                                  modem_types[modem_type],
2368                                  speed);
2369 # endif
2370                      uint lineno = hsla * 32u + slot;
2371                      struct t_line * linep = & fudp->MState.line[lineno];
2372 
2373 
2374 
2375 
2376 
2377 
2378 
2379                      //linep->lineType = line_type ? line_type : 1; // Map none to ASCII
2380                      linep->lineType = line_type;
2381                   } // for slot
2382               } // if dev type 4 (LSLA)
2383           } // iom table entry
2384 # if defined(VERBOSE_BOOT)
2385         if (nfound != crnls)
2386           sim_printf ("LSLAs configured %d found %d\n", crnls, nfound);
2387 # endif /* if defined(VERBOSE_BOOT) */
2388 
2389 
2390 #if defined(THREADZ) || defined(LOCKLESS)
2391         lock_libuv ();
2392 #endif
2393         fnpcmdBootload (fnp_unit_idx);
2394 #if defined(THREADZ) || defined(LOCKLESS)
2395         unlock_libuv ();
2396 #endif
2397         send_general_interrupt (iomUnitIdx, chan, imwTerminatePic);
2398         fudp -> fnpIsRunning = true;
2399       }
2400     else if (command == 071) // interrupt L6
2401       {
2402 #if defined(THREADZ) || defined(LOCKLESS)
2403         lock_libuv ();
2404 #endif
2405         ok = interruptL66 (iomUnitIdx, chan) == 0;
2406 #if defined(THREADZ) || defined(LOCKLESS)
2407         unlock_libuv ();
2408 #endif
2409       }
2410     else if (command == 075) // data xfer from L6 to L66
2411       {
2412         // Build the L66 address from the PCW
2413         //   0-17 A
2414         //  24-26 B
2415         //  27-29 D Channel #
2416         // Operation          C         A        B        D
2417         // Data Xfer to L66  075    L66 Addr  L66 Addr  L66 Addr
2418         //                           A6-A23    A0-A2     A3-A5
2419         // These don't seem to be right; M[L66Add] is always 0.
2420         //word24 A = (word24) getbits36_18 (dia_pcw,  0);
2421         //word24 B = (word24) getbits36_3  (dia_pcw, 24);
2422         //word24 D = (word24) getbits36_3  (dia_pcw, 29);
2423         //word24 L66Addr = (B << (24 - 3)) | (D << (24 - 3 - 3)) | A;
2424 
2425         // According to fnp_util:
2426         //                      /* better declaration than the one used when MCS is running */
2427         //  dcl  1 a_dia_pcw aligned based (mbxp),
2428         //         2 address fixed bin (18) unsigned unaligned,
2429         //         2 error bit (1) unaligned,
2430         //         2 pad1 bit (3) unaligned,
2431         //         2 parity bit (1) unaligned,
2432         //         2 pad2 bit (1) unaligned,
2433         //                            /* if we used address extension this would be important */
2434         //         2 pad3 bit (3) unaligned,
2435         //         2 interrupt_level fixed bin (3) unsigned unaligned,
2436         //         2 command bit (6) unaligned;
2437         //
2438         //   a_dia_pcw.address = address;
2439         //
2440 
2441         //word24 L66Addr = (word24) getbits36_18 (dia_pcw, 0);
2442         //sim_printf ("L66 xfer\n");
2443         //sim_printf ("PCW  %012"PRIo64"\n", dia_pcw);
2444         //sim_printf ("L66Addr %08o\n", L66Addr);
2445         //sim_printf ("M[] %012"PRIo64"\n", M[L66Addr]);
2446 
2447         // 'dump_mpx d'
2448         //L66 xfer
2449         //PCW  022002000075
2450         //L66Addr 00022002
2451         //M[] 000000401775
2452         //L66 xfer
2453         //PCW  022002000075
2454         //L66Addr 00022002
2455         //M[] 003772401775
2456         //L66 xfer
2457         //PCW  022002000075
2458         //L66Addr 00022002
2459         //M[] 007764401775
2460         //
2461         // The contents of M seem much more reasonable, bit still don't match
2462         // fnp_util$setup_dump_ctl_word. The left octet should be '1', not '0';
2463         // bit 18 should be 0 not 1. But the offsets and tallies match exactly.
2464         // Huh... Looking at 'dump_6670_control' control instead, it matches
2465         // correctly. Apparently fnp_util thinks the FNP is a 6670, not a 335.
2466         // I can't decipher the call path, so I don't know why; but looking at
2467         // multiplexer_types.incl.pl1, I would guess that by MR12.x, all FNPs
2468         // were 6670s.
2469         //
2470         // So:
2471         //          /* word used to supply DN6670 address and tally for fdump */
2472         //   dcl  1 dump_6670_control aligned based (data_ptr),
2473         //          2 fnp_address fixed bin (18) unsigned unaligned,
2474         //          2 unpaged bit (1) unaligned,
2475         //          2 mbz bit (5) unaligned,
2476         //          2 tally fixed bin (12) unsigned unaligned;
2477 
2478         // Since the data is marked 'paged', and I don't understand the
2479         // the paging mechanism or parameters, I'm going to punt here and
2480         // not actually transfer any data.
2481 
2482       }
2483     else
2484       {
2485         sim_warn ("bogus fnp command %d (%o)\n", command, command);
2486         ok = false;
2487       }
2488 
2489     if (ok)
2490       {
2491 #if defined(TESTING)
2492         if_sim_debug (DBG_TRACE, & fnp_dev) dmpmbx (fudp->mailboxAddress);
2493 #endif
2494         //iom_chan_data [iomUnitIdx] [chan] . in_use = false;
2495         dia_pcw = 0;
2496         iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+DIA_PCW, & dia_pcw, direct_store);
2497         putbits36_1 (& bootloadStatus, 0, 1); // real_status = 1
2498         putbits36_3 (& bootloadStatus, 3, 0); // major_status = BOOTLOAD_OK;
2499         putbits36_8 (& bootloadStatus, 9, 0); // substatus = BOOTLOAD_OK;
2500         putbits36_17 (& bootloadStatus, 17, 0); // channel_no = 0;
2501         iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+CRASH_DATA, & bootloadStatus, direct_store);
2502       }
2503     else
2504       {
2505 #if defined(TESTING)
2506         if_sim_debug (DBG_TRACE, & fnp_dev) dmpmbx (fudp->mailboxAddress);
2507 #endif
2508         // 3 error bit (1) unaligned, /* set to "1"b if error on connect */
2509         //iom_chan_data [iomUnitIdx] [chan] . in_use = false;
2510         putbits36_1 (& dia_pcw, 18, 1); // set bit 18
2511         iom_direct_data_service (iomUnitIdx, chan, fudp -> mailboxAddress+DIA_PCW, & dia_pcw, direct_store);
2512       }
2513   }
2514 
2515 static int fnpCmd (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
2516   iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
2517 
2518   switch (p->IDCW_DEV_CMD) {
2519     case 000: { // CMD 00 Request status
2520         p->stati = 04000;
2521         processMBX (iomUnitIdx, chan);
2522         // no status_service and no additional terminate interrupt
2523         // ???
2524       }
2525       return IOM_CMD_DISCONNECT;
2526 
2527     default: {
2528       p->stati = 04501; // cmd reject, invalid opcode
2529       p->chanStatus = chanStatIncorrectDCW;
2530       if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
2531         sim_warn ("%s: FNP unrecognized device command  %02o\n", __func__, p->IDCW_DEV_CMD);
2532       }
2533       return IOM_CMD_ERROR;
2534   }
2535 }
2536 
2537 /*
2538  * fnp_iom_cmd()
2539  *
2540  */
2541 
2542 iom_cmd_rc_t fnp_iom_cmd (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
2543   iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
2544 // Is it an IDCW?
2545 
2546   if (IS_IDCW (p)) {
2547     return fnpCmd (iomUnitIdx, chan);
2548   }
2549   // else // DDCW/TDCW
2550   sim_warn ("%s expected IDCW\n", __func__);
2551   return IOM_CMD_ERROR;
2552 }

/* [previous][next][first][last][top][bottom][index][help] */