This source file includes following definitions.
- parseval
 
- getval
 
- name_match
 
- back_cable_iom_to_scu
 
- cable_scu_to_iom
 
- back_cable_cpu_to_scu
 
- cable_scu_to_cpu
 
- cable_scu
 
- cable_ctlr_to_iom
 
- cable_ctlr
 
- cable_iom
 
- cable_periph_to_ctlr
 
- cable_periph
 
- cable_mtp
 
- cable_ipc
 
- cable_msp
 
- cable_urp
 
- sys_cable
 
- cable_init
 
- sys_cable_graph
 
- sys_cable_show
 
- sys_cable_ripout
 
- sysCableInit
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 
  45 
  46 
  47 
  48 
  49 
  50 
  51 
  52 
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 
  62 
  63 
  64 
  65 
  66 
  67 
  68 
  69 
  70 
  71 
  72 
  73 
  74 
  75 
  76 
  77 
  78 
  79 
  80 
  81 
  82 
  83 
  84 
  85 
  86 
  87 
  88 
  89 
  90 
  91 
  92 
  93 
  94 
  95 
  96 
  97 
  98 
  99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 #include <ctype.h>
 109 
 110 #include "dps8.h"
 111 #include "dps8_simh.h"
 112 #include "dps8_iom.h"
 113 #include "dps8_mt.h"
 114 #include "dps8_socket_dev.h"
 115 #include "dps8_sys.h"
 116 #include "dps8_cable.h"
 117 #include "dps8_cpu.h"
 118 #include "dps8_faults.h"
 119 #include "dps8_scu.h"
 120 #include "dps8_state.h"
 121 #include "dps8_console.h"
 122 #include "dps8_disk.h"
 123 #include "dps8_fnp2.h"
 124 #include "dps8_urp.h"
 125 #include "dps8_crdrdr.h"
 126 #include "dps8_crdpun.h"
 127 #include "dps8_prt.h"
 128 #include "dps8_utils.h"
 129 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined (CROSS_MINGW64) && !defined (CROSS_MINGW32)
 130 # include "dps8_absi.h"
 131 # include "dps8_mgp.h"
 132 #endif 
 133 #if defined(M_SHARED)
 134 # include <unistd.h>
 135 # include "shm.h"
 136 #endif
 137 
 138 #define DBG_CTR 1
 139 
 140 #if defined(FREE)
 141 # undef FREE
 142 #endif 
 143 #define FREE(p) do  \
 144   {                 \
 145     free((p));      \
 146     (p) = NULL;     \
 147   } while(0)
 148 
 149 struct cables_s * cables = NULL;
 150 
 151 char * ctlr_type_strs [] =
 152   {
 153     "none",
 154      "MTP", "MSP", "IPC", "OPC",
 155      "URP", "FNP", "ABSI", "SKC", "MGP"
 156   };
 157 
 158 char * chan_type_strs [] =
 159   {
 160     "CPI", "PSI", "Direct"
 161   };
 162 
 163 static t_stat sys_cable_graph (void);
 164 
 165 static int parseval (char * value)
     
 166   {
 167     if (! value)
 168       return -1;
 169     if (strlen (value) == 1 && value[0] >= 'a' && value[0] <= 'z')
 170       return (int) (value[0] - 'a');
 171     if (strlen (value) == 1 && value[0] >= 'A' && value[0] <= 'Z')
 172       return (int) (value[0] - 'A');
 173     char * endptr;
 174     long l = strtol (value, & endptr, 0);
 175     if (* endptr || l < 0 || l > INT_MAX)
 176       {
 177         sim_printf ("error: CABLE: can't parse %s\r\n", value);
 178         return -1;
 179       }
 180     return (int) l;
 181   }
 182 
 183 static int getval (char * * save, char * text)
     
 184   {
 185     char * value;
 186     value = strtok_r (NULL, ", ", save);
 187     if (! value)
 188       {
 189         sim_printf ("error: CABLE: can't parse %s\r\n", text);
 190         return -1;
 191       }
 192     return parseval (value);
 193   }
 194 
 195 
 196 
 197 
 198 
 199 
 200 static bool name_match (const char * str, const char * pattern, uint * val)
     
 201   {
 202     
 203     size_t pat_len = strlen (pattern);
 204     if (strncasecmp (pattern, str, pat_len))
 205       return false;
 206 
 207     
 208     size_t rest = strlen (str) - pat_len;
 209     const char * p = str + pat_len;
 210 
 211     
 212     if (! rest)
 213       return false; 
 214 
 215     
 216     char * q;
 217     char * tags = "abcdefghijklmnopqrstuvwxyz";
 218     if (rest == 1 && (q = strchr (tags, tolower (*p))))
 219       {
 220         * val = (uint) (q - tags);
 221         return true;
 222       }
 223 
 224     
 225     char * digits = "0123456789";
 226     q = strchr (digits, tolower (*p));
 227     if (! q)
 228       return false; 
 229 
 230     long l = strtol (p, & q, 0);
 231     if (* q || l < 0 || l > INT_MAX)
 232       {
 233         sim_printf ("error: sys_cable: can't parse %s\r\n", str);
 234         return false;
 235       }
 236     * val =  (uint) l;
 237     return true;
 238   }
 239 
 240 
 241 
 242 static t_stat back_cable_iom_to_scu (int uncable, uint iom_unit_idx, uint iom_port_num, uint scu_unit_idx, uint scu_port_num)
     
 243   {
 244     struct iom_to_scu_s * p = & cables->iom_to_scu[iom_unit_idx][iom_port_num];
 245     if (uncable)
 246       {
 247         p->in_use = false;
 248       }
 249     else
 250       {
 251         if (p->in_use)
 252           {
 253             sim_printf ("cable SCU: IOM%u port %u in use.\r\n", iom_unit_idx, iom_port_num);
 254              return SCPE_ARG;
 255           }
 256         p->in_use = true;
 257         p->scu_unit_idx = scu_unit_idx;
 258         p->scu_port_num = scu_port_num;
 259       }
 260     return SCPE_OK;
 261   }
 262 
 263 
 264 
 265 static t_stat cable_scu_to_iom (int uncable, uint scu_unit_idx, uint scu_port_num, uint iom_unit_idx, uint iom_port_num)
     
 266   {
 267     struct scu_to_iom_s * p = & cables->scu_to_iom[scu_unit_idx][scu_port_num];
 268     if (uncable)
 269       {
 270         if (! p->in_use)
 271           {
 272             sim_printf ("uncable SCU%u port %d: not cabled\r\n", scu_unit_idx, scu_port_num);
 273             return SCPE_ARG;
 274           }
 275 
 276         
 277         t_stat rc = back_cable_iom_to_scu (uncable, iom_unit_idx, iom_port_num,
 278                                   scu_unit_idx, scu_port_num);
 279         if (rc)
 280           {
 281             return rc;
 282           }
 283 
 284         p->in_use = false;
 285         scu[scu_unit_idx].ports[scu_port_num].type    = ADEV_NONE;
 286         scu[scu_unit_idx].ports[scu_port_num].dev_idx = 0;
 287         
 288         scu[scu_unit_idx].ports[scu_port_num].is_exp  = false;
 289         
 290       }
 291     else
 292       {
 293         if (p->in_use)
 294           {
 295             sim_printf ("cable_scu: SCU %d port %d in use.\r\n", scu_unit_idx, scu_port_num);
 296             return SCPE_ARG;
 297           }
 298 
 299         
 300         t_stat rc = back_cable_iom_to_scu (uncable, iom_unit_idx, iom_port_num,
 301                                   scu_unit_idx, scu_port_num);
 302         if (rc)
 303           {
 304             return rc;
 305           }
 306 
 307         p->in_use = true;
 308         p->iom_unit_idx = iom_unit_idx;
 309         p->iom_port_num = (uint) iom_port_num;
 310 
 311         scu[scu_unit_idx].ports[scu_port_num].type        = ADEV_IOM;
 312         scu[scu_unit_idx].ports[scu_port_num].dev_idx     = (int) iom_unit_idx;
 313         scu[scu_unit_idx].ports[scu_port_num].dev_port[0] = (int) iom_port_num;
 314         
 315         scu[scu_unit_idx].ports[scu_port_num].is_exp      = 0;
 316         
 317       }
 318     return SCPE_OK;
 319   }
 320 
 321 
 322 
 323 static t_stat back_cable_cpu_to_scu (int uncable, uint cpu_unit_idx, uint cpu_port_num,
     
 324         uint scu_unit_idx, uint scu_port_num, uint scu_subport_num)
 325   {
 326     struct cpu_to_scu_s * p = & cables->cpu_to_scu[cpu_unit_idx][cpu_port_num];
 327     if (uncable)
 328       {
 329         p->in_use = false;
 330       }
 331     else
 332       {
 333         if (p->in_use)
 334           {
 335             sim_printf ("cable SCU: CPU%u port %u in use.\r\n", cpu_unit_idx, cpu_port_num);
 336              return SCPE_ARG;
 337           }
 338         p->in_use = true;
 339         p->scu_unit_idx    = scu_unit_idx;
 340         p->scu_port_num    = scu_port_num;
 341         p->scu_subport_num = scu_subport_num;
 342       }
 343     return SCPE_OK;
 344   }
 345 
 346 
 347 
 348 static t_stat cable_scu_to_cpu (int uncable, uint scu_unit_idx, uint scu_port_num,
     
 349         uint scu_subport_num, uint cpu_unit_idx, uint cpu_port_num, bool is_exp)
 350   {
 351     struct scu_to_cpu_s * p = & cables->scu_to_cpu[scu_unit_idx][scu_port_num][scu_subport_num];
 352     if (uncable)
 353       {
 354         if (! p->in_use)
 355           {
 356             sim_printf ("uncable SCU%u port %u subport %u: not cabled\r\n",
 357                     scu_unit_idx, scu_port_num, scu_subport_num);
 358             return SCPE_ARG;
 359           }
 360 
 361         
 362         t_stat rc = back_cable_cpu_to_scu (uncable, cpu_unit_idx, cpu_port_num,
 363                                   scu_unit_idx, scu_port_num, scu_subport_num);
 364         if (rc)
 365           {
 366             return rc;
 367           }
 368 
 369         p->in_use = false;
 370         scu[scu_unit_idx].ports[scu_port_num].type                      = ADEV_NONE;
 371         scu[scu_unit_idx].ports[scu_port_num].dev_idx                   = 0;
 372         
 373         scu[scu_unit_idx].ports[scu_port_num].is_exp                    = false;
 374         scu[scu_unit_idx].ports[scu_port_num].dev_port[scu_subport_num] = 0;
 375       }
 376     else
 377       {
 378         if (p->in_use)
 379           {
 380             sim_printf ("cable_scu: SCU %u port %u subport %u in use.\r\n",
 381                     scu_unit_idx, scu_port_num, scu_subport_num);
 382             return SCPE_ARG;
 383           }
 384 
 385         
 386         t_stat rc = back_cable_cpu_to_scu (uncable, cpu_unit_idx, cpu_port_num,
 387                                   scu_unit_idx, scu_port_num, scu_subport_num);
 388         if (rc)
 389           {
 390             return rc;
 391           }
 392 
 393         p->in_use = true;
 394         p->cpu_unit_idx = cpu_unit_idx;
 395         p->cpu_port_num = (uint) cpu_port_num;
 396 
 397         scu[scu_unit_idx].ports[scu_port_num].type                      = ADEV_CPU;
 398         scu[scu_unit_idx].ports[scu_port_num].dev_idx                   = (int) cpu_unit_idx;
 399         scu[scu_unit_idx].ports[scu_port_num].dev_port[0]               = (int) cpu_port_num;
 400         
 401         scu[scu_unit_idx].ports[scu_port_num].is_exp                    = is_exp;
 402         scu[scu_unit_idx].ports[scu_port_num].dev_port[scu_subport_num] = (int) cpu_port_num;
 403 
 404         cpus[cpu_unit_idx].scu_port[scu_unit_idx]                       = scu_port_num;
 405       }
 406     
 407     setup_scbank_map (_cpup);
 408     return SCPE_OK;
 409   }
 410 
 411 
 412 
 413 
 414 static t_stat cable_scu (int uncable, uint scu_unit_idx, char * * name_save)
     
 415   {
 416     if (scu_unit_idx >= scu_dev.numunits)
 417       {
 418         sim_printf ("cable_scu: SCU unit number out of range <%d>\r\n",
 419                     scu_unit_idx);
 420         return SCPE_ARG;
 421       }
 422 
 423     int scu_port_num = getval (name_save, "SCU port number");
 424 
 425     
 426     
 427 
 428     
 429     
 430     
 431     
 432     
 433     
 434 
 435     
 436     
 437     char * param = strtok_r (NULL, ", ", name_save);
 438     if (! param)
 439       {
 440         sim_printf ("cable_scu: can't parse IOM\r\n");
 441         return SCPE_ARG;
 442       }
 443     uint unit_idx;
 444 
 445     
 446     if (name_match (param, "IOM", & unit_idx))
 447       {
 448         if (unit_idx >= N_IOM_UNITS_MAX)
 449           {
 450             sim_printf ("cable SCU: IOM unit number out of range <%d>\r\n", unit_idx);
 451             return SCPE_ARG;
 452           }
 453 
 454         if (scu_port_num < 0 || scu_port_num >= N_SCU_PORTS)
 455           {
 456             sim_printf ("cable_scu: SCU port number out of range <%d>\r\n",
 457                         scu_port_num);
 458             return SCPE_ARG;
 459           }
 460 
 461         
 462         param = strtok_r (NULL, ", ", name_save);
 463         if (! param)
 464           {
 465             sim_printf ("cable SCU: can't parse IOM port number\r\n");
 466             return SCPE_ARG;
 467           }
 468         int iom_port_num = parseval (param);
 469 
 470         if (iom_port_num < 0 || iom_port_num >= N_IOM_PORTS)
 471           {
 472             sim_printf ("cable SCU: IOM port number out of range <%d>\r\n", iom_port_num);
 473             return SCPE_ARG;
 474           }
 475         return cable_scu_to_iom (uncable, scu_unit_idx, (uint) scu_port_num,
 476                                  unit_idx, (uint) iom_port_num);
 477       }
 478 
 479     
 480     else if (name_match (param, "CPU", & unit_idx))
 481       {
 482         if (unit_idx >= N_CPU_UNITS_MAX)
 483           {
 484             sim_printf ("cable SCU: IOM unit number out of range <%d>\r\n", unit_idx);
 485             return SCPE_ARG;
 486           }
 487 
 488         
 489         
 490         
 491         
 492         
 493         
 494         
 495 
 496         int scu_subport_num = 0;
 497         bool is_exp = false;
 498         int exp_port = scu_port_num / 10;
 499         if (exp_port)
 500           {
 501             scu_subport_num = scu_port_num % 10;
 502             if (scu_subport_num < 0 || scu_subport_num >= N_SCU_SUBPORTS)
 503               {
 504                 sim_printf ("cable SCU: subport number out of range <%d>\r\n",
 505                             scu_subport_num);
 506                 return SCPE_ARG;
 507               }
 508             scu_port_num /= 10;
 509             is_exp = true;
 510           }
 511         if (scu_port_num < 0 || scu_port_num >= N_SCU_PORTS)
 512           {
 513             sim_printf ("cable SCU: port number out of range <%d>\r\n",
 514                         scu_port_num);
 515             return SCPE_ARG;
 516           }
 517 
 518         
 519         param = strtok_r (NULL, ", ", name_save);
 520         if (! param)
 521           {
 522             sim_printf ("cable SCU: can't parse CPU port number\r\n");
 523             return SCPE_ARG;
 524           }
 525         int cpu_port_num = parseval (param);
 526 
 527         if (cpu_port_num < 0 || cpu_port_num >= N_CPU_PORTS)
 528           {
 529             sim_printf ("cable SCU: CPU port number out of range <%d>\r\n", cpu_port_num);
 530             return SCPE_ARG;
 531           }
 532         return cable_scu_to_cpu (uncable, scu_unit_idx, (uint) scu_port_num,
 533                                  (uint) scu_subport_num, unit_idx, (uint) cpu_port_num, is_exp);
 534       }
 535     else
 536       {
 537         sim_printf ("cable SCU: can't parse IOM or CPU\r\n");
 538         return SCPE_ARG;
 539       }
 540   }
 541 
 542 static t_stat cable_ctlr_to_iom (int uncable, struct ctlr_to_iom_s * there,
     
 543                                  uint iom_unit_idx, uint chan_num)
 544   {
 545     if (uncable)
 546       {
 547         if (! there->in_use)
 548           {
 549             sim_printf ("error: UNCABLE: controller not cabled\r\n");
 550             return SCPE_ARG;
 551           }
 552         if (there->iom_unit_idx != iom_unit_idx ||
 553             there->chan_num != chan_num)
 554           {
 555             sim_printf ("error: UNCABLE: wrong controller\r\n");
 556             return SCPE_ARG;
 557           }
 558         there->in_use = false;
 559       }
 560    else
 561       {
 562         if (there->in_use)
 563           {
 564             sim_printf ("error: CABLE: controller in use\r\n");
 565             return SCPE_ARG;
 566           }
 567         there->in_use = true;
 568         there->iom_unit_idx = iom_unit_idx;
 569         there->chan_num     = chan_num;
 570       }
 571     return SCPE_OK;
 572   }
 573 
 574 static t_stat cable_ctlr (int uncable,
     
 575                           uint iom_unit_idx, uint chan_num,
 576                           uint ctlr_unit_idx, uint port_num,
 577                           char * service,
 578                           DEVICE * devp,
 579                           struct ctlr_to_iom_s * there,
 580                           enum ctlr_type_e ctlr_type, enum chan_type_e chan_type,
 581                           UNIT * unitp, iom_cmd_t * iom_cmd)
 582   {
 583     if (ctlr_unit_idx >= devp->numunits)
 584       {
 585         sim_printf ("%s: unit index out of range <%d>\r\n",
 586                     service, ctlr_unit_idx);
 587         return SCPE_ARG;
 588       }
 589 
 590     struct iom_to_ctlr_s * p = & cables->iom_to_ctlr[iom_unit_idx][chan_num];
 591 
 592     if (uncable)
 593       {
 594         if (! p->in_use)
 595           {
 596             sim_printf ("%s: not cabled\r\n", service);
 597             return SCPE_ARG;
 598           }
 599 
 600         if (p->ctlr_unit_idx != ctlr_unit_idx)
 601           {
 602             sim_printf ("%s: Wrong IOM expected %d, found %d\r\n",
 603                         service, ctlr_unit_idx, p->ctlr_unit_idx);
 604             return SCPE_ARG;
 605           }
 606 
 607         
 608         t_stat rc = cable_ctlr_to_iom (uncable, there,
 609                                        iom_unit_idx, chan_num);
 610         if (rc)
 611           {
 612             return rc;
 613           }
 614         p->in_use  = false;
 615         p->iom_cmd = NULL;
 616       }
 617     else
 618       {
 619         if (p->in_use)
 620           {
 621             sim_printf ("%s: socket in use; unit number %d. (%o); "
 622                         "not cabling.\r\n", service, iom_unit_idx, iom_unit_idx);
 623             return SCPE_ARG;
 624           }
 625 
 626         
 627         t_stat rc = cable_ctlr_to_iom (uncable, there,
 628                                        iom_unit_idx, chan_num);
 629         if (rc)
 630           {
 631             return rc;
 632           }
 633         p->in_use        = true;
 634         p->ctlr_unit_idx = ctlr_unit_idx;
 635         p->port_num      = port_num;
 636         p->ctlr_type     = ctlr_type;
 637         p->chan_type     = chan_type;
 638         p->dev           = devp;
 639         p->board         = unitp;
 640         p->iom_cmd       = iom_cmd;
 641       }
 642 
 643     return SCPE_OK;
 644   }
 645 
 646 
 647 
 648 
 649 
 650 
 651 
 652 
 653 
 654 
 655 static t_stat cable_iom (int uncable, uint iom_unit_idx, char * * name_save)
     
 656   {
 657     if (iom_unit_idx >= iom_dev.numunits)
 658       {
 659         sim_printf ("error: CABLE IOM: unit number out of range <%d>\r\n",
 660                     iom_unit_idx);
 661         return SCPE_ARG;
 662       }
 663 
 664     int chan_num = getval (name_save, "IOM channel number");
 665 
 666     if (chan_num < 0 || chan_num >= MAX_CHANNELS)
 667       {
 668         sim_printf ("error: CABLE IOM channel number out of range <%d>\r\n",
 669                     chan_num);
 670         return SCPE_ARG;
 671       }
 672 
 673     
 674     char * param = strtok_r (NULL, ", ", name_save);
 675     if (! param)
 676       {
 677         sim_printf ("error: CABLE IOM can't parse controller type\r\n");
 678         return SCPE_ARG;
 679       }
 680     uint unit_idx;
 681 
 682     
 683     if (name_match (param, "IPC", & unit_idx))
 684       {
 685         if (unit_idx >= N_IPC_UNITS_MAX)
 686           {
 687             sim_printf ("error: CABLE IOM: IPC unit number out of range <%d>\r\n", unit_idx);
 688             return SCPE_ARG;
 689           }
 690 
 691         
 692         int ipc_port_num = 0;
 693         param = strtok_r (NULL, ", ", name_save);
 694         if (param)
 695           ipc_port_num = parseval (param);
 696 
 697         if (ipc_port_num < 0 || ipc_port_num >= MAX_CTLR_PORTS)
 698           {
 699             sim_printf ("error: CABLE IOM: IPC port number out of range <%d>\r\n", ipc_port_num);
 700             return SCPE_ARG;
 701           }
 702         return cable_ctlr (uncable,
 703                            iom_unit_idx, (uint) chan_num,
 704                            unit_idx, (uint) ipc_port_num,
 705                            "CABLE IOMx IPCx",
 706                            & ipc_dev,
 707                            & cables->ipc_to_iom[unit_idx][ipc_port_num],
 708                            CTLR_T_IPC, chan_type_PSI,
 709                            & ipc_unit [unit_idx], dsk_iom_cmd); 
 710       }
 711 
 712     
 713     if (name_match (param, "MSP", & unit_idx))
 714       {
 715         if (unit_idx >= N_MSP_UNITS_MAX)
 716           {
 717             sim_printf ("error: CABLE IOM: MSP unit number out of range <%d>\r\n", unit_idx);
 718             return SCPE_ARG;
 719           }
 720 
 721         
 722         int msp_port_num = 0;
 723         param = strtok_r (NULL, ", ", name_save);
 724         if (param)
 725           msp_port_num = parseval (param);
 726 
 727         if (msp_port_num < 0 || msp_port_num >= MAX_CTLR_PORTS)
 728           {
 729             sim_printf ("error: CABLE IOM: MSP port number out of range <%d>\r\n", msp_port_num);
 730             return SCPE_ARG;
 731           }
 732         return cable_ctlr (uncable,
 733                            iom_unit_idx, (uint) chan_num,
 734                            unit_idx, (uint) msp_port_num,
 735                            "CABLE IOMx MSPx",
 736                            & msp_dev,
 737                            & cables->msp_to_iom[unit_idx][msp_port_num],
 738                            CTLR_T_MSP, chan_type_PSI,
 739                            & msp_unit [unit_idx], dsk_iom_cmd); 
 740       }
 741 
 742     
 743     if (name_match (param, "MTP", & unit_idx))
 744       {
 745         if (unit_idx >= N_MTP_UNITS_MAX)
 746           {
 747             sim_printf ("error: CABLE IOM: MTP unit number out of range <%d>\r\n", unit_idx);
 748             return SCPE_ARG;
 749           }
 750 
 751         
 752         int mtp_port_num = 0;
 753         param = strtok_r (NULL, ", ", name_save);
 754         if (param)
 755           mtp_port_num = parseval (param);
 756 
 757         if (mtp_port_num < 0 || mtp_port_num >= MAX_CTLR_PORTS)
 758           {
 759             sim_printf ("error: CABLE IOM: MTP port number out of range <%d>\r\n", mtp_port_num);
 760             return SCPE_ARG;
 761           }
 762         return cable_ctlr (uncable,
 763                            iom_unit_idx, (uint) chan_num,
 764                            unit_idx, (uint) mtp_port_num,
 765                            "CABLE IOMx MTPx",
 766                            & mtp_dev,
 767                            & cables->mtp_to_iom[unit_idx][mtp_port_num],
 768                            CTLR_T_MTP, chan_type_PSI,
 769                            & mtp_unit [unit_idx], mt_iom_cmd); 
 770       }
 771 
 772     
 773     if (name_match (param, "URP", & unit_idx))
 774       {
 775         if (unit_idx >= N_URP_UNITS_MAX)
 776           {
 777             sim_printf ("error: CABLE IOM: URP unit number out of range <%d>\r\n", unit_idx);
 778             return SCPE_ARG;
 779           }
 780 
 781         
 782         int urp_port_num = 0;
 783         param = strtok_r (NULL, ", ", name_save);
 784         if (param)
 785           urp_port_num = parseval (param);
 786 
 787         if (urp_port_num < 0 || urp_port_num >= MAX_CTLR_PORTS)
 788           {
 789             sim_printf ("error: CABLE IOM: URP port number out of range <%d>\r\n", urp_port_num);
 790             return SCPE_ARG;
 791           }
 792 
 793         return cable_ctlr (uncable,
 794                            iom_unit_idx, (uint) chan_num,
 795                            unit_idx, (uint) urp_port_num,
 796                            "CABLE IOMx URPx",
 797                            & urp_dev,
 798                            & cables->urp_to_iom[unit_idx][urp_port_num],
 799                            CTLR_T_URP, chan_type_PSI,
 800                            & urp_unit [unit_idx], urp_iom_cmd);
 801       }
 802 
 803     
 804     if (name_match (param, "OPC", & unit_idx))
 805       {
 806         if (unit_idx >= N_OPC_UNITS_MAX)
 807           {
 808             sim_printf ("error: CABLE IOM: OPC unit number out of range <%d>\r\n", unit_idx);
 809             return SCPE_ARG;
 810           }
 811 
 812         uint opc_port_num = 0;
 813         return cable_ctlr (uncable,
 814                            iom_unit_idx, (uint) chan_num,
 815                            unit_idx, opc_port_num,
 816                            "CABLE IOMx OPCx",
 817                            & opc_dev,
 818                            & cables->opc_to_iom[unit_idx][opc_port_num],
 819                            CTLR_T_OPC, chan_type_CPI,
 820                            & opc_unit [unit_idx], opc_iom_cmd);
 821       }
 822 
 823     
 824     if (name_match (param, "FNP", & unit_idx))
 825       {
 826         if (unit_idx >= N_FNP_UNITS_MAX)
 827           {
 828             sim_printf ("error: CABLE IOM: FNP unit number out of range <%d>\r\n", unit_idx);
 829             return SCPE_ARG;
 830           }
 831 
 832         uint fnp_port_num = 0;
 833         return cable_ctlr (uncable,
 834                            iom_unit_idx, (uint) chan_num,
 835                            unit_idx, fnp_port_num,
 836                            "CABLE IOMx FNPx",
 837                            & fnp_dev,
 838                            & cables->fnp_to_iom[unit_idx][fnp_port_num],
 839                            CTLR_T_FNP, chan_type_direct,
 840                            & fnp_unit [unit_idx], fnp_iom_cmd);
 841       }
 842 
 843 #if defined(WITH_ABSI_DEV)
 844 # if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined (CROSS_MINGW64) && !defined(CROSS_MINGW32)
 845     
 846     if (name_match (param, "ABSI", & unit_idx))
 847       {
 848         if (unit_idx >= N_ABSI_UNITS_MAX)
 849           {
 850             sim_printf ("error: CABLE IOM: ABSI unit number out of range <%d>\r\n", unit_idx);
 851             return SCPE_ARG;
 852           }
 853 
 854         uint absi_port_num = 0;
 855         return cable_ctlr (uncable,
 856                            iom_unit_idx, (uint) chan_num,
 857                            unit_idx, absi_port_num,
 858                            "CABLE IOMx ABSIx",
 859                            & absi_dev,
 860                            & cables->absi_to_iom[unit_idx][absi_port_num],
 861                            CTLR_T_ABSI, chan_type_direct,
 862                            & absi_unit [unit_idx], absi_iom_cmd);
 863       }
 864 # endif 
 865 #endif 
 866 
 867 #if defined(WITH_MGP_DEV)
 868 # if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32)
 869     
 870     if (name_match (param, "MGP", & unit_idx))
 871       {
 872         if (unit_idx >= N_MGP_UNITS_MAX)
 873           {
 874             sim_printf ("error: CABLE IOM: MGP unit number out of range <%d>\r\n", unit_idx);
 875             return SCPE_ARG;
 876           }
 877 
 878         uint mgp_port_num = 0;
 879         return cable_ctlr (uncable,
 880                            iom_unit_idx, (uint) chan_num,
 881                            unit_idx, mgp_port_num,
 882                            "CABLE IOMx MGPx",
 883                            & mgp_dev,
 884                            & cables->mgp_to_iom[unit_idx][mgp_port_num],
 885                            CTLR_T_MGP, chan_type_direct,
 886                            & mgp_unit [unit_idx], mgp_iom_cmd);
 887       }
 888 # endif 
 889 #endif 
 890 
 891 #if defined(WITH_SOCKET_DEV)
 892 # if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32)
 893     
 894     if (name_match (param, "SKC", & unit_idx))
 895       {
 896         if (unit_idx >= N_SKC_UNITS_MAX)
 897           {
 898             sim_printf ("error: CABLE IOM: SKC unit number out of range <%d>\r\n", unit_idx);
 899             return SCPE_ARG;
 900           }
 901 
 902         uint skc_port_num = 0;
 903         return cable_ctlr (uncable,
 904                            iom_unit_idx, (uint) chan_num,
 905                            unit_idx, skc_port_num,
 906                            "CABLE IOMx SKCx",
 907                            & skc_dev,
 908                            & cables->sk_to_iom[unit_idx][skc_port_num],
 909                            CTLR_T_SKC, chan_type_direct,
 910                            & sk_unit [unit_idx], skc_iom_cmd);
 911       }
 912 # endif 
 913 #endif 
 914 
 915     sim_printf ("cable IOM: can't parse controller type\r\n");
 916     return SCPE_ARG;
 917   }
 918 
 919 static t_stat cable_periph_to_ctlr (int uncable,
     
 920                                     uint ctlr_unit_idx, uint dev_code,
 921                                     enum ctlr_type_e ctlr_type,
 922                                     struct dev_to_ctlr_s * there,
 923                                     UNUSED iom_cmd_t * iom_cmd)
 924   {
 925     if (uncable)
 926       {
 927         if (! there->in_use)
 928           {
 929             sim_printf ("error: UNCABLE: device not cabled\r\n");
 930             return SCPE_ARG;
 931           }
 932         if (there->ctlr_unit_idx != ctlr_unit_idx ||
 933             there->dev_code != dev_code)
 934           {
 935             sim_printf ("error: UNCABLE: wrong controller\r\n");
 936             return SCPE_ARG;
 937           }
 938         there->in_use = false;
 939       }
 940    else
 941       {
 942         if (there->in_use)
 943           {
 944             sim_printf ("error: CABLE: device in use\r\n");
 945             return SCPE_ARG;
 946           }
 947         there->in_use        = true;
 948         there->ctlr_unit_idx = ctlr_unit_idx;
 949         there->dev_code      = dev_code;
 950         there->ctlr_type     = ctlr_type;
 951       }
 952     return SCPE_OK;
 953   }
 954 
 955 static t_stat cable_periph (int uncable,
     
 956                             uint ctlr_unit_idx,
 957                             uint dev_code,
 958                             enum ctlr_type_e ctlr_type,
 959                             struct ctlr_to_dev_s * here,
 960                             uint unit_idx,
 961                             iom_cmd_t * iom_cmd,
 962                             struct dev_to_ctlr_s * there,
 963                             char * service)
 964   {
 965     if (uncable)
 966       {
 967         if (! here->in_use)
 968           {
 969             sim_printf ("%s: socket not in use\r\n", service);
 970             return SCPE_ARG;
 971           }
 972         
 973         t_stat rc = cable_periph_to_ctlr (uncable,
 974                                           ctlr_unit_idx, dev_code, ctlr_type,
 975                                           there,
 976                                           iom_cmd);
 977         if (rc)
 978           {
 979             return rc;
 980           }
 981 
 982         here->in_use  = false;
 983         here->iom_cmd = NULL;
 984       }
 985     else
 986       {
 987         if (here->in_use)
 988           {
 989             sim_printf ("%s: controller socket in use; unit number %u. dev_code %oo\r\n",
 990                         service, ctlr_unit_idx, dev_code);
 991             return SCPE_ARG;
 992           }
 993 
 994         
 995         t_stat rc = cable_periph_to_ctlr (uncable,
 996                                           ctlr_unit_idx, dev_code, ctlr_type,
 997                                           there,
 998                                           iom_cmd);
 999         if (rc)
1000           {
1001             return rc;
1002           }
1003 
1004         here->in_use   = true;
1005         here->unit_idx = unit_idx;
1006         here->iom_cmd  = iom_cmd;
1007       }
1008 
1009     return SCPE_OK;
1010   }
1011 
1012 
1013 
1014 static t_stat cable_mtp (int uncable, uint ctlr_unit_idx, char * * name_save)
     
