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

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