root/src/dps8/dps8_utils.c

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

DEFINITIONS

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

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