1015   {
1016     if (ctlr_unit_idx >= mtp_dev.numunits)
1017       {
1018         sim_printf ("error: CABLE MTP: controller unit number out of range <%d>\r\n",
1019                     ctlr_unit_idx);
1020         return SCPE_ARG;
1021       }
1022 
1023     int dev_code = getval (name_save, "MTP device code");
1024 
1025     if (dev_code < 0 || dev_code >= MAX_CHANNELS)
1026       {
1027         sim_printf ("error: CABLE MTP device code out of range <%d>\r\n",
1028                     dev_code);
1029         return SCPE_ARG;
1030       }
1031 
1032     
1033     char * param = strtok_r (NULL, ", ", name_save);
1034     if (! param)
1035       {
1036         sim_printf ("error: CABLE IOM can't parse device name\r\n");
1037         return SCPE_ARG;
1038       }
1039     uint mt_unit_idx;
1040 
1041     
1042     if (name_match (param, "TAPE", & mt_unit_idx))
1043       {
1044         if (mt_unit_idx >= N_MT_UNITS_MAX)
1045           {
1046             sim_printf ("error: CABLE IOM: TAPE unit number out of range <%d>\r\n", mt_unit_idx);
1047             return SCPE_ARG;
1048           }
1049 
1050         return cable_periph (uncable,
1051                              ctlr_unit_idx,
1052                              (uint) dev_code,
1053                              CTLR_T_MTP,
1054                              & cables->mtp_to_tape[ctlr_unit_idx][dev_code],
1055                              mt_unit_idx,
1056                              mt_iom_cmd,
1057                              & cables->tape_to_mtp[mt_unit_idx],
1058                              "CABLE MTPx TAPEx");
1059       }
1060 
1061     sim_printf ("cable MTP: can't parse device name\r\n");
1062     return SCPE_ARG;
1063   }
1064 
1065 
1066 
1067 static t_stat cable_ipc (int uncable, uint ctlr_unit_idx, char * * name_save)
     
