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

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