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

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