root/src/dps8/dps8_utils.c

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

DEFINITIONS

This source file includes following definitions.
  1. dump_flags
  2. dps8_strupr
  3. get_iwb_info
  4. disassemble
  5. get_mod_string
  6. Add36b
  7. Sub36b
  8. Add18b
  9. Sub18b
  10. Add72b
  11. Sub72b
  12. compl36
  13. compl18
  14. copyBytes
  15. copyChars
  16. putByte
  17. putChar
  18. convert_to_word72
  19. convert_to_word36
  20. cmp36
  21. cmp18
  22. cmp36wl
  23. cmp72
  24. strlower
  25. strmask
  26. rtrim
  27. ltrim
  28. trim
  29. stripquotes
  30. cfg_parse
  31. cfg_parse_done
  32. strdupesc
  33. extrASCII36
  34. extr36
  35. putASCII36
  36. put36
  37. extractASCII36FromBuffer
  38. extractWord36FromBuffer
  39. insertASCII36toBuffer
  40. insertWord36toBuffer
  41. print_uint128o_r
  42. print_int128o
  43. print_uint128_r
  44. print_int128
  45. timespec_diff

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: 1414c8ee-f62f-11ec-885a-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2007-2013 Michael Mondy
   9  * Copyright (c) 2012-2016 Harry Reed
  10  * Copyright (c) 2013-2016 Charles Anthony
  11  * Copyright (c) 2021-2024 The DPS8M Development Team
  12  *
  13  * This software is made available under the terms of the ICU License.
  14  * See the LICENSE.md file at the top-level directory of this distribution.
  15  *
  16  * ---------------------------------------------------------------------------
  17  */
  18 
  19 #include <stdio.h>
  20 #include <string.h>
  21 #include <signal.h>
  22 #include <ctype.h>
  23 
  24 #include "dps8.h"
  25 #include "dps8_sys.h"
  26 #include "dps8_iom.h"
  27 #include "dps8_cable.h"
  28 #include "dps8_cpu.h"
  29 #include "dps8_faults.h"
  30 #include "dps8_scu.h"
  31 #include "dps8_ins.h"
  32 #include "dps8_opcodetable.h"
  33 #include "dps8_utils.h"
  34 
  35 #define DBG_CTR 1
  36 
  37 #define FREE(p) do  \
  38   {                 \
  39     free((p));      \
  40     (p) = NULL;     \
  41   } while(0)
  42 
  43 /*
  44  * misc utility routines used by simulator
  45  */
  46 
  47 char * dump_flags(char * buffer, word18 flags)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49     (void)sprintf(buffer, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
  50                   flags & I_HEX   ? "Hex "   : "",  // L68 will never have I_HEX set, so no need to DPS8M-only
  51                   flags & I_ABS   ? "Abs "   : "",
  52                   flags & I_MIF   ? "MIF "   : "",
  53                   flags & I_TRUNC ? "Trunc " : "",
  54                   flags & I_NBAR  ? "~BAR "  : "",
  55                   flags & I_PMASK ? "PMask " : "",
  56                   flags & I_PERR  ? "PErr"   : "",
  57                   flags & I_TALLY ? "Tally " : "",
  58                   flags & I_OMASK ? "OMASK " : "",
  59                   flags & I_EUFL  ? "EUFL "  : "",
  60                   flags & I_EOFL  ? "EOFL "  : "",
  61                   flags & I_OFLOW ? "Ovr "   : "",
  62                   flags & I_CARRY ? "Carry " : "",
  63                   flags & I_NEG   ? "Neg "   : "",
  64                   flags & I_ZERO  ? "Zero "  : ""
  65                  );
  66     return buffer;
  67 }
  68 
  69 static char * dps8_strupr(char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71     char *s;
  72 
  73     for(s = str; *s; s++)
  74         *s = (char) toupper((unsigned char)*s);
  75     return str;
  76 }
  77 
  78 //! get instruction info for IWB ...
  79 
  80 static struct opcode_s unimplented = {"(unimplemented)", 0, 0, 0, 0};
  81 
  82 struct opcode_s * get_iwb_info  (DCDstruct * i)
     /* [previous][next][first][last][top][bottom][index][help] */
  83   {
  84     struct opcode_s * p = &opcodes10[i->opcode10];
  85     return p->mne ? p : &unimplented;
  86   }
  87 
  88 char *disassemble(char * result, word36 instruction)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     uint32 opcode   = GET_OP(instruction);   ///< get opcode
  91     uint32 opcodeX  = GET_OPX(instruction);  ///< opcode extension
  92     uint32 opcode10 = opcode | (opcodeX ? 01000 : 0);
  93     word18 address  = GET_ADDR(instruction);
  94     word1  a        = GET_A(instruction);
  95     //int32 i       = GET_I(instruction);
  96     word6  tag      = GET_TAG(instruction);
  97 
  98     //static char result[132] = "???";
  99     strcpy(result, "???");
 100 
 101     // get mnemonic ...
 102     if (opcodes10[opcode10].mne)
 103         strcpy(result, opcodes10[opcode10].mne);
 104 
 105     // XXX need to reconstruct multi-word EIS instruction.
 106 
 107     char buff[256];
 108 
 109     if (a)
 110     {
 111         int n = (address >> 15) & 07;
 112         int offset = address & 077777;
 113 
 114         (void)sprintf (buff, " pr%d|%o", n, offset);
 115         strcat (result, buff);
 116         // return dps8_strupr(result);
 117     } else {
 118         (void)sprintf (buff, " %06o", address);
 119         strcat (result, buff);
 120     }
 121     // get mod
 122     strcpy(buff, "");
 123     for(uint n = 0 ; n < 0100 ; n++)
 124         if (extMods[n].mod)
 125             if(n == tag)
 126             {
 127                 strncpy(buff, extMods[n].mod, sizeof(buff) - 1);
 128                 buff[sizeof(buff) - 1] = '\0';
 129                 break;
 130             }
 131 
 132     if (strlen(buff))
 133     {
 134         strcat(result, ",");
 135         strcat(result, buff);
 136     }
 137 
 138     return dps8_strupr(result);
 139 }
 140 
 141 /*
 142  * get_mod__string ()
 143  *
 144  * Convert instruction address modifier tag to printable string
 145  * WARNING: returns pointer to statically allocated string
 146  */
 147 
 148 char *get_mod_string(char * msg, word6 tag)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150     strcpy(msg, "none");
 151 
 152     if (tag >= 0100) //-V536
 153     {
 154         (void)sprintf (msg, "getModReg(tag out-of-range %o)", tag);
 155     } else {
 156         for(uint n = 0 ; n < 0100 ; n++) //-V536
 157             if (extMods[n].mod)
 158                 if(n == tag)
 159                 {
 160                     strcpy(msg, extMods[n].mod);
 161                     break;
 162                 }
 163 
 164     }
 165     return msg;
 166 }
 167 
 168 /*
 169  * 36-bit arithmetic stuff ...
 170  */
 171 /* Single word integer routines */
 172 
 173 word36 Add36b (cpu_state_t * cpup, word36 op1, word36 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 174   {
 175     CPT (cpt2L, 17); // Add36b
 176     sim_debug (DBG_TRACEEXT, & cpu_dev,
 177                "Add36b op1 %012"PRIo64" op2 %012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
 178                op1, op2, carryin, flagsToSet, * flags);
 179 
 180 // See: https://en.wikipedia.org/wiki/Two%27s_complement#Addition
 181 
 182     // 37 bit arithmetic for the above N+1 algorithm
 183     word38 op1e = op1 & MASK36;
 184     word38 op2e = op2 & MASK36;
 185     word38 ci   = carryin ? 1 : 0;
 186 
 187     // extend sign bits
 188     if (op1e & SIGN36)
 189       op1e |= BIT37;
 190     if (op2e & SIGN36)
 191       op2e |= BIT37;
 192 
 193     // Do the math
 194     word38 res = op1e + op2e + ci;
 195 
 196     // Extract the overflow bits
 197     bool r37 = res & BIT37 ? true : false;
 198     bool r36 = res & SIGN36 ? true : false;
 199 
 200     // Extract the carry bit
 201     bool r38 = res & BIT38 ? true : false;
 202 
 203     // Check for overflow
 204     * ovf = r37 ^ r36;
 205 
 206     // Check for carry
 207     bool cry = r38;
 208 
 209     // Truncate the result
 210     res &= MASK36;
 211 
 212 #if defined(PANEL68)
 213     if (cry) CPT (cpt2L, 28); // carry
 214     if (ovf) CPT (cpt2L, 29); // ovf
 215     if (!res) CPT (cpt2L, 30); // zero
 216     if (res & SIGN36) CPT (cpt2L, 31); // neg
 217 #endif
 218 
 219     if (flagsToSet & I_CARRY)
 220       {
 221         if (cry)
 222           SETF (* flags, I_CARRY);
 223         else
 224           CLRF (* flags, I_CARRY);
 225       }
 226 
 227     if (chkOVF (cpup) && (flagsToSet & I_OFLOW))
 228       {
 229         if (* ovf)
 230           SETF (* flags, I_OFLOW);      // overflow
 231       }
 232 
 233     if (flagsToSet & I_ZERO)
 234       {
 235         if (res)
 236           CLRF (* flags, I_ZERO);
 237         else
 238           SETF (* flags, I_ZERO);       // zero result
 239       }
 240 
 241     if (flagsToSet & I_NEG)
 242       {
 243         if (res & SIGN36)
 244           SETF (* flags, I_NEG);
 245         else
 246           CLRF (* flags, I_NEG);
 247       }
 248 
 249     sim_debug (DBG_TRACEEXT, & cpu_dev, "Add36b res %012"PRIo64" flags %06o ovf %o\n", res, * flags, * ovf);
 250     return res;
 251   }
 252 
 253 word36 Sub36b (cpu_state_t * cpup, word36 op1, word36 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 254   {
 255     CPT (cpt2L, 18); // Sub36b
 256 
 257 // See: https://en.wikipedia.org/wiki/Two%27s_complement
 258 
 259 // AL39:
 260 //
 261 //  If carry indicator ON, then C(A) - C(Y) -> C(A)
 262 //  If carry indicator OFF, then C(A) - C(Y) - 1 -> C(A)
 263 
 264     // 38 bit arithmetic for the above N+1 algorithm
 265     word38 op1e = op1 & MASK36;
 266     word38 op2e = op2 & MASK36;
 267     // Note that carryin has an inverted sense for borrow
 268     word38 ci   = carryin ? 0 : 1;
 269 
 270     // extend sign bits
 271     if (op1e & SIGN36)
 272       op1e |= BIT37;
 273     if (op2e & SIGN36)
 274       op2e |= BIT37;
 275 
 276     // Do the math
 277     // word38 res = op1e - op2e - ci;
 278     // ubsan
 279     word38 res = (word38) (((word38s) op1e) - ((word38s) op2e) - ((word38) ci));
 280 
 281     // Extract the overflow bits
 282     bool r37 = (res & BIT37) ? true : false;
 283     bool r36 = (res & SIGN36) ? true : false;
 284 
 285     // Extract the carry bit
 286     bool r38 = res & BIT38 ? true : false;
 287 
 288     // Truncate the result
 289     res &= MASK36;
 290 
 291     // Check for overflow
 292     * ovf = r37 ^ r36;
 293 
 294     // Check for carry
 295     bool cry = r38;
 296 
 297 #if defined(PANEL68)
 298     if (cry) CPT (cpt2L, 28); // carry
 299     if (ovf) CPT (cpt2L, 29); // ovf
 300     if (!res) CPT (cpt2L, 30); // zero
 301     if (res & SIGN36) CPT (cpt2L, 31); // neg
 302 #endif
 303 
 304     if (flagsToSet & I_CARRY)
 305       {
 306         if (cry) // Note inverted logic for subtraction
 307           CLRF (* flags, I_CARRY);
 308         else
 309           SETF (* flags, I_CARRY);
 310       }
 311 
 312     if (chkOVF (cpup) && (flagsToSet & I_OFLOW))
 313       {
 314         if (* ovf)
 315           SETF (* flags, I_OFLOW);      // overflow
 316       }
 317 
 318     if (flagsToSet & I_ZERO)
 319       {
 320         if (res)
 321           CLRF (* flags, I_ZERO);
 322         else
 323           SETF (* flags, I_ZERO);       // zero result
 324       }
 325 
 326     if (flagsToSet & I_NEG)
 327       {
 328         if (res & SIGN36)
 329           SETF (* flags, I_NEG);
 330         else
 331           CLRF (* flags, I_NEG);
 332       }
 333 
 334     return res;
 335   }
 336 
 337 word18 Add18b (cpu_state_t * cpup, word18 op1, word18 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 338   {
 339     CPT (cpt2L, 19); // Add18b
 340 
 341 // See: https://en.wikipedia.org/wiki/Two%27s_complement#Addition
 342 
 343     // 19 bit arithmetic for the above N+1 algorithm
 344     word20 op1e = op1 & MASK18;
 345     word20 op2e = op2 & MASK18;
 346     word20 ci   = carryin ? 1 : 0;
 347 
 348     // extend sign bits
 349     if (op1e & SIGN18)
 350       op1e |= BIT19;
 351     if (op2e & SIGN18)
 352       op2e |= BIT19;
 353 
 354     // Do the math
 355     word20 res = op1e + op2e + ci;
 356 
 357     // Extract the overflow bits
 358     bool r19 = (res & BIT19)  ? true : false;
 359     bool r18 = (res & SIGN18) ? true : false;
 360 
 361     // Extract the carry bit
 362     bool r20 = res & BIT20 ? true : false;
 363 
 364     // Truncate the result
 365     res &= MASK18;
 366 
 367     // Check for overflow
 368     * ovf = r19 ^ r18;
 369 
 370     // Check for carry
 371     bool cry = r20;
 372 
 373 #if defined(PANEL68)
 374     if (cry) CPT (cpt2L, 28); // carry
 375     if (ovf) CPT (cpt2L, 29); // ovf
 376     if (!res) CPT (cpt2L, 30); // zero
 377     if (res & SIGN36) CPT (cpt2L, 31); // neg
 378 #endif
 379 
 380     if (flagsToSet & I_CARRY)
 381       {
 382         if (cry)
 383           SETF (* flags, I_CARRY);
 384         else
 385           CLRF (* flags, I_CARRY);
 386       }
 387 
 388     if (chkOVF (cpup) && (flagsToSet & I_OFLOW))
 389       {
 390         if (* ovf)
 391           SETF (* flags, I_OFLOW);      // overflow
 392       }
 393 
 394     if (flagsToSet & I_ZERO)
 395       {
 396         if (res)
 397           CLRF (* flags, I_ZERO);
 398         else
 399           SETF (* flags, I_ZERO);       // zero result
 400       }
 401 
 402     if (flagsToSet & I_NEG)
 403       {
 404         if (res & SIGN18)
 405           SETF (* flags, I_NEG);
 406         else
 407           CLRF (* flags, I_NEG);
 408       }
 409 
 410     return (word18) res;
 411   }
 412 
 413 word18 Sub18b (cpu_state_t * cpup, word18 op1, word18 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 414   {
 415     CPT (cpt2L, 20); // Sub18b
 416 
 417 // See: https://en.wikipedia.org/wiki/Two%27s_complement
 418 
 419 // AL39:
 420 //
 421 //  If carry indicator ON, then C(A) - C(Y) -> C(A)
 422 //  If carry indicator OFF, then C(A) - C(Y) - 1 -> C(A)
 423 
 424     // 19 bit arithmetic for the above N+1 algorithm
 425     word20 op1e = op1 & MASK18;
 426     word20 op2e = op2 & MASK18;
 427     // Note that carryin has an inverted sense for borrow
 428     word20 ci   = carryin ? 0 : 1;
 429 
 430     // extend sign bits
 431     if (op1e & SIGN18)
 432       op1e |= BIT19;
 433     if (op2e & SIGN18)
 434       op2e |= BIT19;
 435 
 436     // Do the math
 437     // word20 res = op1e - op2e - ci;
 438     // ubsan
 439     word20 res = (word20) (((word20s) op1e) - ((word20s) op2e) - ((word20s) ci));
 440 
 441     // Extract the overflow bits
 442     bool r19 = res & BIT19  ? true : false;
 443     bool r18 = res & SIGN18 ? true : false;
 444 
 445     // Extract the carry bit
 446     bool r20 = res & BIT20 ? true : false;
 447 
 448     // Truncate the result
 449     res &= MASK18;
 450 
 451     // Check for overflow
 452     * ovf = r19 ^ r18;
 453 
 454     // Check for carry
 455     bool cry = r20;
 456 
 457 #if defined(PANEL68)
 458     if (cry) CPT (cpt2L, 28); // carry
 459     if (ovf) CPT (cpt2L, 29); // ovf
 460     if (!res) CPT (cpt2L, 30); // zero
 461     if (res & SIGN36) CPT (cpt2L, 31); // neg
 462 #endif
 463 
 464     if (flagsToSet & I_CARRY)
 465       {
 466         if (cry) // Note inverted logic for subtraction
 467           CLRF (* flags, I_CARRY);
 468         else
 469           SETF (* flags, I_CARRY);
 470       }
 471 
 472     if (chkOVF (cpup) && (flagsToSet & I_OFLOW))
 473       {
 474         if (* ovf)
 475           SETF (* flags, I_OFLOW);      // overflow
 476       }
 477 
 478     if (flagsToSet & I_ZERO)
 479       {
 480         if (res)
 481           CLRF (* flags, I_ZERO);
 482         else
 483           SETF (* flags, I_ZERO);       // zero result
 484       }
 485 
 486     if (flagsToSet & I_NEG)
 487       {
 488         if (res & SIGN18)
 489           SETF (* flags, I_NEG);
 490         else
 491           CLRF (* flags, I_NEG);
 492       }
 493 
 494     return res;
 495   }
 496 
 497 word72 Add72b (cpu_state_t * cpup, word72 op1, word72 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 498   {
 499     CPT (cpt2L, 21); // Add72b
 500 
 501 // See: https://en.wikipedia.org/wiki/Two%27s_complement#Addition
 502 
 503     // 73 bit arithmetic for the above N+1 algorithm
 504 #if defined(NEED_128)
 505     word74 op1e = and_128 (op1, MASK72);
 506     word74 op2e = and_128 (op2, MASK72);
 507     word74 ci   = construct_128 (0, carryin ? 1 : 0);
 508 #else
 509     word74 op1e = op1 & MASK72;
 510     word74 op2e = op2 & MASK72;
 511     word74 ci   = carryin ? 1 : 0;
 512 #endif
 513 
 514     // extend sign bits
 515 #if defined(NEED_128)
 516     if (isnonzero_128 (and_128 (op1e, SIGN72)))
 517       op1e = or_128 (op1e, BIT73);
 518     if (isnonzero_128 (and_128 (op2e, SIGN72)))
 519       op2e = or_128 (op2e, BIT73);
 520 #else
 521     if (op1e & SIGN72)
 522       op1e |= BIT73;
 523     if (op2e & SIGN72)
 524       op2e |= BIT73;
 525 #endif
 526 
 527     // Do the math
 528 #if defined(NEED_128)
 529     word74 res = add_128 (op1e, add_128 (op2e, ci));
 530 #else
 531     word74 res = op1e + op2e + ci;
 532 #endif
 533 
 534     // Extract the overflow bits
 535 #if defined(NEED_128)
 536     bool r73 = isnonzero_128 (and_128 (res, BIT73));
 537     bool r72 = isnonzero_128 (and_128 (res, SIGN72));
 538 #else
 539     bool r73 = res & BIT73  ? true : false;
 540     bool r72 = res & SIGN72 ? true : false;
 541 #endif
 542 
 543     // Extract the carry bit
 544 #if defined(NEED_128)
 545     bool r74 = isnonzero_128 (and_128 (res, BIT74));
 546 #else
 547     bool r74 = res & BIT74 ? true : false;
 548 #endif
 549 
 550     // Truncate the result
 551 #if defined(NEED_128)
 552     res = and_128 (res, MASK72);
 553 #else
 554     res &= MASK72;
 555 #endif
 556 
 557     // Check for overflow
 558     * ovf = r73 ^ r72;
 559 
 560     // Check for carry
 561     bool cry = r74;
 562 
 563 #if defined(PANEL68)
 564     if (cry) CPT (cpt2L, 28); // carry
 565     if (ovf) CPT (cpt2L, 29); // ovf
 566     if (!res) CPT (cpt2L, 30); // zero
 567     if (res & SIGN36) CPT (cpt2L, 31); // neg
 568 #endif
 569 
 570     if (flagsToSet & I_CARRY)
 571       {
 572         if (cry)
 573           SETF (* flags, I_CARRY);
 574         else
 575           CLRF (* flags, I_CARRY);
 576       }
 577 
 578     if (chkOVF (cpup) && (flagsToSet & I_OFLOW))
 579       {
 580         if (* ovf)
 581           SETF (* flags, I_OFLOW);      // overflow
 582       }
 583 
 584     if (flagsToSet & I_ZERO)
 585       {
 586 #if defined(NEED_128)
 587         if (isnonzero_128 (res))
 588 #else
 589         if (res)
 590 #endif
 591           CLRF (* flags, I_ZERO);
 592         else
 593           SETF (* flags, I_ZERO);       // zero result
 594       }
 595 
 596     if (flagsToSet & I_NEG)
 597       {
 598 #if defined(NEED_128)
 599         if (isnonzero_128 (and_128 (res, SIGN72)))
 600 #else
 601         if (res & SIGN72)
 602 #endif
 603           SETF (* flags, I_NEG);
 604         else
 605           CLRF (* flags, I_NEG);
 606       }
 607 
 608     return res;
 609   }
 610 
 611 word72 Sub72b (cpu_state_t * cpup, word72 op1, word72 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 612   {
 613     CPT (cpt2L, 22); // Sub72b
 614 #if defined(NEED_128)
 615     sim_debug (DBG_TRACEEXT, & cpu_dev,
 616                "Sub72b op1 %012"PRIo64"%012"PRIo64" op2 %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
 617                (word36) ((rshift_128 (op1, 36).l) & MASK36),
 618                (word36) (op1.l & MASK36),
 619                (word36) (rshift_128 (op2, 36).l & MASK36),
 620                (word36) (op2.l & MASK36),
 621                carryin, flagsToSet, * flags);
 622 #else
 623     sim_debug (DBG_TRACEEXT, & cpu_dev,
 624                "Sub72b op1 %012"PRIo64"%012"PRIo64" op2 %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
 625                (word36) ((op1 >> 36) & MASK36),
 626                (word36) (op1 & MASK36),
 627                (word36) ((op2 >> 36) & MASK36),
 628                (word36) (op2 & MASK36),
 629                carryin, flagsToSet, * flags);
 630 #endif
 631 
 632 // See: https://en.wikipedia.org/wiki/Two%27s_complement
 633 
 634 // AL39:
 635 //
 636 //  If carry indicator ON, then C(A) - C(Y) -> C(A)
 637 //  If carry indicator OFF, then C(A) - C(Y) - 1 -> C(A)
 638 
 639     // 73 bit arithmetic for the above N+1 algorithm
 640 #if defined(NEED_128)
 641     word74 op1e = and_128 (op1, MASK72);
 642     word74 op2e = and_128 (op2, MASK72);
 643 #else
 644     word74 op1e = op1 & MASK72;
 645     word74 op2e = op2 & MASK72;
 646 #endif
 647     // Note that carryin has an inverted sense for borrow
 648 #if defined(NEED_128)
 649     word74 ci = construct_128 (0, carryin ? 0 : 1);
 650 #else
 651     word74 ci = carryin ? 0 : 1;
 652 #endif
 653 
 654     // extend sign bits
 655 #if defined(NEED_128)
 656     if (isnonzero_128 (and_128 (op1e, SIGN72)))
 657       op1e = or_128 (op1e, BIT73);
 658     if (isnonzero_128 (and_128 (op2e, SIGN72)))
 659       op2e = or_128 (op2e, BIT73);
 660 #else
 661     if (op1e & SIGN72)
 662       op1e |= BIT73;
 663     if (op2e & SIGN72)
 664       op2e |= BIT73;
 665 #endif
 666 
 667     // Do the math
 668 #if defined(NEED_128)
 669     sim_debug (DBG_TRACEEXT, & cpu_dev,
 670                "Sub72b op1e %012"PRIo64"%012"PRIo64" op2e %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
 671                (word36) ((rshift_128 (op1e, 36).l) & MASK36),
 672                (word36) (op1e.l & MASK36),
 673                (word36) (rshift_128 (op2e, 36).l & MASK36),
 674                (word36) (op2e.l & MASK36),
 675                carryin, flagsToSet, * flags);
 676 #else
 677     sim_debug (DBG_TRACEEXT, & cpu_dev,
 678                "Sub72b op1e %012"PRIo64"%012"PRIo64" op2e %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
 679                (word36) ((op1e >> 36) & MASK36),
 680                (word36) (op1e & MASK36),
 681                (word36) ((op2e >> 36) & MASK36),
 682                (word36) (op2e & MASK36),
 683                carryin, flagsToSet, * flags);
 684 #endif
 685 #if defined(NEED_128)
 686     word74 res = subtract_128 (subtract_128 (op1e, op2e), ci);
 687 #else
 688     // word74 res = op1e - op2e - ci;
 689     // ubsan
 690     word74 res = (word72) (((word72s) op1e) - ((word72s) op2e) - ((word72s) ci));
 691 #endif
 692 #if defined(NEED_128)
 693     sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n",
 694                (word36) (rshift_128 (res, 36).l & MASK36), (word36) (res.l & MASK36), * flags, * ovf);
 695 #else
 696     sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n",
 697                (word36) ((res >> 36) & MASK36), (word36) (res & MASK36), * flags, * ovf);
 698 #endif
 699 
 700     // Extract the overflow bits
 701 #if defined(NEED_128)
 702     bool r73 = isnonzero_128 (and_128 (res, BIT73));
 703     bool r72 = isnonzero_128 (and_128 (res, SIGN72));
 704 #else
 705     bool r73 = res & BIT73  ? true : false;
 706     bool r72 = res & SIGN72 ? true : false;
 707 #endif
 708 
 709     // Extract the carry bit
 710 #if defined(NEED_128)
 711     bool r74 = isnonzero_128 (and_128 (res, BIT74));
 712 #else
 713     bool r74 = res & BIT74 ? true : false;
 714 #endif
 715 
 716     // Truncate the result
 717 #if defined(NEED_128)
 718     res = and_128 (res, MASK72);
 719 #else
 720     res &= MASK72;
 721 #endif
 722 
 723     // Check for overflow
 724     * ovf = r73 ^ r72;
 725 
 726     // Check for carry
 727     bool cry = r74;
 728 
 729 #if defined(PANEL68)
 730     if (cry) CPT (cpt2L, 28); // carry
 731     if (ovf) CPT (cpt2L, 29); // ovf
 732     if (!res) CPT (cpt2L, 30); // zero
 733     if (res & SIGN36) CPT (cpt2L, 31); // neg
 734 #endif
 735 
 736     if (flagsToSet & I_CARRY)
 737       {
 738         if (cry) // Note inverted logic for subtraction
 739           CLRF (* flags, I_CARRY);
 740         else
 741           SETF (* flags, I_CARRY);
 742       }
 743 
 744     if (chkOVF (cpup) && (flagsToSet & I_OFLOW))
 745       {
 746         if (* ovf)
 747           SETF (* flags, I_OFLOW);      // overflow
 748       }
 749 
 750     if (flagsToSet & I_ZERO)
 751       {
 752 #if defined(NEED_128)
 753         if (isnonzero_128 (res))
 754 #else
 755         if (res)
 756 #endif
 757           CLRF (* flags, I_ZERO);
 758         else
 759           SETF (* flags, I_ZERO);       // zero result
 760       }
 761 
 762     if (flagsToSet & I_NEG)
 763       {
 764 #if defined(NEED_128)
 765         if (isnonzero_128 (and_128 (res, SIGN72)))
 766 #else
 767         if (res & SIGN72)
 768 #endif
 769           SETF (* flags, I_NEG);
 770         else
 771           CLRF (* flags, I_NEG);
 772       }
 773 
 774 #if defined(NEED_128)
 775     sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n",
 776                (word36) (rshift_128 (res, 36).l & MASK36), (word36) (res.l & MASK36), * flags, * ovf);
 777 #else
 778     sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n",
 779                (word36) ((res >> 36) & MASK36), (word36) (res & MASK36), * flags, * ovf);
 780 #endif
 781     return res;
 782   }
 783 
 784 // CANFAULT
 785 word36 compl36(cpu_state_t * cpup, word36 op1, word18 *flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 786 {
 787     CPT (cpt2L, 23); // compl36
 788     //(void)printf("op1 = %"PRIo64" %"PRIo64"\n", op1, (-op1) & DMASK);
 789 
 790     op1 &= DMASK;
 791 
 792     // word36 res = -op1 & DMASK;
 793     // ubsan
 794     word36 res = ((word36) (- ((word36s) op1))) & DMASK;
 795 
 796     * ovf = op1 == MAXNEG;
 797 
 798 #if defined(PANEL68)
 799     if (* ovf) CPT (cpt2L, 29); // ovf
 800     if (!res) CPT (cpt2L, 30); // zero
 801     if (res & SIGN36) CPT (cpt2L, 31); // neg
 802 #endif
 803 
 804     if (chkOVF (cpup) && * ovf)
 805         SETF(*flags, I_OFLOW);
 806 
 807     if (res & SIGN36)
 808         SETF(*flags, I_NEG);
 809     else
 810         CLRF(*flags, I_NEG);
 811 
 812     if (res == 0)
 813         SETF(*flags, I_ZERO);
 814     else
 815         CLRF(*flags, I_ZERO);
 816 
 817     return res;
 818 }
 819 
 820 // CANFAULT
 821 word18 compl18(cpu_state_t * cpup, word18 op1, word18 *flags, bool * ovf)
     /* [previous][next][first][last][top][bottom][index][help] */
 822 {
 823     CPT (cpt2L, 24); // compl18
 824     //(void)printf("op1 = %"PRIo64" %"PRIo64"\n", op1, (-op1) & DMASK);
 825 
 826     op1 &= MASK18;
 827 
 828     // word18 res = -op1 & MASK18;
 829     // ubsan
 830     word18 res = ((word18) (- (word18s) op1)) & MASK18;
 831 
 832     * ovf = op1 == MAX18NEG;
 833 #if defined(PANEL68)
 834     if (* ovf) CPT (cpt2L, 29); // ovf
 835     if (!res) CPT (cpt2L, 30); // zero
 836     if (res & SIGN18) CPT (cpt2L, 31); // neg
 837 #endif
 838 
 839     if (chkOVF (cpup) && * ovf)
 840         SETF(*flags, I_OFLOW);
 841     if (res & SIGN18)
 842         SETF(*flags, I_NEG);
 843     else
 844         CLRF(*flags, I_NEG);
 845 
 846     if (res == 0)
 847         SETF(*flags, I_ZERO);
 848     else
 849         CLRF(*flags, I_ZERO);
 850 
 851     return res;
 852 }
 853 
 854 void copyBytes(int posn, word36 src, word36 *dst)
     /* [previous][next][first][last][top][bottom][index][help] */
 855 {
 856     word36 mask = 0;
 857 
 858     if (posn & 8) // bit 30 - byte 0 - (bits 0-8)
 859         mask |= 0777000000000LL;
 860 
 861     if (posn & 4) // bit 31 - byte 1 - (bits 9-17)
 862         mask |= 0000777000000LL;
 863 
 864     if (posn & 2) // bit 32 - byte 2 - (bits 18-26)
 865         mask |= 0000000777000LL;
 866 
 867     if (posn & 1) // bit 33 - byte 3 - (bits 27-35)
 868         mask |= 0000000000777LL;
 869 
 870     word36 byteVals = src & mask;   // get byte bits
 871 
 872     // clear the bits in dst
 873     *dst &= ~mask;
 874 
 875     // and set the bits in dst
 876     *dst |= byteVals;
 877 }
 878 
 879 void copyChars(int posn, word36 src, word36 *dst)
     /* [previous][next][first][last][top][bottom][index][help] */
 880 {
 881     word36 mask = 0;
 882 
 883     if (posn & 32) // bit 30 - char 0 - (bits 0-5)
 884         mask |= 0770000000000LL;
 885 
 886     if (posn & 16) // bit 31 - char 1 - (bits 6-11)
 887         mask |= 0007700000000LL;
 888 
 889     if (posn & 8) // bit 32 - char 2 - (bits 12-17)
 890         mask |= 0000077000000LL;
 891 
 892     if (posn & 4) // bit 33 - char 3 - (bits 18-23)
 893         mask |= 0000000770000LL;
 894 
 895     if (posn & 2) // bit 34 - char 4 - (bits 24-29)
 896         mask |= 0000000007700LL;
 897 
 898     if (posn & 1) // bit 35 - char 5 - (bits 30-35)
 899         mask |= 0000000000077LL;
 900 
 901     word36 byteVals = src & mask;   // get byte bits
 902 
 903     // clear the bits in dst
 904     *dst &= ~mask;
 905 
 906     // and set the bits in dst
 907     *dst |= byteVals;
 908 }
 909 
 910 /*!
 911  * write 9-bit byte into 36-bit word....
 912  */
 913 void putByte(word36 *dst, word9 data, int posn)
     /* [previous][next][first][last][top][bottom][index][help] */
 914 {
 915     // XXX which is faster switch() or calculation?
 916 
 917 //    int offset = 27 - (9 * posn);//    0;
 918 //    switch (posn)
 919 //    {
 920 //        case 0:
 921 //            offset = 27;
 922 //            break;
 923 //        case 1:
 924 //            offset = 18;
 925 //            break;
 926 //        case 2:
 927 //            offset = 9;
 928 //            break;
 929 //        case 3:
 930 //            offset = 0;
 931 //            break;
 932 //    }
 933     putbits36_9 (dst, (uint) posn * 9, data);
 934 }
 935 
 936 void putChar(word36 *dst, word6 data, int posn)
     /* [previous][next][first][last][top][bottom][index][help] */
 937 {
 938     // XXX which is faster switch() or calculation?
 939 
 940 //    int offset = 30 - (6 * posn);   //0;
 941 //    switch (posn)
 942 //    {
 943 //        case 0:
 944 //            offset = 30;
 945 //            break;
 946 //        case 1:
 947 //            offset = 24;
 948 //            break;
 949 //        case 2:
 950 //            offset = 18;
 951 //            break;
 952 //        case 3:
 953 //            offset = 12;
 954 //            break;
 955 //        case 4:
 956 //            offset = 6;
 957 //            break;
 958 //        case 5:
 959 //            offset = 0;
 960 //            break;
 961 //    }
 962     putbits36_6 (dst, (uint) posn * 6, data);
 963 }
 964 
 965 word72 convert_to_word72(word36 even, word36 odd)
     /* [previous][next][first][last][top][bottom][index][help] */
 966 {
 967 #if defined(NEED_128)
 968     return or_128 (lshift_128 (construct_128 (0, even), 36), construct_128 (0, odd));
 969 #else
 970     return ((word72)even << 36) | (word72)odd;
 971 #endif
 972 }
 973 
 974 void convert_to_word36 (word72 src, word36 *even, word36 *odd)
     /* [previous][next][first][last][top][bottom][index][help] */
 975 {
 976 #if defined(NEED_128)
 977     *even = rshift_128 (src, 36).l & DMASK;
 978     *odd  = src.l & DMASK;
 979 #else
 980     *even = (word36)(src >> 36) & DMASK;
 981     *odd  = (word36)src & DMASK;
 982 #endif
 983 }
 984 
 985 void cmp36(cpu_state_t * cpup, word36 oP1, word36 oP2, word18 *flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 986   {
 987     CPT (cpt2L, 25); // cmp36
 988     L68_ (cpu.ou.cycle |= ou_GOS;)
 989     t_int64 op1 = SIGNEXT36_64(oP1 & DMASK);
 990     t_int64 op2 = SIGNEXT36_64(oP2 & DMASK);
 991 
 992     word36 sign1 = (word36) op1 & SIGN36;
 993     word36 sign2 = (word36) op2 & SIGN36;
 994 
 995     if ((! sign1) && sign2)  // op1 > 0, op2 < 0 :: op1 > op2
 996       CLRF (* flags, I_ZERO | I_NEG | I_CARRY);
 997 
 998     else if (sign1 == sign2) // both operands have the same sign
 999       {
1000          if (op1 > op2)
1001            {
1002              CPT (cpt2L, 28); // carry
1003              SETF (* flags, I_CARRY);
1004              CLRF (* flags, I_ZERO | I_NEG);
1005            }
1006          else if (op1 == op2)
1007            {
1008              CPT (cpt2L, 28); // carry
1009              CPT (cpt2L, 30); // zero
1010              SETF (* flags, I_ZERO | I_CARRY);
1011              CLRF (* flags, I_NEG);
1012            }
1013          else //  op1 < op2
1014           {
1015             CPT (cpt2L, 31); // neg
1016             SETF (* flags, I_NEG);
1017             CLRF (* flags, I_ZERO | I_CARRY);
1018           }
1019       }
1020     else // op1 < 0, op2 > 0 :: op1 < op2
1021       {
1022         CPT  (cpt2L, 28); // carry
1023         CPT  (cpt2L, 31); // neg
1024         SETF (* flags, I_CARRY | I_NEG);
1025         CLRF (* flags, I_ZERO);
1026       }
1027   }
1028 
1029 void cmp18(cpu_state_t * cpup, word18 oP1, word18 oP2, word18 *flags)
     /* [previous][next][first][last][top][bottom][index][help] */
1030   {
1031     CPT (cpt2L, 26); // cmp18
1032     L68_ (cpu.ou.cycle |= ou_GOS;)
1033     int32 op1 = SIGNEXT18_32 (oP1 & MASK18);
1034     int32 op2 = SIGNEXT18_32 (oP2 & MASK18);
1035 
1036     word18 sign1 = (word18) op1 & SIGN18;
1037     word18 sign2 = (word18) op2 & SIGN18;
1038 
1039     if ((! sign1) && sign2)  // op1 > 0, op2 < 0 :: op1 > op2
1040       CLRF (* flags, I_ZERO | I_NEG | I_CARRY);
1041 
1042     else if (sign1 == sign2) // both operands have the same sign
1043       {
1044         if (op1 > op2)
1045           {
1046             CPT (cpt2L, 28); // carry
1047             SETF (* flags, I_CARRY);
1048             CLRF (* flags, I_ZERO | I_NEG);
1049           }
1050         else if (op1 == op2)
1051           {
1052             CPT (cpt2L, 28); // carry
1053             CPT (cpt2L, 30); // zero
1054             SETF (* flags, I_ZERO | I_CARRY);
1055             CLRF (* flags, I_NEG);
1056           }
1057         else //  op1 < op2
1058           {
1059             CPT (cpt2L, 31); // neg
1060             SETF (* flags, I_NEG);
1061             CLRF (* flags, I_ZERO | I_CARRY);
1062           }
1063       }
1064     else // op1 < 0, op2 > 0 :: op1 < op2
1065       {
1066         CPT (cpt2L, 28); // carry
1067         CPT (cpt2L, 31); // neg
1068         SETF (* flags, I_CARRY | I_NEG);
1069         CLRF (* flags, I_ZERO);
1070       }
1071   }
1072 
1073 void cmp36wl(cpu_state_t * cpup, word36 A, word36 Y, word36 Q, word18 *flags)
     /* [previous][next][first][last][top][bottom][index][help] */
1074 {
1075     CPT (cpt2L, 26); // cmp36wl
1076     // This is wrong; signed math is needed.
1077 
1078     //bool Z = (A <= Y && Y <= Q) || (A >= Y && Y >= Q);
1079 
1080     L68_ (cpu.ou.cycle |= ou_GOS;)
1081     t_int64 As = (word36s) SIGNEXT36_64(A & DMASK);
1082     t_int64 Ys = (word36s) SIGNEXT36_64(Y & DMASK);
1083     t_int64 Qs = (word36s) SIGNEXT36_64(Q & DMASK);
1084     bool Z = (As <= Ys && Ys <= Qs) || (As >= Ys && Ys >= Qs);
1085 
1086     SCF(Z, *flags, I_ZERO);
1087 
1088     if (!(Q & SIGN36) && (Y & SIGN36) && (Qs > Ys))
1089         CLRF(*flags, I_NEG | I_CARRY);
1090     else if (((Q & SIGN36) == (Y & SIGN36)) && (Qs >= Ys))
1091     {
1092         CPT (cpt2L, 28); // carry
1093         SETF(*flags, I_CARRY);
1094         CLRF(*flags, I_NEG);
1095     } else if (((Q & SIGN36) == (Y & SIGN36)) && (Qs < Ys))
1096     {
1097         CPT (cpt2L, 31); // neg
1098         CLRF(*flags, I_CARRY);
1099         SETF(*flags, I_NEG);
1100     } else if ((Q & SIGN36) && !(Y & SIGN36) && (Qs < Ys))
1101     {
1102         CPT (cpt2L, 28); // carry
1103         CPT (cpt2L, 31); // neg
1104         SETF(*flags, I_NEG | I_CARRY);
1105     }
1106 }
1107 
1108 void cmp72(cpu_state_t * cpup, word72 op1, word72 op2, word18 *flags)
     /* [previous][next][first][last][top][bottom][index][help] */
1109 {
1110     CPT (cpt2L, 27); // cmp72
1111    // The case of op1 == 400000000000000000000000 and op2 == 0 falls through
1112    // this code.
1113     L68_ (cpu.ou.cycle |= ou_GOS;)
1114 #if defined(NEED_128)
1115 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1 %016"PRIx64"%016"PRIx64"\n", op1.h, op1.l);
1116 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2 %016"PRIx64"%016"PRIx64"\n", op2.h, op2.l);
1117     int128 op1s =  SIGNEXT72_128 (and_128 (op1, MASK72));
1118     int128 op2s =  SIGNEXT72_128 (and_128 (op2, MASK72));
1119 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1s %016"PRIx64"%016"PRIx64"\n", op1s.h, op1s.l);
1120 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2s %016"PRIx64"%016"PRIx64"\n", op2s.h, op2s.l);
1121 #else
1122 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1 %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op1>>64), (uint64_t) op1);
1123 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2 %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op2>>64), (uint64_t) op2);
1124     int128 op1s =  SIGNEXT72_128 (op1 & MASK72);
1125     int128 op2s =  SIGNEXT72_128 (op2 & MASK72);
1126 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1s %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op1s>>64), (uint64_t) op1s);
1127 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2s %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op2s>>64), (uint64_t) op2s);
1128 #endif
1129 #if defined(NEED_128)
1130     if (isgt_s128 (op1s, op2s))
1131 #else
1132     if (op1s > op2s)
1133 #endif
1134       {
1135 #if defined(NEED_128)
1136         if (isnonzero_128 (and_128 (op2, SIGN72)))
1137 #else
1138         if (op2 & SIGN72)
1139 #endif
1140           CLRF (* flags, I_CARRY);
1141         else
1142           {
1143             CPT (cpt2L, 28); // carry
1144             SETF (* flags, I_CARRY);
1145           }
1146         CLRF (* flags, I_ZERO | I_NEG);
1147       }
1148 #if defined(NEED_128)
1149     else if (iseq_128 (cast_128 (op1s), cast_128 (op2s)))
1150 #else
1151     else if (op1s == op2s)
1152 #endif
1153       {
1154         CPT (cpt2L, 28); // carry
1155         CPT (cpt2L, 30); // zero
1156         SETF (* flags, I_CARRY | I_ZERO);
1157         CLRF (* flags, I_NEG);
1158       }
1159     else /* op1s < op2s */
1160       {
1161         CPT (cpt2L, 31); // neg
1162 #if defined(NEED_128)
1163         if (isnonzero_128 (and_128 (op1, SIGN72)))
1164 #else
1165         if (op1 & SIGN72)
1166 #endif
1167           {
1168             CPT (cpt2L, 28); // carry
1169             SETF (* flags, I_CARRY);
1170           }
1171         else
1172           CLRF (* flags, I_CARRY);
1173         CLRF (* flags, I_ZERO);
1174         SETF (* flags, I_NEG);
1175       }
1176 }
1177 
1178 /*
1179  * String utilities ...
1180  */
1181 
1182 char * strlower(char *q)
     /* [previous][next][first][last][top][bottom][index][help] */
