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

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