1068   {
1069     if (ctlr_unit_idx >= ipc_dev.numunits)
1070       {
1071         sim_printf ("error: CABLE IPC: controller unit number out of range <%d>\r\n",
1072                     ctlr_unit_idx);
1073         return SCPE_ARG;
1074       }
1075 
1076     int dev_code = getval (name_save, "IPC device code");
1077 
1078     if (dev_code < 0 || dev_code >= MAX_CHANNELS)
1079       {
1080         sim_printf ("error: CABLE IPC device code out of range <%d>\r\n",
1081                     dev_code);
1082         return SCPE_ARG;
1083       }
1084 
1085     
1086     char * param = strtok_r (NULL, ", ", name_save);
1087     if (! param)
1088       {
1089         sim_printf ("error: CABLE IOM can't parse device name\r\n");
1090         return SCPE_ARG;
1091       }
1092     uint dsk_unit_idx;
1093 
1094     
1095     if (name_match (param, "DISK", & dsk_unit_idx))
1096       {
1097         if (dsk_unit_idx >= N_DSK_UNITS_MAX)
1098           {
1099             sim_printf ("error: CABLE IOM: DISK unit number out of range <%d>\r\n", dsk_unit_idx);
1100             return SCPE_ARG;
1101           }
1102 
1103         return cable_periph (uncable,
1104                              ctlr_unit_idx,
1105                              (uint) dev_code,
1106                              CTLR_T_IPC,
1107                              & cables->ipc_to_dsk[ctlr_unit_idx][dev_code],
1108                              dsk_unit_idx,
1109                              dsk_iom_cmd, 
1110                              & cables->dsk_to_ctlr[dsk_unit_idx],
1111                              "CABLE IPCx DISKx");
1112       }
1113 
1114     sim_printf ("cable IPC: can't parse device name\r\n");
1115     return SCPE_ARG;
1116   }
1117 
1118 
1119 
1120 static t_stat cable_msp (int uncable, uint ctlr_unit_idx, char * * name_save)
     