1183 {
1184         char *s = q;
1185 
1186         while (*s) {
1187                 if (isupper((unsigned char)*s))
1188                         *s = (char) tolower(*s);
1189                 s++;
1190         }
1191         return q;
1192 }
1193 
1194 /*  state definitions  */
1195 #define STAR    0
1196 #define NOTSTAR 1
1197 #define RESET   2
1198 
1199 int strmask (char * str, char * mask)
     /* [previous][next][first][last][top][bottom][index][help] */
1200 /*!
1201  Tests string 'str' against mask string 'mask'
1202  Returns TRUE if the string matches the mask.
1203 
1204  The mask can contain '?' and '*' wild card characters.
1205  '?' matches any        single character.
1206  '*' matches any number of any characters.
1207 
1208  For example:
1209  strmask("Hello", "Hello");     ---> TRUE
1210  strmask("Hello", "Jello");     ---> FALSE
1211  strmask("Hello", "H*o");       ---> TRUE
1212  strmask("Hello", "H*g");       ---> FALSE
1213  strmask("Hello", "?ello");     ---> TRUE
1214  strmask("Hello", "H????");     ---> TRUE
1215  strmask("H", "H????");         ---> FALSE
1216  */
1217   {
1218     char * sp, * mp, * reset_string, * reset_mask, * sn;
1219     int state;
1220 
1221     sp = str;
1222     mp = mask;
1223 
1224     while (1)
1225       {
1226         switch (* mp)
1227           {
1228             case '\0':
1229               return * sp ? false : true;
1230 
1231             case '?':
1232               sp ++;
1233               mp ++;
1234               break;
1235 
1236             default:
1237               if (* mp == * sp)
1238                 {
1239                   sp ++;
1240                   mp ++;
1241                   break;
1242                 }
1243               else
1244                 {
1245                   return false;
1246                 }
1247 
1248             case '*':
1249               if (* (mp + 1) == '\0')
1250                 {
1251                   return true;
1252                 }
1253               if ((sn = strchr (sp, * (mp + 1))) == NULL)
1254                 {
1255                   return false;
1256                 }
1257 
1258               /* save place -- match rest of string */
1259               /* if fail, reset to here */
1260               reset_mask = mp;
1261               reset_string = sn + 1;
1262 
1263               mp = mp + 2;
1264               sp = sn + 1;
1265               state = NOTSTAR;
1266               while (state == NOTSTAR)
1267                 {
1268                   switch (* mp)
1269                     {
1270                       case '\0':
1271                         if (* sp == '\0')
1272                           return false;
1273                         else
1274                           state = RESET;
1275                         break;
1276                       case '?':
1277                         sp ++;
1278                         mp ++;
1279                         break;
1280                       default:
1281                         if (* mp == * sp)
1282                           {
1283                             sp ++;
1284                             mp ++;
1285                           }
1286                         else
1287                           state = RESET;
1288                         break;
1289                       case '*':
1290                         state = STAR;
1291                         break;
1292                     }
1293                 } // while STATE == NOTSTAR
1294               /* we've reach a new star or should reset to last star */
1295               if (state == RESET)
1296                 {
1297                   sp = reset_string;
1298                   mp = reset_mask;
1299                 }
1300               break;
1301           } // switch (* mp)
1302       } // while (1)
1303 #if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
1304     /*NOTREACHED*/ /* unreachable */
1305     return false;
1306 #endif /* if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) */
1307   }
1308 
1309 
1310 
1311 
1312 
1313 
1314 
1315 
1316 
1317 
1318 
1319 
1320 
1321 
1322 
1323 
1324 
1325 
1326 
1327 
1328 
1329 
1330 
1331 
1332 
1333 
1334 
1335 
1336 
1337 
1338 
1339 
1340 
1341 
1342 
1343 
1344 
1345 
1346 
1347 
1348 
1349 
1350 
1351 
1352 
1353 
1354 
1355 
1356 
1357 
1358 
1359 
1360 
1361 
1362 
1363 
1364 
1365 
1366 
1367 
1368 
1369 
1370 
1371 
1372 
1373 
1374 
1375 
1376 
1377 
1378 
1379 
1380 
1381 
1382 
1383 
1384 
1385 
1386 
1387 
1388 
1389 
1390 
1391 
1392 
1393 
1394 
1395 
1396 
1397 
1398 
1399 
1400 
1401 
1402 
1403 
1404 /*
1405  * Removes the trailing spaces from a string.
1406  */
1407 char *rtrim(char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
1408 {
1409     if (! s)
1410       return s;
1411     int index;
1412 
1413     //for (index = (int)strlen(s) - 1; index >= 0 && (s[index] == ' ' || s[index] == '\t'); index--)
1414     for (index = (int)strlen(s) - 1; index >= 0 && isspace((unsigned char)s[index]); index--)
1415     {
1416         s[index] = '\0';
1417     }
1418     return(s);
1419 }
1420 
1421 char *ltrim(char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
1422 /*
1423  * Removes the leading spaces from a string.
1424  */
1425 {
1426     char *p;
1427     if (s == NULL)
1428         return NULL;
1429 
1430     //for (p = s; (*p == ' ' || *p == '\t') && *p != '\0'; p++)
1431     for (p = s; isspace((unsigned char)*p) && *p != '\0'; p++)
1432         ;
1433 
1434     //strcpy(s, p);
1435     memmove(s, p, strlen(p) + 1);
1436     return(s);
1437 }
1438 
1439 char *trim(char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
1440 {
1441     return ltrim(rtrim(s));
1442 }
1443 
1444 char *
1445 stripquotes(char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
1446 {
1447     if (! s || ! *s)
1448         return s;
1449     /*
1450      char *p;
1451 
1452      while ((p = strchr(s, '"')))
1453      *p = ' ';
1454      strchop(s);
1455 
1456      return s;
1457      */
1458     int nLast = (int)strlen(s) - 1;
1459     // trim away leading/trailing "'s
1460     if (s[0] == '"')
1461         s[0] = ' ';
1462     if (s[nLast] == '"')
1463         s[nLast] = ' ';
1464     return trim(s);
1465 }
1466 
1467 #include <ctype.h>
1468 
1469 // XXX what about config=addr7=123, where clist has a "addr%"?
1470 
1471 // return -2: error; -1: done; >= 0 option found
1472 int cfg_parse (const char * tag, const char * cptr, config_list_t * clist, config_state_t * state, int64_t * result)
     /* [previous][next][first][last][top][bottom][index][help] */
1473   {
1474     if (! cptr)
1475       return -2;
1476     char * start = NULL;
1477     if (! state -> copy)
1478       {
1479         state -> copy            = strdup (cptr);
1480         if (! state->copy)
1481           {
1482             (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1483                            __func__, __FILE__, __LINE__);
1484 #if defined(USE_BACKTRACE)
1485 # if defined(SIGUSR2)
1486             (void)raise(SIGUSR2);
1487             /*NOTREACHED*/ /* unreachable */
1488 # endif /* if defined(SIGUSR2) */
1489 #endif /* if defined(USE_BACKTRACE) */
1490             abort();
1491           }
1492         start                    = state -> copy;
1493         state ->  statement_save = NULL;
1494       }
1495 
1496     int ret = -2; // error
1497 
1498     // grab every thing up to the next semicolon
1499     char * statement;
1500     statement = strtok_r (start, ";", & state -> statement_save);
1501     start = NULL;
1502     if (! statement)
1503       {
1504         ret = -1; // done
1505         goto done;
1506       }
1507 
1508     // extract name
1509     char * name_start = statement;
1510     char * name_save  = NULL;
1511     char * name;
1512     name = strtok_r (name_start, "=", & name_save);
1513     if (! name)
1514       {
1515         sim_printf ("error: %s: can't parse name\n", tag);
1516         goto done;
1517       }
1518 
1519     // lookup name
1520     config_list_t * p = clist;
1521     while (p -> name)
1522       {
1523         if (strcasecmp (name, p -> name) == 0)
1524           break;
1525         p ++;
1526       }
1527     if (! p -> name)
1528       {
1529         sim_printf ("error: %s: don't know name <%s>\n", tag, name);
1530         goto done;
1531       }
1532 
1533     // extract value
1534     char * value;
1535     value = strtok_r (NULL, "", & name_save);
1536     if (! value)
1537       {
1538         // Special case; min>max and no value list
1539         // means that a missing value is ok
1540         if (p -> min > p -> max && ! p -> value_list)
1541           {
1542             return (int) (p - clist);
1543           }
1544         sim_printf ("error: %s: can't parse value\n", tag);
1545         goto done;
1546       }
1547 
1548     // first look to value in the value list
1549     config_value_list_t * v = p -> value_list;
1550     if (v)
1551       {
1552         while (v -> value_name)
1553           {
1554             if (strcasecmp (value, v -> value_name) == 0)
1555               break;
1556             v ++;
1557           }
1558 
1559         // Hit?
1560         if (v -> value_name)
1561           {
1562             * result = v -> value;
1563             return (int) (p - clist);
1564           }
1565       }
1566 
1567     // Must be a number
1568     if (p -> min > p -> max)
1569       {
1570         sim_printf ("error: %s: can't parse value\n", tag);
1571         goto done;
1572       }
1573 
1574     if (strlen (value) == 0)
1575       {
1576          sim_printf ("error: %s: missing value\n", tag);
1577          goto done;
1578       }
1579     char * endptr;
1580     int64_t n = strtoll (value, & endptr, 0);
1581     if (* endptr)
1582       {
1583         sim_printf ("error: %s: can't parse value\n", tag);
1584         goto done;
1585       }
1586 
1587 // XXX small bug; doesn't check for junk after number...
1588     if (n < p -> min || n > p -> max)
1589       {
1590         sim_printf ("error: %s: value out of range\n", tag);
1591         goto done;
1592       }
1593 
1594     * result = n;
1595     return (int) (p - clist);
1596 
1597 done:
1598     FREE (state -> copy);
1599     state -> copy = NULL;
1600     return ret;
1601   }
1602 
1603 void cfg_parse_done (config_state_t * state)
     /* [previous][next][first][last][top][bottom][index][help] */
1604   {
1605     if (state -> copy)
1606       FREE (state -> copy);
1607     state -> copy = NULL;
1608   }
1609 
1610 // strdup with limited C-style escape processing
1611 //
1612 //  strdupesc ("foo\nbar") --> 'f' 'o' 'o' 012 'b' 'a' 'r'
1613 //
1614 //  Handles:
1615 //   \\  backslash
1616 //   \n  newline
1617 //   \t  tab
1618 //   \f  formfeed
1619 //   \r  carriage return
1620 //   \0  null              // doesn't work, commented out.
1621 //
1622 // \\ doesn't seem to work...
1623 //  Also, a scp specific:
1624 //
1625 //   \e  (end simulation)
1626 //
1627 //  the scp parser doesn't handle these very well...
1628 //
1629 //   \_  space
1630 //   \c  comma
1631 //   \s  semicolon
1632 //   \d  dollar
1633 //   \q  double quote
1634 //   \w  <backslash>
1635 //   \z  ^D eof (DECism)
1636 //   \^  caret
1637 //   \x  expect; used by the autoinput parser
1638 //
1639 // And a special case:
1640 //
1641 //   \TZ replaced with the timezone string. Three characters are used
1642 //       to allow for space in the buffer.
1643 //
1644 //  all others silently ignored and left unprocessed
1645 //
1646 
1647 char * strdupesc (const char * str)
     /* [previous][next][first][last][top][bottom][index][help] */
1648   {
1649     char * buf = strdup (str);
1650     if (!buf)
1651       {
1652         (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1653                       __func__, __FILE__, __LINE__);
1654 #if defined(USE_BACKTRACE)
1655 # if defined(SIGUSR2)
1656         (void)raise(SIGUSR2);
1657         /*NOTREACHED*/ /* unreachable */
1658 # endif /* if defined(SIGUSR2) */
1659 #endif /* if defined(USE_BACKTRACE) */
1660         abort();
1661       }
1662     char * p = buf;
1663     while (* p)
1664       {
1665         if (* p != '\\')
1666           {
1667             p ++;
1668             continue;
1669           }
1670         if (p [1] == '\\')           //   \\    backslash
1671           * p = '\\'; //-V1048
1672         else if (p [1] == 'a')       //   \a    ^A
1673           * p = '\001';
1674         else if (p [1] == 'w')       //   \w    backslash
1675           * p = '\\'; //-V1048
1676         else if (p [1] == 'n')       //   \n    newline
1677           * p = '\n';
1678         else if (p [1] == 't')       //  \t    tab
1679           * p = '\t';
1680         else if (p [1] == 'f')       //  \f    formfeed
1681           * p = '\f';
1682         else if (p [1] == 'r')       //  \r    carriage return
1683           * p = '\r';
1684         else if (p [1] == 'e')       //  \e    ^E; Multics escape char.
1685           * p = '\005';
1686         else if (p [1] == '_')       //  \_    space; needed for leading or
1687                                      //        trailing spaces (scp parser
1688                                      //        issue)
1689           * p = ' ';
1690         else if (p [1] == 'c')       //  \c    comma (scp parser issue)
1691           * p = ',';
1692         else if (p [1] == 's')       //  \s    semicolon (scp parser issue)
1693           * p = ';';
1694         else if (p [1] == 'd')       //  \d    dollar sign (scp parser issue)
1695           * p = '$';
1696         else if (p [1] == 'q')       //  \q    double quote (scp parser issue)
1697           * p = '"';
1698         else if (p [1] == 'z')       //  \z    ^D eof (VAXism)
1699           * p = '\004';
1700         else if (p [1] == 'k')       //  \k    caret
1701           * p = '^';
1702         else if (p [1] == 'x')       //  \x    expect
1703           * p = '\030';
1704         else if (p [1] == 'y')       //  \y    expect
1705           * p = '\031';
1706         //else if (p [1] == '0')       //  \0    null; used as end of expect string
1707           //* p = 0;
1708 
1709 
1710 
1711 
1712 
1713 
1714 
1715 
1716 
1717 
1718 
1719 
1720 
1721 
1722 
1723 
1724 
1725         else
1726           {
1727             p ++;
1728             continue;
1729           }
1730         p ++;
1731         memmove (p, p + 1, strlen (p + 1) + 1);
1732       }
1733     return buf;
1734   }
1735 
1736 // Layout of data as read from tape file format
1737 //
1738 //   bits: buffer of bits from tape. The data is
1739 //   packed as 2 36 bit words in 9 eight bit bytes
1740 //     (2 * 36 == 7 * 9)
1741 //   The of the bytes in bits is
1742 //      byte     value
1743 //       0       most significant byte in word 0
1744 //       1       2nd msb in word 0
1745 //       2       3rd msb in word 0
1746 //       3       4th msb in word 0
1747 //       4       upper half is 4 least significant bits in word 0
1748 //               lower half is 4 most significant bit in word 1
1749 //       5       5th to 13th most significant bits in word 1
1750 //       6       ...
1751 //       7       ...
1752 //       8       least significant byte in word 1
1753 //
1754 
1755 // Multics humor: this is idiotic
1756 
1757 // Data conversion routines
1758 //
1759 //  'bits' is the packed bit stream read from the tape
1760 //    it is assumed to start at an even word36 address
1761 //
1762 //   extr36
1763 //     extract the word36 at woffset
1764 //
1765 
1766 static word36 extrASCII36 (uint8 * bits, uint woffset)
     /* [previous][next][first][last][top][bottom][index][help] */
1767   {
1768     uint8 * p = bits + woffset * 4;
1769 
1770     uint64 w;
1771     w  = ((uint64) p [0]) << 27;
1772     w |= ((uint64) p [1]) << 18;
1773     w |= ((uint64) p [2]) << 9;
1774     w |= ((uint64) p [3]);
1775     // mask shouldn't be necessary but is robust
1776     return (word36) (w & MASK36);
1777   }
1778 
1779 // Data conversion routines
1780 //
1781 //  'bits' is the packed bit stream read from the tape
1782 //    it is assumed to start at an even word36 address
1783 //
1784 //   extr36
1785 //     extract the word36 at woffset
1786 //
1787 
1788 word36 extr36 (uint8 * bits, uint woffset)
     /* [previous][next][first][last][top][bottom][index][help] */
1789   {
1790     uint isOdd = woffset % 2;
1791     uint dwoffset = woffset / 2;
1792     uint8 * p = bits + dwoffset * 9;
1793 
1794     uint64 w;
1795     if (isOdd)
1796       {
1797         w  = (((uint64) p [4]) & 0xf) << 32;
1798         w |=  ((uint64) p [5]) << 24;
1799         w |=  ((uint64) p [6]) << 16;
1800         w |=  ((uint64) p [7]) << 8;
1801         w |=  ((uint64) p [8]);
1802       }
1803     else
1804       {
1805         w  =  ((uint64) p [0]) << 28;
1806         w |=  ((uint64) p [1]) << 20;
1807         w |=  ((uint64) p [2]) << 12;
1808         w |=  ((uint64) p [3]) << 4;
1809         w |= (((uint64) p [4]) >> 4) & 0xf;
1810       }
1811     // mask shouldn't be necessary but is robust
1812     return (word36) (w & MASK36);
1813   }
1814 
1815 static void putASCII36 (word36 val, uint8 * bits, uint woffset)
     /* [previous][next][first][last][top][bottom][index][help] */
1816   {
1817     uint8 * p = bits + woffset * 4;
1818     p [0]  = (val >> 27) & 0xff;
1819     p [1]  = (val >> 18) & 0xff;
1820     p [2]  = (val >>  9) & 0xff;
1821     p [3]  = (val      ) & 0xff;
1822   }
1823 
1824 void put36 (word36 val, uint8 * bits, uint woffset)
     /* [previous][next][first][last][top][bottom][index][help] */
1825   {
1826     uint isOdd = woffset % 2;
1827     uint dwoffset = woffset / 2;
1828     uint8 * p = bits + dwoffset * 9;
1829 
1830     if (isOdd)
1831       {
1832         p [4] &=               0xf0;
1833         p [4] |= (val >> 32) & 0x0f;
1834         p [5]  = (val >> 24) & 0xff;
1835         p [6]  = (val >> 16) & 0xff;
1836         p [7]  = (val >>  8) & 0xff;
1837         p [8]  = (val >>  0) & 0xff;
1838         //w  = ((uint64) (p [4] & 0xf)) << 32;
1839         //w |=  (uint64) (p [5]) << 24;
1840         //w |=  (uint64) (p [6]) << 16;
1841         //w |=  (uint64) (p [7]) << 8;
1842         //w |=  (uint64) (p [8]);
1843       }
1844     else
1845       {
1846         p [0]  = (val >> 28) & 0xff;
1847         p [1]  = (val >> 20) & 0xff;
1848         p [2]  = (val >> 12) & 0xff;
1849         p [3]  = (val >>  4) & 0xff;
1850         p [4] &=               0x0f;
1851         p [4] |= (val <<  4) & 0xf0;
1852         //w  =  (uint64) (p [0]) << 28;
1853         //w |=  (uint64) (p [1]) << 20;
1854         //w |=  (uint64) (p [2]) << 12;
1855         //w |=  (uint64) (p [3]) << 4;
1856         //w |= ((uint64) (p [4]) >> 4) & 0xf;
1857       }
1858     // mask shouldn't be necessary but is robust
1859   }
1860 
1861 int extractASCII36FromBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 *wordp)
     /* [previous][next][first][last][top][bottom][index][help] */
1862   {
1863     uint wp = * words_processed; // How many words have been processed
1864 
1865     // 1 dps8m word == 4 bytes
1866 
1867     uint bytes_processed = wp * 4;
1868     if (bytes_processed >= tbc)
1869       return 1;
1870     //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1871 
1872     * wordp = extrASCII36 (bufp, wp);
1873     //if (* wordp & ~MASK36) sim_printf (">>>>>>> extr %012"PRIo64"\n", * wordp);
1874     //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1875     (* words_processed) ++;
1876 
1877     return 0;
1878   }
1879 
1880 int extractWord36FromBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 *wordp)
     /* [previous][next][first][last][top][bottom][index][help] */
1881   {
1882     uint wp = * words_processed; // How many words have been processed
1883 
1884     // 2 dps8m words == 9 bytes
1885 
1886     uint bytes_processed = (wp * 9 + 1) / 2;
1887     if (bytes_processed >= tbc)
1888       return 1;
1889     //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1890 
1891     * wordp = extr36 (bufp, wp);
1892     //if (* wordp & ~MASK36) sim_printf (">>>>>>> extr %012"PRIo64"\n", * wordp);
1893     //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1894     (* words_processed) ++;
1895 
1896     return 0;
1897   }
1898 
1899 int insertASCII36toBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 word)
     /* [previous][next][first][last][top][bottom][index][help] */
1900   {
1901     uint wp = * words_processed; // How many words have been processed
1902 
1903     // 1 dps8m word == 4 bytes
1904 
1905     uint bytes_processed = wp * 4;
1906     if (bytes_processed >= tbc)
1907       return 1;
1908     //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1909 
1910     putASCII36 (word, bufp, wp);
1911     //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1912     (* words_processed) ++;
1913 
1914     return 0;
1915   }
1916 
1917 int insertWord36toBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 word)
     /* [previous][next][first][last][top][bottom][index][help] */
