root/src/dps8/dps8_dia.c

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

DEFINITIONS

This source file includes following definitions.
  1. fnp_core_read
  2. set_config
  3. show_config
  4. show_status
  5. show_nunits
  6. set_nunits
  7. reset
  8. attach
  9. detach
  10. dia_init
  11. fnp_core_write
  12. virtToPhys
  13. cmd_bootload
  14. interruptL66
  15. processMBX
  16. dia_cmd
  17. dia_iom_cmd
  18. load_stored_boot
  19. poll_coupler
  20. dia_unit_process_events
  21. dia_process_events

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * SPDX-License-Identifier: Multics
   5  * scspell-id: 134751ac-f62e-11ec-b67e-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * Copyright (c) 2007-2013 Michael Mondy
  10  * Copyright (c) 2012-2016 Harry Reed
  11  * Copyright (c) 2013-2022 Charles Anthony
  12  * Copyright (c) 2021-2023 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 #include <stdio.h>
  31 #include <ctype.h>
  32 
  33 #include "dps8.h"
  34 #include "dps8_dia.h"
  35 #include "dps8_sys.h"
  36 #include "dps8_cpu.h"
  37 #include "dps8_cache.h"
  38 #include "dps8_faults.h"
  39 #include "dps8_scu.h"
  40 #include "dps8_iom.h"
  41 #include "dps8_cable.h"
  42 #include "dps8_utils.h"
  43 
  44 #include "udplib.h"
  45 
  46 #define DBG_CTR 1
  47 
  48 #if defined(THREADZ)
  49 # include "threadz.h"
  50 #endif /* if defined(THREADZ) */
  51 
  52 #if defined(FREE)
  53 # undef FREE
  54 #endif /* if defined(FREE) */
  55 #define FREE(p) do  \
  56   {                 \
  57     free((p));      \
  58     (p) = NULL;     \
  59   } while(0)
  60 
  61 static inline void fnp_core_read (word24 addr, word36 *data, UNUSED const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
  62   {
  63 #if defined(THREADZ)
  64     lock_mem_rd ();
  65 #endif /* if defined(THREADZ) */
  66     * data = M [addr] & DMASK;
  67 #if defined(THREADZ)
  68     unlock_mem ();
  69 #endif /* if defined(THREADZ) */
  70   }
  71 #define N_DIA_UNITS 1 // default
  72 #define DIA_UNIT_IDX(uptr) ((uptr) - dia_unit)
  73 
  74 static config_list_t dia_config_list [] =
  75   {
  76     /*  0 */
  77     { "mailbox",   0, 07777, NULL },
  78     { NULL,        0, 0,     NULL }
  79   };
  80 
  81 static t_stat set_config (UNIT * uptr, UNUSED int value, const char * cptr, UNUSED void * desc)
     /* [previous][next][first][last][top][bottom][index][help] */
  82   {
  83     uint dia_unit_idx = (uint) DIA_UNIT_IDX (uptr);
  84     //if (dia_unit_idx >= dia_dev.numunits)
  85     if (dia_unit_idx >= N_DIA_UNITS_MAX)
  86       {
  87         sim_debug (DBG_ERR, & dia_dev, "DIA SET CONFIG: Invalid unit number %ld\r\n",
  88                 (long) dia_unit_idx);
  89         sim_printf ("error: DIA SET CONFIG: Invalid unit number %ld\r\n",
  90                 (long) dia_unit_idx);
  91         return SCPE_ARG;
  92       }
  93 
  94     struct dia_unit_data * dudp = dia_data.dia_unit_data + dia_unit_idx;
  95 
  96     config_state_t cfg_state = { NULL, NULL };
  97 
  98     for (;;)
  99       {
 100         int64_t v;
 101         int rc = cfg_parse ("DIA SET CONFIG", cptr, dia_config_list, & cfg_state, & v);
 102         switch (rc)
 103           {
 104             case -2: // error
 105               cfg_parse_done (& cfg_state);
 106               return SCPE_ARG;
 107 
 108             case -1: // done
 109               break;
 110 
 111             case 0: // mailbox
 112               dudp -> mailbox_address = (uint) v;
 113               break;
 114 
 115             default:
 116               sim_printf ("error: DIA SET CONFIG: Invalid cfg_parse rc <%ld>\r\n", (long) rc);
 117               cfg_parse_done (& cfg_state);
 118               return SCPE_ARG;
 119           } // switch
 120         if (rc < 0)
 121           break;
 122       } // process statements
 123     cfg_parse_done (& cfg_state);
 124     return SCPE_OK;
 125   }
 126 
 127 static t_stat show_config (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
 128                            UNUSED const void * desc)
 129   {
 130     long unit_idx = DIA_UNIT_IDX (uptr);
 131     if (unit_idx >= (long) N_DIA_UNITS_MAX)
 132       {
 133         sim_debug (DBG_ERR, & dia_dev,
 134                    "DIA SHOW CONFIG: Invalid unit number %ld\r\n", (long) unit_idx);
 135         sim_printf ("error: Invalid unit number %ld\r\n", (long) unit_idx);
 136         return SCPE_ARG;
 137       }
 138 
 139     sim_printf ("DIA unit number %ld\r\n", (long) unit_idx);
 140     struct dia_unit_data * dudp = dia_data.dia_unit_data + unit_idx;
 141 
 142     sim_printf ("DIA Mailbox Address:         %04o(8)\r\n", dudp -> mailbox_address);
 143 
 144     return SCPE_OK;
 145   }
 146 
 147 static t_stat show_status (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
 148                              UNUSED const void * desc)
 149   {
 150     long dia_unit_idx = DIA_UNIT_IDX (uptr);
 151     if (dia_unit_idx >= (long) dia_dev.numunits)
 152       {
 153         sim_debug (DBG_ERR, & dia_dev,
 154                    "DIA SHOW STATUS: Invalid unit number %ld\r\n", (long) dia_unit_idx);
 155         sim_printf ("error: Invalid unit number %ld\r\n", (long) dia_unit_idx);
 156         return SCPE_ARG;
 157       }
 158 
 159     sim_printf ("DIA unit number %ld\r\n", (long) dia_unit_idx);
 160     struct dia_unit_data * dudp = dia_data.dia_unit_data + dia_unit_idx;
 161 
 162     sim_printf ("mailbox_address:              %04o\r\n", dudp->mailbox_address);
 163     return SCPE_OK;
 164   }
 165 
 166 static t_stat show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 167                            UNUSED int val, UNUSED const void * desc)
 168   {
 169     sim_printf("Number of DIA units in system is %d\r\n", dia_dev.numunits);
 170     return SCPE_OK;
 171   }
 172 
 173 static t_stat set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 174                              const char * cptr, UNUSED void * desc)
 175   {
 176     if (! cptr)
 177       return SCPE_ARG;
 178     int n = atoi (cptr);
 179     if (n < 1 || n > N_DIA_UNITS_MAX)
 180       return SCPE_ARG;
 181     dia_dev.numunits = (uint32) n;
 182     return SCPE_OK;
 183   }
 184 
 185 static MTAB dia_mod [] =
 186   {
 187     {
 188       MTAB_XTD | MTAB_VUN | \
 189       MTAB_NMO | MTAB_VALR,                 /* Mask               */
 190       0,                                    /* Match              */
 191       "CONFIG",                             /* Print string       */
 192       "CONFIG",                             /* Match string       */
 193       set_config,                           /* Validation routine */
 194       show_config,                          /* Display routine    */
 195       NULL,                                 /* Value descriptor   */
 196       NULL                                  /* Help string        */
 197     },
 198 
 199     {
 200       MTAB_XTD | MTAB_VUN | \
 201       MTAB_NMO | MTAB_VALR,                 /* Mask               */
 202       0,                                    /* Match              */
 203       "STATUS",                             /* Print string       */
 204       "STATUS",                             /* Match string       */
 205       NULL,                                 /* Validation routine */
 206       show_status,                          /* Display routine    */
 207       NULL,                                 /* Value descriptor   */
 208       NULL                                  /* Help string        */
 209     },
 210 
 211     {
 212       MTAB_XTD | MTAB_VDV | \
 213       MTAB_NMO | MTAB_VALR,                 /* Mask               */
 214       0,                                    /* Match              */
 215       "NUNITS",                             /* Print string       */
 216       "NUNITS",                             /* Match string       */
 217       set_nunits,                           /* Validation routine */
 218       show_nunits,                          /* Display routine    */
 219       "Number of DIA units in the system",  /* Value descriptor   */
 220       NULL                                  /* Help               */
 221     },
 222     { 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }
 223   };
 224 
 225 UNIT dia_unit [N_DIA_UNITS_MAX] = {
 226     {UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
 227 };
 228 
 229 static DEBTAB dia_DT [] =
 230   {
 231     { "TRACE",  DBG_TRACE,  NULL },
 232     { "NOTIFY", DBG_NOTIFY, NULL },
 233     { "INFO",   DBG_INFO,   NULL },
 234     { "ERR",    DBG_ERR,    NULL },
 235     { "WARN",   DBG_WARN,   NULL },
 236     { "DEBUG",  DBG_DEBUG,  NULL },
 237     { "ALL",    DBG_ALL,    NULL }, // Don't move as it messes up DBG message
 238     { NULL,     0,          NULL }
 239   };
 240 
 241 static t_stat reset (UNUSED DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 242   {
 243     return SCPE_OK;
 244   }
 245 
 246 static t_stat attach (UNIT * uptr, const char * cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 247   {
 248     if (! cptr)
 249       return SCPE_ARG;
 250     int unitno = (int) (uptr - dia_unit);
 251 
 252     // ATTACH DNn llll:w.x.y.z:rrrr - connect via UDP to a remote
 253 
 254     t_stat ret;
 255     char * pfn;
 256 
 257     // If we're already attached, then detach ...
 258     if ((uptr->flags & UNIT_ATT) != 0)
 259       detach_unit (uptr);
 260 
 261     // Make a copy of the "file name" argument.  udp_create() actually modifies
 262     // the string buffer we give it, so we make a copy now so we'll have
 263     // something to display in the "SHOW DNn ..." command.
 264     pfn = (char *) calloc (CBUFSIZE, sizeof (char));
 265     if (pfn == NULL)
 266       return SCPE_MEM;
 267     strncpy (pfn, cptr, CBUFSIZE);
 268 
 269     // Create the UDP connection.
 270     ret = udp_create (cptr, & dia_data.dia_unit_data[unitno].link);
 271     if (ret != SCPE_OK)
 272       {
 273         FREE (pfn);
 274         return ret;
 275       }
 276 
 277     uptr->flags    |= UNIT_ATT;
 278     uptr->filename  = pfn;
 279     return SCPE_OK;
 280   }
 281 
 282 // Detach (connect) ...
 283 static t_stat detach (UNIT * uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 284   {
 285     int unitno = (int) (uptr - dia_unit);
 286     t_stat ret;
 287     if ((uptr->flags & UNIT_ATT) == 0)
 288       return SCPE_OK;
 289     if (dia_data.dia_unit_data[unitno].link == NOLINK)
 290       return SCPE_OK;
 291 
 292     ret = udp_release (dia_data.dia_unit_data[unitno].link);
 293     if (ret != SCPE_OK)
 294       return ret;
 295     dia_data.dia_unit_data[unitno].link = NOLINK;
 296     uptr->flags &= ~ (unsigned int) UNIT_ATT;
 297     FREE (uptr->filename);
 298     uptr->filename = NULL;
 299     return SCPE_OK;
 300   }
 301 
 302 DEVICE dia_dev = {
 303     "DIA",           /* Name                */
 304     dia_unit,        /* Units               */
 305     NULL,            /* Registers           */
 306     dia_mod,         /* Modifiers           */
 307     N_DIA_UNITS,     /* #Units              */
 308     10,              /* Address radix       */
 309     31,              /* Address width       */
 310     1,               /* Address increment   */
 311     8,               /* Data radix          */
 312     9,               /* Data width          */
 313     NULL,            /* Examine routine     */
 314     NULL,            /* Deposit routine     */
 315     reset,           /* Reset routine       */
 316     NULL,            /* Boot routine        */
 317     attach,          /* Attach routine      */
 318     detach,          /* Detach routine      */
 319     NULL,            /* Context             */
 320     DEV_DEBUG,       /* Flags               */
 321     0,               /* Debug control flags */
 322     dia_DT,          /* Debug flag names    */
 323     NULL,            /* Memory size change  */
 324     NULL,            /* Logical name        */
 325     NULL,            /* Attach help         */
 326     NULL,            /* Help                */
 327     NULL,            /* Help context        */
 328     NULL,            /* Device description  */
 329     NULL
 330 };
 331 
 332 t_dia_data dia_data;
 333 
 334 struct dn355_submailbox
 335   {
 336     word36 word1;            // dn355_no; is_hsla; la_no; slot_no
 337     word36 word2;            // cmd_data_len; op_code; io_cmd
 338     word36 command_data [3];
 339     word36 word6;            // data_addr, word_cnt;
 340     word36 pad3 [2];
 341   };
 342 
 343 struct fnp_submailbox // 28 words
 344   {
 345                                                                  // AN85
 346     word36 word1; // dn355_no; is_hsla; la_no; slot_no    // 0      word0
 347     word36 word2; // cmd_data_len; op_code; io_cmd        // 1      word1
 348     word36 mystery [26];                                         // word2...
 349   };
 350 
 351 struct mailbox
 352   {
 353     word36 dia_pcw;
 354     word36 mailbox_requests;
 355     word36 term_inpt_mpx_wd;
 356     word36 last_mbx_req_count;
 357     word36 num_in_use;
 358     word36 mbx_used_flags;
 359     word36 crash_data [2];
 360     struct dn355_submailbox dn355_sub_mbxes [8];
 361     struct fnp_submailbox fnp_sub_mbxes [4];
 362   };
 363 
 364 #define MAILBOX_WORDS (sizeof (struct mailbox) / sizeof (word36))
 365 #define TERM_INPT_MPX_WD (offsetof (struct mailbox, term_inpt_mpx_wd) / sizeof (word36))
 366 
 367 //
 368 // Once-only initialization
 369 //
 370 
 371 void dia_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 372   {
 373     // 0 sets set service to service_undefined
 374     (void)memset(& dia_data, 0, sizeof(dia_data));
 375     for (uint unit_num = 0; unit_num < N_DIA_UNITS_MAX; unit_num ++)
 376       {
 377         cables -> cables_from_iom_to_dia [unit_num].iomUnitIdx = -1;
 378         dia_data.dia_unit_data[unit_num].link = -1;
 379       }
 380   }
 381 
 382 static inline void fnp_core_write (word24 addr, word36 data, UNUSED const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
 383   {
 384 #if defined(THREADZ)
 385     lock_mem_wr ();
 386 #endif /* if defined(THREADZ) */
 387     M [addr] = data & DMASK;
 388 #if defined(THREADZ)
 389     unlock_mem ();
 390 #endif /* if defined(THREADZ) */
 391     cachePurgeAll (addr);
 392   }
 393 
 394 //
 395 // Convert virtual address to physical
 396 //
 397 
 398 static uint virtToPhys (uint ptPtr, uint l66Address)
     /* [previous][next][first][last][top][bottom][index][help] */
 399   {
 400     uint pageTable      = ptPtr * 64u;
 401     uint l66AddressPage = l66Address / 1024u;
 402 
 403     word36 ptw;
 404     fnp_core_read (pageTable + l66AddressPage, & ptw, "fnpIOMCmd get ptw");
 405     uint page = getbits36_14 (ptw, 4);
 406     uint addr = page * 1024u + l66Address % 1024u;
 407     return addr;
 408   }
 409 
 410 //
 411 // udp packets
 412 //
 413 //   pkt[0] = cmd
 414 //     cmd 1 - bootload
 415 //
 416 
 417 static void cmd_bootload (uint iom_unit_idx, uint dev_unit_idx, uint chan, word24 l66_addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 418   {
 419     uint fnpno = dev_unit_idx; // XXX
 420     //iom_chan_data_t * p       = & iom_chan_data [iom_unit_idx] [chan];
 421     struct dia_unit_data * dudp = & dia_data.dia_unit_data[fnpno];
 422     struct mailbox vol * mbxp   = (struct mailbox vol *) & M[dudp->mailbox_address];
 423 
 424     dia_data.dia_unit_data[dev_unit_idx].l66_addr = l66_addr;
 425 
 426     dn_bootload pkt;
 427     pkt.cmd = dn_cmd_bootload;
 428     //pkt.dia_pcw = mbxp->dia_pcw;
 429 
 430     sim_printf ("XXXXXXXXXXXXXXXXXXXXXXXXXXX cmd_bootload\r\n");
 431     int rc = dn_udp_send (dia_data.dia_unit_data[dev_unit_idx].link,
 432                           (uint8_t *) & pkt,
 433                           (uint16_t) sizeof (pkt), PFLG_FINAL);
 434     if (rc < 0)
 435       {
 436         (void)fprintf (stderr, "udp_send failed\r\n");
 437       }
 438   }
 439 
 440 static int interruptL66 (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 441   {
 442     iom_chan_data_t * p         = & iom_chan_data[iom_unit_idx][chan];
 443     struct device * d           = & cables->cablesFromIomToDev[iom_unit_idx].
 444       devices[chan][p->IDCW_DEV_CODE];
 445     uint dev_unit_idx           = d->devUnitIdx;
 446     struct dia_unit_data * dudp = &dia_data.dia_unit_data[dev_unit_idx];
 447     struct mailbox vol * mbxp   = (struct mailbox vol *) & M[dudp->mailbox_address];
 448     word36 dia_pcw              = mbxp -> dia_pcw;
 449 
 450 // AN85, pg 13-5
 451 // When the CS has control information or output data to send
 452 // to the FNP, it fills in a submailbox as described in Section 4
 453 // and sends an interrupt over the DIA. This interrupt is handled
 454 // by dail as described above; when the submailbox is read, the
 455 // transaction control word is set to "submailbox read" so that when
 456 // the I/O completes and dtrans runs, the mailbox decoder (decmbx)
 457 // is called. the I/O command in the submail box is either WCD (for
 458 // control information) or WTX (for output data). If it is WCD,
 459 // decmbx dispatches according to a table of operation codes and
 460 // setting a flag in the IB and calling itest, the "test-state"
 461 // entry of the interpreter. n a few cases, the operation requires
 462 // further DIA I/O, but usually all that remains to be does is to
 463 // "free" the submailbox by turning on the corresponding bit in the
 464 // mailbox terminate interrupt multiplex word (see Section 4) and
 465 // set the transaction control word accordingly. When the I/O to
 466 // update TIMW terminates, the transaction is complete.
 467 //
 468 // If the I/O command is WTX, the submailbox contains the
 469 // address and length of a 'pseudo-DCW" list containing the
 470 // addresses and tallies of data buffers in tty_buf. In this case,
 471 // dia_man connects to a DCW list to read them into a reserved area
 472 // in dia_man. ...
 473 
 474 // interrupt level (in "cell"):
 475 //
 476 // mbxs 0-7 are CS -> FNP
 477 // mbxs 8--11 are FNP -> CS
 478 //
 479 //   0-7 Multics has placed a message for the FNP in mbx 0-7.
 480 //   8-11 Multics has updated mbx 8-11
 481 //   12-15 Multics is done with mbx 8-11  (n - 4).
 482 
 483     word6 cell = getbits36_6 (dia_pcw, 24);
 484     sim_debug (DBG_TRACE, & dia_dev, "CS interrupt %u\r\n", cell);
 485     if (cell < 8)
 486       {
 487         //interruptL66_CS_to_FNP ();
 488       }
 489     else if (cell >= 8 && cell <= 11)
 490       {
 491         //interruptL66_FNP_to_CS ();
 492       }
 493     else if (cell >= 12 && cell <= 15)
 494       {
 495         //interruptL66_CS_done ();
 496       }
 497     else
 498       {
 499         sim_debug (DBG_ERR, & dia_dev, "fnp illegal cell number %d\r\n", cell);
 500         sim_printf ("fnp illegal cell number %d\r\n", cell);
 501         // doFNPfault (...) // XXX
 502         return -1;
 503       }
 504     return 0;
 505   }
 506 
 507 static void processMBX (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 508   {
 509     iom_chan_data_t * p         = & iom_chan_data[iom_unit_idx][chan];
 510     struct device * d           = & cables->cablesFromIomToDev[iom_unit_idx].
 511       devices[chan][p->IDCW_DEV_CODE];
 512     uint dev_unit_idx           = d->devUnitIdx;
 513     struct dia_unit_data * dudp = &dia_data.dia_unit_data[dev_unit_idx];
 514 
 515 // 60132445 FEP Coupler EPS
 516 // 2.2.1 Control Intercommunication
 517 //
 518 // "In Level 66 memory, at a location known to the coupler and
 519 // to Level 6 software is a mailbox area consisting to an Overhead
 520 // mailbox and 7 Channel mailboxes."
 521 
 522     bool ok = true;
 523     struct mailbox vol * mbxp = (struct mailbox vol *) & M [dudp -> mailbox_address];
 524 
 525     word36 dia_pcw;
 526     dia_pcw = mbxp -> dia_pcw;
 527 //sim_printf ("mbx %08o:%012"PRIo64"\r\n", dudp -> mailbox_address, dia_pcw);
 528 
 529 // Mailbox word 0:
 530 //
 531 //   0-17 A
 532 //     18 I
 533 //  19-20 MBZ
 534 //  21-22 RFU
 535 //     23 0
 536 //  24-26 B
 537 //  27-29 D Channel #
 538 //  30-35 C Command
 539 //
 540 //                          A6-A23    A0-A2     A3-A5
 541 // Operation          C         A        B        D
 542 // Interrupt L6      071       ---      Int.     Level
 543 // Bootload L6       072    L66 Addr  L66 Addr  L66 Addr
 544 //                           A6-A23    A0-A2     A3-A5
 545 // Interrupt L66     073      ---      ---     Intr Cell
 546 // Data Xfer to L66  075    L66 Addr  L66 Addr  L66 Addr
 547 //                           A6-A23    A0-A2     A3-A5
 548 // Data Xfer to L6   076    L66 Addr  L66 Addr  L66 Addr
 549 //                           A6-A23    A0-A2     A3-A5
 550 
 551 //
 552 // fnp_util.pl1:
 553 //    075 tandd read
 554 //    076 tandd write
 555 
 556 // mbx word 1: mailbox_requests fixed bin
 557 //          2: term_inpt_mpx_wd bit (36) aligned
 558 //          3: last_mbx_req_count fixed bin
 559 //          4: num_in_use fixed bin
 560 //          5: mbx_used_flags
 561 //                used (0:7) bit (1) unaligned
 562 //                pad2 bit (28) unaligned
 563 //          6,7: crash_data
 564 //                fault_code fixed bin (18) unal unsigned
 565 //                ic fixed bin (18) unal unsigned
 566 //                iom_fault_status fixed bin (18) unal unsigned
 567 //                fault_word fixed bin (18) unal unsigned
 568 //
 569 //    crash_data according to dn355_boot_interrupt.pl1:
 570 //
 571 //   dcl  1 fnp_boot_status aligned based (stat_ptr),            /* structure of bootload status */
 572 //          2 real_status bit (1) unaligned,                     /* must be "1"b in valid status */
 573 //          2 pad1 bit (2) unaligned,
 574 //          2 major_status bit (3) unaligned,
 575 //          2 pad2 bit (3) unaligned,
 576 //          2 substatus fixed bin (8) unal,                      /* code set by 355, only interesting if major_status is 4 */
 577 //          2 channel_no fixed bin (17) unaligned;               /* channel no. of LSLA in case of config error */
 578 //    only 34 bits???
 579 // major_status:
 580 //  dcl  BOOTLOAD_OK fixed bin int static options (constant) init (0);
 581 //  dcl  CHECKSUM_ERROR fixed bin int static options (constant) init (1);
 582 //  dcl  READ_ERROR fixed bin int static options (constant) init (2);
 583 //  dcl  GICB_ERROR fixed bin int static options (constant) init (3);
 584 //  dcl  INIT_ERROR fixed bin int static options (constant) init (4);
 585 //  dcl  UNWIRE_STATUS fixed bin int static options (constant) init (5);
 586 //  dcl  MAX_STATUS fixed bin int static options (constant) init (5);
 587 
 588 // 3.5.1 Commands Issued by Central System
 589 //
 590 // In the issuing of an order by the Central System to the Coupler, the
 591 // sequence occurs:
 592 //
 593 // 1. The L66 program creates a LPW and Pcw for the Central System Connect
 594 // channel. It also generates and stores a control word containing a command
 595 // in the L66 mailbox. A Connect is then issued to the L66 IOM.
 596 //
 597 // 2. The Connect Channel accesses the PCW to get the channel number of
 598 // the Direct Channel that the coupler is attached to. the direct Channel
 599 // sends a signal to the Coupler that a Connect has been issued.
 600 //
 601 // 3. The Coupler now reads the content of the L66 mailbox, obtaining the
 602 // control word. If the control word is legal, the Coupler will write a
 603 // word of all zeros into the mailbox.
 604 //
 605 
 606 // 4.1.1.2 Transfer Control Word.
 607 // The transfer control word, which is pointed to by the
 608 // mailbox word in l66 memory on Op Codes 72, 7, 76 contains
 609 // a starting address which applies to L6 memory an a Tally
 610 // of the number of 36 bit words to be transferred. The l66
 611 // memory locations to/from which the transfers occur are
 612 // those immediately following the location where this word
 613 // was obtained.
 614 //
 615 //    00-02  001
 616 //    03-17 L6 Address
 617 //       18 P
 618 //    19-23 MBZ
 619 //    24-25 Tally
 620 //
 621 //     if P = 0 the l6 address:
 622 //        00-07 00000000
 623 //        08-22 L6 address (bits 3-17)
 624 //           23 0
 625 //     if P = 1
 626 //        00-14 L6 address (bits 3-17)
 627 //        15-23 0
 628 //
 629 
 630     //uint chanNum = getbits36_6 (dia_pcw, 24);
 631     uint command          = getbits36_6 (dia_pcw, 30);
 632     word36 bootloadStatus = 0;
 633 
 634     if (command == 000) // reset
 635       {
 636           sim_debug (DBG_TRACE, & dia_dev, "FNP reset??\r\n");
 637       }
 638     else if (command == 072) // bootload
 639       {
 640         // 60132445 pg 49
 641         // Extract L66 address from dia_pcw
 642 
 643 // According to 60132445:
 644         //word24 A = (word24) getbits36_18 (dia_pcw,  0);
 645         //word24 B = (word24) getbits36_3  (dia_pcw, 24);
 646         //word24 D = (word24) getbits36_3  (dia_pcw, 29);
 647         //word24 l66_addr = (B << (24 - 3)) | (D << (24 - 3 - 3)) | A;
 648 // According to fnp_util.pl1:
 649 //     dcl  1 a_dia_pcw aligned based (mbxp),    /* better declaration than the one used when MCS is running */
 650 //            2 address fixed bin (18) unsigned unaligned,
 651         word24 l66_addr = (word24) getbits36_18 (dia_pcw,  0);
 652 sim_printf ("l66_addr %08o\r\n", l66_addr);
 653 
 654         uint phys_addr = virtToPhys (p->PCW_PAGE_TABLE_PTR, l66_addr);
 655 sim_printf ("phys_addr %08o\r\n", phys_addr);
 656 
 657         word36 tcw;
 658         fnp_core_read (phys_addr, & tcw, "tcw fetch");
 659 
 660 // Got 100000000517 as expected
 661 //sim_printf ("tcw %012llo\r\n", tcw);
 662 
 663         //word36 tcw1;
 664         //fnp_core_read (phys_addr + 1, & tcw1, "tcw fetch");
 665 
 666 // Got 100002060002, as expected (first word of gicb)
 667 //sim_printf ("tcw1 %012llo\r\n", tcw1);
 668 
 669         // pg 50 4.1.1.2 Transfer control word
 670         // "The transfer control word, which is pointed to by the
 671         // mailbox word in L66 memory on Op Codes 72, 75, 76 contains
 672         // a starting address which applies to L6 memory and a Tally
 673         // of the number of 36 bit words to be transferred. The L66
 674         // memory locations to/from which the transfers occur are
 675         // those immediately following the location where this word
 676         // was obtained.
 677         //
 678         // 0-2: 001
 679         // 3-17: L6 Address
 680         // 18: P
 681         // 19-23: MBZ
 682         // 24-36: Tally
 683         //
 684         // The L6 Address field is interpreted as an effective L6 byte
 685         // address as follows:
 686         //
 687         // If P = 0
 688         //
 689         // 0-7: 00000000
 690         // 8-22: L6 Address field (bits 3-17)
 691         // 23: 0
 692         //
 693         // If P = 1
 694         //
 695         // 0-14: L6 Address field (bits 3-17)
 696         // 15-22: 0000000
 697         // 23: 0
 698 
 699         cmd_bootload (iom_unit_idx, dev_unit_idx, chan, l66_addr);
 700 
 701 // My understanding is that the FNP shouldn't clear the MBX PCW until
 702 // the bootload is complete; but the timeout in fnp_util$connect_to_dia_paged
 703 // is short:
 704 //   do i = 1 to 100000 while (unspec (a_dia_pcw) = old_pcw);
 705 // I am going ahead and acking, but it is unclear to me what the mechanism,
 706 // if any, is for FNP signaling completed successful bootload.
 707 
 708         // Don't acknowledge the boot yet.
 709         //dudp -> fnpIsRunning = true;
 710         //return;
 711       }
 712     else if (command == 071) // interrupt L6
 713       {
 714         ok = interruptL66 (iom_unit_idx, chan) == 0;
 715       }
 716     else if (command == 075) // data xfer from L6 to L66
 717       {
 718         // Build the L66 address from the PCW
 719         //   0-17 A
 720         //  24-26 B
 721         //  27-29 D Channel #
 722         // Operation          C         A        B        D
 723         // Data Xfer to L66  075    L66 Addr  L66 Addr  L66 Addr
 724         //                           A6-A23    A0-A2     A3-A5
 725         // These don't seem to be right; M[L66Add] is always 0.
 726         //word24 A = (word24) getbits36_18 (dia_pcw,  0);
 727         //word24 B = (word24) getbits36_3  (dia_pcw, 24);
 728         //word24 D = (word24) getbits36_3  (dia_pcw, 29);
 729         //word24 L66Addr = (B << (24 - 3)) | (D << (24 - 3 - 3)) | A;
 730 
 731         // According to fnp_util:
 732         //                      /* better declaration than the one used when MCS is running */
 733         //  dcl  1 a_dia_pcw aligned based (mbxp),
 734         //         2 address fixed bin (18) unsigned unaligned,
 735         //         2 error bit (1) unaligned,
 736         //         2 pad1 bit (3) unaligned,
 737         //         2 parity bit (1) unaligned,
 738         //         2 pad2 bit (1) unaligned,
 739         //                            /* if we used address extension this would be important */
 740         //         2 pad3 bit (3) unaligned,
 741         //         2 interrupt_level fixed bin (3) unsigned unaligned,
 742         //         2 command bit (6) unaligned;
 743         //
 744         //   a_dia_pcw.address = address;
 745         //
 746 
 747         //word24 L66Addr = (word24) getbits36_18 (dia_pcw, 0);
 748         //sim_printf ("L66 xfer\r\n");
 749         //sim_printf ("PCW  %012"PRIo64"\r\n", dia_pcw);
 750         //sim_printf ("L66Addr %08o\r\n", L66Addr);
 751         //sim_printf ("M[] %012"PRIo64"\r\n", M[L66Addr]);
 752 
 753         // 'dump_mpx d'
 754         //L66 xfer
 755         //PCW  022002000075
 756         //L66Addr 00022002
 757         //M[] 000000401775
 758         //L66 xfer
 759         //PCW  022002000075
 760         //L66Addr 00022002
 761         //M[] 003772401775
 762         //L66 xfer
 763         //PCW  022002000075
 764         //L66Addr 00022002
 765         //M[] 007764401775
 766         //
 767         // The contents of M seem much more reasonable, bit still don't match
 768         // fnp_util$setup_dump_ctl_word. The left octet should be '1', not '0';
 769         // bit 18 should be 0 not 1. But the offsets and tallies match exactly.
 770         // Huh... Looking at 'dump_6670_control' control instead, it matches
 771         // correctly. Apparently fnp_util thinks the FNP is a 6670, not a 335.
 772         // I can't decipher the call path, so I don't know why; but looking at
 773         // multiplexer_types.incl.pl1, I would guess that by MR12.x, all FNPs
 774         // were 6670s.
 775         //
 776         // So:
 777         //
 778         //   dcl  1 dump_6670_control aligned based (data_ptr),
 779         //         /* word used to supply DIA address and tally for fdump */
 780         //          2 fnp_address fixed bin (18) unsigned unaligned,
 781         //          2 unpaged bit (1) unaligned,
 782         //          2 mbz bit (5) unaligned,
 783         //          2 tally fixed bin (12) unsigned unaligned;
 784 
 785         // Since the data is marked 'paged', and I don't understand the
 786         // the paging mechanism or parameters, I'm going to punt here and
 787         // not actually transfer any data.
 788         sim_debug (DBG_TRACE, & dia_dev, "FNP data xfer??\r\n");
 789       }
 790     else
 791       {
 792         sim_warn ("bogus fnp command %d (%o)\r\n", command, command);
 793         ok = false;
 794       }
 795 
 796     if (ok)
 797       {
 798         //if_sim_debug (DBG_TRACE, & fnp_dev) dmpmbx (dudp->mailbox_address);
 799         fnp_core_write (dudp -> mailbox_address,  0, "dia_iom_cmd clear dia_pcw");
 800         putbits36_1    (& bootloadStatus,  0, 1);    // real_status = 1
 801         putbits36_3    (& bootloadStatus,  3, 0);    // major_status = BOOTLOAD_OK;
 802         putbits36_8    (& bootloadStatus,  9, 0);    // substatus = BOOTLOAD_OK;
 803         putbits36_17   (& bootloadStatus, 17, 0);    // channel_no = 0;
 804         fnp_core_write (dudp -> mailbox_address + 6, bootloadStatus,
 805                 "dia_iom_cmd set bootload status");
 806       }
 807     else
 808       {
 809         //dmpmbx (dudp->mailbox_address);
 810         sim_printf ("%s not ok\r\n", __func__);
 811 // 3 error bit (1) unaligned, /* set to "1"b if error on connect */
 812         putbits36_1 (& dia_pcw, 18, 1); // set bit 18
 813         fnp_core_write (dudp -> mailbox_address, dia_pcw, "dia_iom_cmd set error bit");
 814       }
 815   }
 816 
 817 static int dia_cmd (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 818   {
 819     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
 820     p -> stati = 0;
 821 //sim_printf ("fnp cmd %d\r\n", p -> IDCW_DEV_CMD);
 822     switch (p -> IDCW_DEV_CMD)
 823       {
 824         case 000: // CMD 00 Request status
 825           {
 826             p -> stati = 04000;
 827             sim_debug (DBG_NOTIFY, & dia_dev, "Request status\r\n");
 828           }
 829           break;
 830 
 831         default:
 832           {
 833             p -> stati      = 04501;
 834             p -> chanStatus = chanStatIncorrectDCW;
 835             if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
 836               sim_warn ("dia daze %o\r\n", p->IDCW_DEV_CMD);
 837           }
 838           return IOM_CMD_ERROR;
 839       }
 840 
 841     processMBX (iom_unit_idx, chan);
 842 
 843     return IOM_CMD_NO_DCW; // did command, don't want more
 844   }
 845 
 846 /*
 847  * dia_iom_cmd()
 848  *
 849  */
 850 
 851 // 1 ignored command
 852 // 0 ok
 853 // -1 problem
 854 
 855 int dia_iom_cmd (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 856   {
 857 sim_printf ("dia_iom_cmd %u %u\r\n", iom_unit_idx, chan);
 858     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
 859 // Is it an IDCW?
 860 
 861     if (IS_IDCW (p))
 862       {
 863         return dia_cmd (iom_unit_idx, chan);
 864       }
 865     // else // DDCW/TDCW
 866     sim_printf ("%s expected IDCW\r\n", __func__);
 867     return -1;
 868   }
 869 
 870 static void load_stored_boot (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 871   {
 872     // pg 45:
 873 
 874     //  3.8 BOOTLOAD OF L6 BY L66
 875     //...
 876     // The receipt of the Input Stored Boot order causes the coupler,
 877     // if the Stored Boot but is ONE, to input data into L6 memory as
 878     // specified by the L66 Bootload order. On completion of this,
 879     // the Stored Boot bit is cleared.
 880     //
 881     // ... the PROM program issues the Input Stored Boot IOLD order
 882     // to the coupler..
 883     //
 884     // ... the L66 Bootload command specifies the L6 memory locations into
 885     // which the load from L66 is to occur and the extent of the lod;
 886     // location (0100)16 in L6 would always be the first location to be
 887     // executed by L6 after the load from L66 assuming that the L66
 888     // bootload is independent of the mechanization used in L66
 889 
 890     sim_printf ("got load_stored_boot\r\n");
 891   }
 892 
 893 #define psz 17000
 894 static uint8_t pkt[psz];
 895 
 896 // warning: returns ptr to static buffer
 897 static int poll_coupler (uint unitno, uint8_t * * pktp)
     /* [previous][next][first][last][top][bottom][index][help] */
 898   {
 899     int sz = dn_udp_receive (dia_data.dia_unit_data[unitno].link, pkt, psz);
 900     if (sz < 0)
 901       {
 902         sim_printf ("dn_udp_receive failed: %d\r\n", sz);
 903         sz = 0;
 904       }
 905     * pktp = pkt;
 906     return sz;
 907   }
 908 
 909 void dia_unit_process_events (uint unit_num)
     /* [previous][next][first][last][top][bottom][index][help] */
 910   {
 911 // XXX remember
 912 // XXX        //dudp -> fnpIsRunning = true;
 913 // XXX when bootload complete!
 914 
 915     uint8_t * pktp;
 916     int sz = poll_coupler (unit_num, & pktp);
 917 //sim_printf ("poll_coupler return %d\r\n", sz);
 918     if (! sz)
 919       {
 920         return;
 921       }
 922 
 923    uint8_t cmd = pktp [0];
 924    switch (cmd)
 925      {
 926        // IO Load Stored Boot
 927        case dn_cmd_ISB_IOLD:
 928          {
 929            load_stored_boot ();
 930            break;
 931          }
 932 
 933        default:
 934          {
 935            sim_printf ("%s got unhandled cmd %u\r\n", __func__, cmd);
 936            break;
 937          }
 938      }
 939   }
 940 
 941 void dia_process_events (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 942   {
 943     for (uint unit_num = 0; unit_num < N_DIA_UNITS_MAX; unit_num ++)
 944       {
 945          if (dia_data.dia_unit_data[unit_num].link >= 0)
 946            dia_unit_process_events (unit_num);
 947       }
 948   }

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