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

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