1918   {
1919     uint wp = * words_processed; // How many words have been processed
1920 
1921     // 2 dps8m words == 9 bytes
1922 
1923     uint bytes_processed = (wp * 9 + 1) / 2;
1924     if (bytes_processed >= tbc)
1925       return 1;
1926     //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1927 
1928     put36 (word, bufp, wp);
1929     //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1930     (* words_processed) ++;
1931 
1932     return 0;
1933   }
1934 
1935 #if !defined(NEED_128)
1936 static void print_uint128o_r (uint128 n, char * p)
     /* [previous][next][first][last][top][bottom][index][help] */
1937   {
1938     if (n == 0)
1939       return;
1940 
1941     print_uint128o_r(n / 8, p);
1942     if (p)
1943       {
1944         char s [2];
1945         s [0] = n % 8 + '0';
1946         s [1] = '\0';
1947         strcat (p, s);
1948       }
1949     else
1950       sim_printf("%c", (int) (n%8+0x30));
1951   }
1952 
1953 char * print_int128o (int128 n, char * p)
     /* [previous][next][first][last][top][bottom][index][help] */
1954   {
1955     if (n == 0)
1956       {
1957         if (p)
1958           strcat (p, "0");
1959         else
1960           sim_printf ("0");
1961         return p;
1962       }
1963     print_uint128o_r ((uint128) n, p);
1964     return p;
1965   }
1966 
1967 static void print_uint128_r (uint128 n, char * p)
     /* [previous][next][first][last][top][bottom][index][help] */