1121   {
1122     if (ctlr_unit_idx >= msp_dev.numunits)
1123       {
1124         sim_printf ("error: CABLE MSP: controller unit number out of range <%d>\r\n",
1125                     ctlr_unit_idx);
1126         return SCPE_ARG;
1127       }
1128 
1129     int dev_code = getval (name_save, "MSP device code");
1130 
1131     if (dev_code < 0 || dev_code >= MAX_CHANNELS)
1132       {
1133         sim_printf ("error: CABLE MSP device code out of range <%d>\r\n",
1134                     dev_code);
1135         return SCPE_ARG;
1136       }
1137 
1138     
1139     char * param = strtok_r (NULL, ", ", name_save);
1140     if (! param)
1141       {
1142         sim_printf ("error: CABLE IOM can't parse device name\r\n");
1143         return SCPE_ARG;
1144       }
1145     uint dsk_unit_idx;
1146 
1147     
1148     if (name_match (param, "DISK", & dsk_unit_idx))
1149       {
1150         if (dsk_unit_idx >= N_DSK_UNITS_MAX)
1151           {
1152             sim_printf ("error: CABLE IOM: DISK unit number out of range <%d>\r\n", dsk_unit_idx);
1153             return SCPE_ARG;
1154           }
1155 
1156         return cable_periph (uncable,
1157                              ctlr_unit_idx,
1158                              (uint) dev_code,
1159                              CTLR_T_MSP,
1160                              & cables->msp_to_dsk[ctlr_unit_idx][dev_code],
1161                              dsk_unit_idx,
1162                              dsk_iom_cmd, 
1163                              & cables->dsk_to_ctlr[dsk_unit_idx],
1164                              "CABLE MSPx DISKx");
1165       }
1166 
1167     sim_printf ("cable MSP: can't parse device name\r\n");
1168     return SCPE_ARG;
1169   }
1170 
1171 
1172 
1173 static t_stat cable_urp (int uncable, uint ctlr_unit_idx, char * * name_save)
     
1174   {
1175     if (ctlr_unit_idx >= urp_dev.numunits)
1176       {
1177         sim_printf ("error: CABLE URP: controller unit number out of range <%d>\r\n",
1178                     ctlr_unit_idx);
1179         return SCPE_ARG;
1180       }
1181 
1182     int dev_code = getval (name_save, "URP device code");
1183 
1184     if (dev_code < 0 || dev_code >= MAX_CHANNELS)
1185       {
1186         sim_printf ("error: CABLE URP device code out of range <%d>\r\n",
1187                     dev_code);
1188         return SCPE_ARG;
1189       }
1190 
1191     
1192     char * param = strtok_r (NULL, ", ", name_save);
1193     if (! param)
1194       {
1195         sim_printf ("error: CABLE IOM can't parse device name\r\n");
1196         return SCPE_ARG;
1197       }
1198     uint unit_idx;
1199 
1200     
1201     if (name_match (param, "RDR", & unit_idx))
1202       {
1203         if (unit_idx >= N_RDR_UNITS_MAX)
1204           {
1205             sim_printf ("error: CABLE IOM: DISK unit number out of range <%d>\r\n", unit_idx);
1206             return SCPE_ARG;
1207           }
1208 
1209         return cable_periph (uncable,
1210                              ctlr_unit_idx,
1211                              (uint) dev_code,
1212                              CTLR_T_URP,
1213                              & cables->urp_to_urd[ctlr_unit_idx][dev_code],
1214                              unit_idx,
1215                              rdr_iom_cmd, 
1216                              & cables->rdr_to_urp[unit_idx],
1217                              "CABLE URPx RDRx");
1218       }
1219 
1220     
1221     if (name_match (param, "PUN", & unit_idx))
1222       {
1223         if (unit_idx >= N_PUN_UNITS_MAX)
1224           {
1225             sim_printf ("error: CABLE IOM: DISK unit number out of range <%d>\r\n", unit_idx);
1226             return SCPE_ARG;
1227           }
1228 
1229         return cable_periph (uncable,
1230                              ctlr_unit_idx,
1231                              (uint) dev_code,
1232                              CTLR_T_URP,
1233                              & cables->urp_to_urd[ctlr_unit_idx][dev_code],
1234                              unit_idx,
1235                              pun_iom_cmd, 
1236                              & cables->pun_to_urp[unit_idx],
1237                              "CABLE URPx PUNx");
1238       }
1239 
1240     
1241     if (name_match (param, "PRT", & unit_idx))
1242       {
1243         if (unit_idx >= N_PRT_UNITS_MAX)
1244           {
1245             sim_printf ("error: CABLE IOM: DISK unit number out of range <%d>\r\n", unit_idx);
1246             return SCPE_ARG;
1247           }
1248 
1249         return cable_periph (uncable,
1250                              ctlr_unit_idx,
1251                              (uint) dev_code,
1252                              CTLR_T_URP,
1253                              & cables->urp_to_urd[ctlr_unit_idx][dev_code],
1254                              unit_idx,
1255                              prt_iom_cmd, 
1256                              & cables->prt_to_urp[unit_idx],
1257                              "CABLE URPx PRTx");
1258       }
1259 
1260     sim_printf ("cable URP: can't parse device name\r\n");
1261     return SCPE_ARG;
1262   }
1263 
1264 t_stat sys_cable (int32 arg, const char * buf)
     