1968   {
1969     if (n == 0)
1970       return;
1971 
1972     print_uint128_r(n / 10, p);
1973     if (p)
1974       {
1975         char s [2];
1976         s [0] = n % 10 + '0';
1977         s [1] = '\0';
1978         strcat (p, s);
1979       }
1980     else
1981       sim_printf("%c", (int) (n%10+0x30));
1982   }
1983 
1984 void print_int128 (int128 n, char * p)
     /* [previous][next][first][last][top][bottom][index][help] */
1985   {
1986     if (n == 0)
1987       {
1988         if (p)
1989           strcat (p, "0");
1990         else
1991           sim_printf ("0");
1992         return;
1993       }
1994     if (n < 0)
1995       {
1996         if (p)
1997           strcat (p, "-");
1998         else
1999           sim_printf ("-");
2000         n = -n;
2001       }
2002     print_uint128_r ((uint128) n, p);
2003   }
2004 #endif
2005 
2006 void timespec_diff(struct timespec * start, struct timespec * stop,
     /* [previous][next][first][last][top][bottom][index][help] */
2007                    struct timespec * result)
2008 {
2009     if ((stop->tv_nsec - start->tv_nsec) < 0) {
2010         result->tv_sec = stop->tv_sec - start->tv_sec - 1;
2011         result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000L;
2012     } else {
2013         result->tv_sec = stop->tv_sec - start->tv_sec;
2014         result->tv_nsec = stop->tv_nsec - start->tv_nsec;
2015     }
2016 
2017     return;
2018 }
2019 
2020 
2021 
2022 
2023 
2024 
2025 
2026 
2027 
2028 
2029 
2030 
2031 
2032 
2033 
2034 
2035 
2036 
2037 
2038 
2039 
2040 
2041 
2042 
2043 
2044 
2045 
2046 
2047 
2048 
2049 
2050 
2051 
2052 

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