1265   {
1266     char * copy = strdup (buf);
1267     if (!copy)
1268       {
1269         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1270                        __func__, __FILE__, __LINE__);
1271 #if defined(USE_BACKTRACE)
1272 # if defined(SIGUSR2)
1273         (void)raise(SIGUSR2);
1274          
1275 # endif 
1276 #endif 
1277         abort();
1278       }
1279     t_stat rc = SCPE_ARG;
1280 
1281     
1282 
1283     
1284     char * name_save = NULL;
1285     char * name;
1286     name = strtok_r (copy, ", \t", & name_save);
1287     if (! name)
1288       {
1289         
1290         sim_printf ("error: CABLE: sys_cable could not parse name\r\n");
1291         goto exit;
1292       }
1293 
1294     uint unit_num;
1295     if (strcasecmp (name, "RIPOUT") == 0)
1296       rc = sys_cable_ripout (0, NULL);
1297     else if (strcasecmp (name, "SHOW") == 0)
1298       rc = sys_cable_show (0, NULL);
1299     else if (strcasecmp (name, "DUMP") == 0)
1300       rc = sys_cable_show (1, NULL);
1301     else if (strcasecmp (name, "GRAPH") == 0)
1302       rc = sys_cable_graph ();
1303     else if (name_match (name, "SCU", & unit_num))
1304       rc = cable_scu (arg, unit_num, & name_save);
1305     else if (name_match (name, "IOM", & unit_num))
1306       rc = cable_iom (arg, unit_num, & name_save);
1307     else if (name_match (name, "MTP", & unit_num))
1308       rc = cable_mtp (arg, unit_num, & name_save);
1309     else if (name_match (name, "IPC", & unit_num))
1310       rc = cable_ipc (arg, unit_num, & name_save);
1311     else if (name_match (name, "MSP", & unit_num))
1312       rc = cable_msp (arg, unit_num, & name_save);
1313     else if (name_match (name, "URP", & unit_num))
1314       rc = cable_urp (arg, unit_num, & name_save);
1315     else
1316       {
1317         sim_printf ("error: CABLE: Invalid name <%s>\r\n", name);
1318         goto exit;
1319       }
1320     if (name_save && strlen (name_save))
1321       {
1322         sim_printf ("CABLE ignored '%s'\r\n", name_save);
1323       }
1324 exit:
1325     FREE (copy);
1326     return rc;
1327   }
1328 
1329 static void cable_init (void)
     
1330   {
1331     
1332     
1333 
1334     (void)memset (cables, 0, sizeof (struct cables_s));
1335   }
1336 
1337 #define all(i,n) \
1338   for (uint i = 0; i < n; i ++)
1339 
1340 static t_stat
1341 sys_cable_graph (void)
     
1342 {
1343         
1344         bool cpus_used[N_CPU_UNITS_MAX];
1345         (void)memset (cpus_used, 0, sizeof (cpus_used));
1346 
1347         all (u, N_CPU_UNITS_MAX) all (prt, N_CPU_PORTS)
1348         {
1349                 struct cpu_to_scu_s *p = &cables->cpu_to_scu[u][prt];
1350                 if (p->in_use)
1351                         cpus_used[u] = true;
1352         }
1353 
1354         
1355         bool scus_used[N_SCU_UNITS_MAX];
1356         (void)memset (scus_used, 0, sizeof (scus_used));
1357 
1358         all (u, N_SCU_UNITS_MAX) all (prt, N_SCU_PORTS)
1359         {
1360                 struct scu_to_iom_s *p = &cables->scu_to_iom[u][prt];
1361                 if (p->in_use)
1362                         scus_used[u] = true;
1363         }
1364         all (u, N_CPU_UNITS_MAX) all (prt, N_CPU_PORTS)
1365         {
1366                 struct cpu_to_scu_s *p = &cables->cpu_to_scu[u][prt];
1367                 if (p->in_use)
1368                         scus_used[p->scu_unit_idx] = true;
1369         }
1370 
1371         
1372         bool ioms_used[N_IOM_UNITS_MAX];
1373         (void)memset (ioms_used, 0, sizeof (ioms_used));
1374 
1375         all (u, N_SCU_UNITS_MAX) all (prt, N_SCU_PORTS)
1376         {
1377                 struct scu_to_iom_s *p = &cables->scu_to_iom[u][prt];
1378                 if (p->in_use)
1379                         ioms_used[p->iom_unit_idx] = true;
1380         }
1381 
1382         
1383         sim_printf ("graph {\r\n");
1384         sim_printf ("    rankdir=TD;\r\n");
1385 
1386         
1387         sim_printf ("    { rank=same; ");
1388         for (int i = 0; i < N_CPU_UNITS_MAX; i++)
1389          if (cpus_used[i])
1390           sim_printf (" CPU%c [shape=diamond,  \
1391                                color=lightgreen, \
1392                                style=filled];",
1393                           i + 'A');
1394         sim_printf ("}\r\n");
1395 
1396         
1397         sim_printf ("    { rank=same; ");
1398         for (int i = 0; i < N_SCU_UNITS_MAX; i++)
1399          if (scus_used[i])
1400           sim_printf (" SCU%c [shape=doubleoctagon, \
1401                                color=deepskyblue4,  \
1402                                style=filled];",
1403                           i + 'A');
1404         sim_printf ("}\r\n");
1405 
1406         
1407         sim_printf ("    { rank=same; ");
1408         for (int i = 0; i < N_IOM_UNITS_MAX; i++)
1409          if (ioms_used[i])
1410           sim_printf (" IOM%c [shape=doublecircle, \
1411                                color=cadetblue4,   \
1412                                style=filled];",
1413                           i + 'A');
1414         sim_printf ("}\r\n");
1415 
1416 #define R_CTLR_IOM(big, small, shape, color)                                 \
1417         sim_printf ("    { rank=same; ");                                    \
1418         all (u, N_ ## big ## _UNITS_MAX) all (prt, MAX_CTLR_PORTS)           \
1419         {                                                                    \
1420                 struct ctlr_to_iom_s *p = &cables->small ## _to_iom[u][prt]; \
1421                 if (p->in_use)                                               \
1422                 sim_printf (" %s%d [shape=%s, color=%s, style=filled];",     \
1423                                 #big, u, #shape, #color);                    \
1424         }                                                                    \
1425         sim_printf ("}\r\n");
1426 
1427         R_CTLR_IOM (MTP,  mtp,  oval,    firebrick1)
1428         R_CTLR_IOM (MSP,  msp,  oval,    firebrick2)
1429         R_CTLR_IOM (IPC,  ipc,  oval,    firebrick3)
1430         R_CTLR_IOM (FNP,  fnp,  egg,     snow2)
1431         R_CTLR_IOM (URP,  urp,  polygon, gold4)
1432         R_CTLR_IOM (DIA,  dia,  oval,    orange)
1433 #if defined(WITH_ABSI_DEV)
1434 # if !defined(__MINGW64__)
1435         R_CTLR_IOM (ABSI, absi, oval,    teal)
1436 # endif 
1437 #endif 
1438 #if defined(WITH_MGP_DEV)
1439 # if !defined(__MINGW64__)
1440         R_CTLR_IOM (MGP, mgp, oval,    teal)
1441 # endif 
1442 #endif 
1443         R_CTLR_IOM (OPC,  opc,  oval,    hotpink)
1444 
1445 #define R_DEV_CTLR(from_big, from_small, to_label,                       \
1446                       to_big, to_small, shape, color)                    \
1447         sim_printf ("    { rank=same; ");                                \
1448         all (u, N_ ## to_big ## _UNITS_MAX)                              \
1449         {                                                                \
1450                 struct dev_to_ctlr_s *p =                                \
1451                     &cables->to_small ## _to_ ## from_small[u];          \
1452                 if (p->in_use)                                           \
1453                 sim_printf (" %s%d [shape=%s, style=filled, color=%s];", \
1454                                 #to_label, u, #shape, #color);           \
1455         }                                                                \
1456         sim_printf ("}\r\n");
1457 
1458         R_DEV_CTLR (MTP,  mtp,  TAPE, MT,  tape, oval,     aquamarine3);
1459         R_DEV_CTLR (CTLR, ctlr, DISK, DSK, dsk,  cylinder, bisque3);
1460         R_DEV_CTLR (URP,  urp,  RDR,  RDR, rdr,  septagon, mediumpurple1);
1461         R_DEV_CTLR (URP,  urp,  PUN,  PUN, pun,  pentagon, maroon3);
1462         R_DEV_CTLR (URP,  urp,  PRT,  PRT, prt,  octagon,  yellowgreen);
1463 
1464         
1465         all (u, N_CPU_UNITS_MAX) all (prt, N_CPU_PORTS)
1466         {
1467                 struct cpu_to_scu_s *p = &cables->cpu_to_scu[u][prt];
1468                 if (p->in_use)
1469                         sim_printf ("    CPU%c -- SCU%c;\r\n", u + 'A',
1470                                     p->scu_unit_idx + 'A');
1471         }
1472 
1473         
1474         all (u, N_SCU_UNITS_MAX) all (prt, N_SCU_PORTS)
1475         {
1476                 struct scu_to_iom_s *p = &cables->scu_to_iom[u][prt];
1477                 if (p->in_use)
1478                         sim_printf ("    SCU%c -- IOM%c;\r\n", u + 'A',
1479                                     p->iom_unit_idx + 'A');
1480         }
1481 
1482         
1483         all (u, N_IOM_UNITS_MAX) all (c, MAX_CHANNELS)
1484         {
1485                 struct iom_to_ctlr_s *p = &cables->iom_to_ctlr[u][c];
1486                 if (p->in_use)
1487                         sim_printf ("    IOM%c -- %s%d;\r\n", u + 'A',
1488                                     ctlr_type_strs[p->ctlr_type],
1489                                     p->ctlr_unit_idx);
1490         }
1491 
1492         
1493 #define G_DEV_CTLR(from_big, from_small, to_label, to_big, to_small) \
1494         all (u, N_ ## to_big ## _UNITS_MAX)                          \
1495         {                                                            \
1496                 struct dev_to_ctlr_s *p =                            \
1497                     &cables->to_small ## _to_ ## from_small[u];      \
1498                 if (p->in_use)                                       \
1499                 sim_printf ("    %s%d -- %s%d;\r\n",                 \
1500                             ctlr_type_strs[p->ctlr_type],            \
1501                             p->ctlr_unit_idx, #to_label, u);         \
1502         }
1503 
1504         G_DEV_CTLR (MTP,  mtp,  TAPE, MT,  tape);
1505         G_DEV_CTLR (CTLR, ctlr, DISK, DSK, dsk);
1506         G_DEV_CTLR (URP,  urp,  RDR,  RDR, rdr);
1507         G_DEV_CTLR (URP,  urp,  PUN,  PUN, pun);
1508         G_DEV_CTLR (URP,  urp,  PRT,  PRT, prt);
1509 
1510         sim_printf ("}\r\n");
1511         return SCPE_OK;
1512 }
1513 
1514 t_stat sys_cable_show (int32 dump, UNUSED const char * buf)
     
1515   {
1516     sim_printf ("SCU <--> IOM\r\n");
1517     sim_printf ("   SCU port --> IOM port\r\n");
1518     all (u, N_SCU_UNITS_MAX)
1519       all (prt, N_SCU_PORTS)
1520         {
1521           struct scu_to_iom_s * p = & cables->scu_to_iom[u][prt];
1522           if (p->in_use)
1523             sim_printf (" %4u %4u    %4u %4u\r\n", u, prt, p->iom_unit_idx, p->iom_port_num);
1524         }
1525 
1526     if (dump)
1527       {
1528         sim_printf ("   IOM port --> SCU port\r\n");
1529         all (u, N_IOM_UNITS_MAX)
1530           all (prt, N_IOM_PORTS)
1531             {
1532               struct iom_to_scu_s * p = & cables->iom_to_scu[u][prt];
1533               if (p->in_use)
1534                 sim_printf (" %4u %4u    %4u %4u\r\n", u, prt, p->scu_unit_idx, p->scu_port_num);
1535             }
1536       }
1537     sim_printf ("\r\n");
1538 
1539     sim_printf ("SCU <--> CPU\r\n");
1540     sim_printf ("   SCU port --> CPU port\r\n");
1541     all (u, N_SCU_UNITS_MAX)
1542       all (prt, N_SCU_PORTS)
1543         all (sp, N_SCU_SUBPORTS)
1544           {
1545             struct scu_to_cpu_s * p = & cables->scu_to_cpu[u][prt][sp];
1546             if (p->in_use)
1547               sim_printf (" %4u %4u    %4u %4u\r\n", u, prt, p->cpu_unit_idx, p->cpu_port_num);
1548           }
1549 
1550     if (dump)
1551       {
1552         sim_printf ("   CPU port --> SCU port subport\r\n");
1553         all (u, N_CPU_UNITS_MAX)
1554           all (prt, N_CPU_PORTS)
1555             {
1556               struct cpu_to_scu_s * p = & cables->cpu_to_scu[u][prt];
1557               if (p->in_use)
1558                 sim_printf (" %4u %4u    %4u %4u  %4u\r\n",
1559                         u, prt, p->scu_unit_idx, p->scu_port_num, p->scu_subport_num);
1560             }
1561         }
1562     sim_printf ("\r\n");
1563 
1564     sim_printf ("IOM <--> controller\r\n");
1565     sim_printf ("                 ctlr       ctlr  chan\r\n");
1566     sim_printf ("   IOM chan -->  idx  port  type  type      device      board    command\r\n");
1567     all (u, N_IOM_UNITS_MAX)
1568       all (c, MAX_CHANNELS)
1569         {
1570           struct iom_to_ctlr_s * p = & cables->iom_to_ctlr[u][c];
1571           if (p->in_use)
1572             sim_printf (" %4u %4u     %4u  %4u %-6s  %-6s %10p %10p %10p\r\n",
1573                     u, c, p->ctlr_unit_idx, p->port_num, ctlr_type_strs[p->ctlr_type],
1574                     chan_type_strs[p->chan_type], (void *) p->dev,
1575                     (void *) p->board, (void *) p->iom_cmd);
1576         }
1577 
1578     if (dump)
1579       {
1580 #define CTLR_IOM(big,small)                                                                \
1581     sim_printf ("  %-4s port --> IOM channel\r\n", #big);                                  \
1582     all (u, N_ ## big ## _UNITS_MAX)                                                       \
1583       all (prt, MAX_CTLR_PORTS)                                                            \
1584         {                                                                                  \
1585           struct ctlr_to_iom_s * p = & cables->small ## _to_iom[u][prt];                   \
1586           if (p->in_use)                                                                   \
1587             sim_printf (" %4u %4u    %4u %4u\r\n", u, prt, p->iom_unit_idx, p->chan_num);  \
1588         }
1589         CTLR_IOM (MTP, mtp)
1590         CTLR_IOM (MSP, msp)
1591         CTLR_IOM (IPC, ipc)
1592         CTLR_IOM (URP, urp)
1593         CTLR_IOM (FNP, fnp)
1594         CTLR_IOM (DIA, dia)
1595 #if defined(WITH_ABSI_DEV)
1596 # if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1597         CTLR_IOM (ABSI, absi)
1598 # endif 
1599 #endif 
1600 #if defined(WITH_MGP_DEV)
1601 # if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1602         CTLR_IOM (MGP, mgp)
1603 # endif 
1604 #endif 
1605 #if defined(WITH_SOCKET_DEV)
1606 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1607         CTLR_IOM (SKC, sk)
1608 # endif 
1609 #endif 
1610         CTLR_IOM (OPC, opc)
1611       }
1612     sim_printf ("\r\n");
1613 
1614     sim_printf ("controller <--> device\r\n");
1615 
1616 #define CTLR_DEV(from_big,from_small, to_label, to_big, to_small)                                   \
1617     sim_printf ("  %-4s dev_code --> %-4s   command\r\n", #from_big, #to_label);                    \
1618     all (u, N_ ## from_big ## _UNITS_MAX)                                                           \
1619       all (prt, N_DEV_CODES)                                                                        \
1620         {                                                                                           \
1621           struct ctlr_to_dev_s * p = & cables->from_small ## _to_ ## to_small[u][prt];              \
1622           if (p->in_use)                                                                            \
1623             sim_printf (" %4u  %4u        %4u %10p\r\n", u, prt, p->unit_idx, (void *) p->iom_cmd); \
1624         }
1625 #define DEV_CTLR(from_big,from_small, to_label, to_big, to_small)               \
1626     sim_printf ("  %-4s --> %-4s dev_code type\r\n", #to_label, #from_big);     \
1627     all (u, N_ ## to_big ## _UNITS_MAX)                                         \
1628       {                                                                         \
1629         struct dev_to_ctlr_s * p = & cables->to_small ## _to_ ## from_small[u]; \
1630         if (p->in_use)                                                          \
1631           sim_printf (" %4u    %4u   %4u    %5s\r\n", u, p->ctlr_unit_idx,      \
1632                   p->dev_code, ctlr_type_strs[p->ctlr_type]);                   \
1633       }
1634     CTLR_DEV (MTP, mtp, TAPE, MT, tape);
1635     if (dump) 
1636       {
1637         DEV_CTLR (MTP, mtp, TAPE, MT, tape);
1638       }
1639     CTLR_DEV (IPC, ipc, DISK, DSK, dsk);
1640     CTLR_DEV (MSP, msp, DISK, DSK, dsk);
1641     if (dump) 
1642       {
1643         DEV_CTLR (CTLR, ctlr, DISK, DSK, dsk);
1644       }
1645     CTLR_DEV (URP, urp, URP, URP, urd);
1646     if (dump) 
1647       {
1648         DEV_CTLR (URP, urp, RDR, RDR, rdr);
1649       }
1650     if (dump) 
1651       {
1652         DEV_CTLR (URP, urp, PUN, PUN, pun);
1653       }
1654     if (dump) 
1655       {
1656         DEV_CTLR (URP, urp, PRT, PRT, prt);
1657       }
1658 
1659     return SCPE_OK;
1660   }
1661 
1662 t_stat sys_cable_ripout (UNUSED int32 arg, UNUSED const char * buf)
     
1663   {
1664     cable_init ();
1665     scu_init ();
1666     return SCPE_OK;
1667   }
1668 
1669 void sysCableInit (void)
     
1670   {
1671 
1672 
1673 
1674 
1675 
1676 
1677 
1678 
1679 
1680 
1681 
1682 
1683 
1684 
1685 
1686 
1687     cables = & system_state->cables;
1688 
1689     
1690     cable_init ();
1691   }