root/src/dps8/dps8_eis.c

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

DEFINITIONS

This source file includes following definitions.
  1. get4
  2. get6
  3. get9
  4. put4
  5. put6
  6. put9
  7. getCrAR
  8. getMFReg18
  9. getMFReg36
  10. EISWriteCache
  11. EISReadCache
  12. EISWriteIdx
  13. EISReadIdx
  14. EISRead
  15. EISReadPage
  16. EISWritePage
  17. EISget469
  18. EISput469
  19. EISget49
  20. EISgetBitRWN
  21. setupOperandDescriptorCache
  22. setupOperandDescriptor
  23. setupEISoperands
  24. parseAlphanumericOperandDescriptor
  25. parseArgOperandDescriptor
  26. parseNumericOperandDescriptor
  27. parseBitstringOperandDescriptor
  28. cleanupOperandDescriptor
  29. a4bd
  30. s4bd
  31. axbd
  32. abd
  33. awd
  34. sbd
  35. swd
  36. s9bd
  37. asxbd
  38. cmpc
  39. scd
  40. scdr
  41. scm
  42. scmr
  43. xlate
  44. tct
  45. tctr
  46. isGBCDOvp
  47. mlr
  48. mrl
  49. EISloadInputBufferNumeric
  50. EISloadInputBufferAlphnumeric
  51. EISwriteOutputBufferToMemory
  52. writeToOutputBuffer
  53. mopCHT
  54. mopENF
  55. mopIGN
  56. mopINSA
  57. mopINSB
  58. mopINSM
  59. mopINSN
  60. mopINSP
  61. mopLTE
  62. mopMFLC
  63. mopMFLS
  64. mopMORS
  65. mopMVC
  66. mopMSES
  67. mopMVZA
  68. mopMVZB
  69. mopSES
  70. EISgetMop
  71. mopExecutor
  72. mve
  73. mvne
  74. mvt
  75. cmpn
  76. EISwrite4
  77. EISwrite9
  78. EISwrite49
  79. mvn
  80. csl
  81. getBitOffsets
  82. EISgetBitRWNR
  83. csr
  84. sztl
  85. sztr
  86. EISgetBit
  87. cmpb
  88. sign9n
  89. signExt9
  90. load9x
  91. btd
  92. dtb
  93. ad2d
  94. ad3d
  95. sb2d
  96. sb3d
  97. mp2d
  98. mp3d
  99. dv2d
  100. dv3d

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * SPDX-License-Identifier: Multics
   5  * scspell-id: 312e3076-f62e-11ec-a7f3-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * Copyright (c) 2007-2013 Michael Mondy
  10  * Copyright (c) 2012-2016 Harry Reed
  11  * Copyright (c) 2013-2016 Charles Anthony
  12  * Copyright (c) 2015-2016 Craig Ruff
  13  * Copyright (c) 2016 Michal Tomek
  14  * Copyright (c) 2021-2023 The DPS8M Development Team
  15  *
  16  * All rights reserved.
  17  *
  18  * This software is made available under the terms of the ICU
  19  * License, version 1.8.1 or later.  For more details, see the
  20  * LICENSE.md file at the top-level directory of this distribution.
  21  *
  22  * ---------------------------------------------------------------------------
  23  *
  24  * This source file may contain code comments that adapt, include, and/or
  25  * incorporate Multics program code and/or documentation distributed under
  26  * the Multics License.  In the event of any discrepancy between code
  27  * comments herein and the original Multics materials, the original Multics
  28  * materials should be considered authoritative unless otherwise noted.
  29  * For more details and historical background, see the LICENSE.md file at
  30  * the top-level directory of this distribution.
  31  *
  32  * ---------------------------------------------------------------------------
  33  */
  34 
  35 #ifdef EIS_PTR
  36 // Cached operand data...
  37 //  Alphanumeric Operand
  38 //    Address 18 bits  --> DkW
  39 //    CN 3 bits --> DkB
  40 //    TA 2 bits
  41 //    Length 12 bits
  42 //  Numeric Operand
  43 //    Address 18 bits  --> DkW
  44 //    CN 3 bits --> DkB
  45 //    TN 1 bits
  46 //    S  2 bits
  47 //    SF 6 bits
  48 //    Length 6 bits
  49 //  Bit-string Operand
  50 //    Address 18 bits  --> DkW
  51 //    C  2 bits --> DkB
  52 //    B  4 bits --> DkB
  53 //    Length 12 bits
  54 #endif
  55 
  56 #include <ctype.h>
  57 
  58 #include "dps8.h"
  59 #include "dps8_sys.h"
  60 #include "dps8_faults.h"
  61 #include "dps8_scu.h"
  62 #include "dps8_iom.h"
  63 #include "dps8_cable.h"
  64 #include "dps8_cpu.h"
  65 #include "dps8_iefp.h"
  66 #include "dps8_decimal.h"
  67 #include "dps8_ins.h"
  68 #include "dps8_eis.h"
  69 #include "dps8_utils.h"
  70 
  71 #define DBG_CTR cpu.cycleCnt
  72 
  73 //  Restart status
  74 //
  75 //  a6bd   n/a
  76 //  a4bd   n/a
  77 //  a9bd   n/a
  78 //  abd    n/a
  79 //  awd    n/a
  80 //  s4bd   n/a
  81 //  s6bd   n/a
  82 //  s9bd   n/a
  83 //  sbd    n/a
  84 //  swd    n/a
  85 //  cmpc   done
  86 //  scd    done
  87 //  scdr   done
  88 //  scm    done
  89 //  scmr   done
  90 //  tct    done
  91 //  tctr   done
  92 //  mlr    done
  93 //  mrl    done
  94 //  mve
  95 //  mvne
  96 //  mvt    done
  97 //  cmpn
  98 //  mvn
  99 //  csl    done
 100 //  csr    done
 101 //  cmpb
 102 //  btd
 103 //  dtb
 104 //  ad2d
 105 //  ad3d
 106 //  sb2d
 107 //  sb3d
 108 //  mp2d
 109 //  mp3d
 110 //  dv2d
 111 //  dv3d
 112 
 113 // Local optimization
 114 #define ABD_BITS
 115 
 116 // Enable EIS operand setup refactoring code -- crashes Multics late in boot.
 117 //#define EIS_SETUP
 118 
 119 //  EISWriteCache  -- flush the cache
 120 //
 121 //
 122 //  EISWriteIdx (p, n, data, flush); -- write to cache at p->addr [n];
 123 //  EISRead (p) -- read to cache from p->addr
 124 //  EISReadIdx (p, n)  -- read to cache from p->addr[n];
 125 //  EISReadN (p, n, dst) -- read N words to dst;
 126 
 127 //  EISget469 (k, i)
 128 //  EISput469 (k, i, c)
 129 
 130 //  EISget49 (k, *pos, tn) get p->addr[*pos++]
 131 
 132 // AL39, Figure 2-3
 133 static word4 get4 (word36 w, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
 134   {
 135     switch (pos)
 136       {
 137         case 0:
 138           return getbits36_4 (w, 1);
 139 
 140         case 1:
 141           return getbits36_4 (w, 5);
 142 
 143         case 2:
 144           return getbits36_4 (w, 10);
 145 
 146         case 3:
 147           return getbits36_4 (w, 14);
 148 
 149         case 4:
 150           return getbits36_4 (w, 19);
 151 
 152         case 5:
 153           return getbits36_4 (w, 23);
 154 
 155         case 6:
 156           return getbits36_4 (w, 28);
 157 
 158         case 7:
 159           return getbits36_4 (w, 32);
 160 
 161       }
 162     sim_printf ("get4(): How'd we get here?\n");
 163     return 0;
 164 }
 165 
 166 // AL39, Figure 2-4
 167 static word4 get6 (word36 w, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
 168   {
 169     switch (pos)
 170       {
 171         case 0:
 172          return getbits36_6 (w, 0);
 173 
 174         case 1:
 175          return getbits36_6 (w, 6);
 176 
 177         case 2:
 178          return getbits36_6 (w, 12);
 179 
 180         case 3:
 181          return getbits36_6 (w, 18);
 182 
 183         case 4:
 184          return getbits36_6 (w, 24);
 185 
 186         case 5:
 187          return getbits36_6 (w, 30);
 188 
 189       }
 190     sim_printf ("get6(): How'd we get here?\n");
 191     return 0;
 192   }
 193 
 194 // AL39, Figure 2-5
 195 static word9 get9(word36 w, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
 196   {
 197 
 198     switch (pos)
 199       {
 200         case 0:
 201          return getbits36_9 (w, 0);
 202 
 203         case 1:
 204          return getbits36_9 (w, 9);
 205 
 206         case 2:
 207          return getbits36_9 (w, 18);
 208 
 209         case 3:
 210          return getbits36_9 (w, 27);
 211 
 212       }
 213     sim_printf ("get9(): How'd we get here?\n");
 214     return 0;
 215   }
 216 
 217 // AL39, Figure 2-3
 218 static word36 put4 (word36 w, int pos, word4 c)
     /* [previous][next][first][last][top][bottom][index][help] */
 219   {
 220 
 221 // AL-39 pg 13: "The 0 bits at it positions 0, 9, 18, and 27 are forced to be 0
 222 // by the processor on data transfers to main memory ..."
 223 //
 224 // The code uses 5 bit sets for the even bytes to force the 0 writes.
 225 
 226     c &= MASK4;
 227     switch (pos)
 228       {
 229         case 0:
 230           //return setbits36_4 (w, 1, c);
 231           return setbits36_5 (w, 0, c);
 232 
 233         case 1:
 234           return setbits36_4 (w, 5, c);
 235 
 236         case 2:
 237           //return setbits36_4 (w, 10, c);
 238           return setbits36_5 (w, 9, c);
 239 
 240         case 3:
 241           return setbits36_4 (w, 14, c);
 242 
 243         case 4:
 244           //return setbits36_4 (w, 19, c);
 245           return setbits36_5 (w, 18, c);
 246 
 247         case 5:
 248           return setbits36_4 (w, 23, c);
 249 
 250         case 6:
 251           //return setbits36_4 (w, 28, c);
 252           return setbits36_5 (w, 27, c);
 253 
 254         case 7:
 255           return setbits36_4 (w, 32, c);
 256       }
 257     sim_printf ("put4(): How'd we get here?\n");
 258     return 0;
 259   }
 260 
 261 // AL39, Figure 2-4
 262 static word36 put6 (word36 w, int pos, word6 c)
     /* [previous][next][first][last][top][bottom][index][help] */
 263   {
 264     switch (pos)
 265       {
 266         case 0:
 267           //return bitfieldInsert36 (w, c, 30, 6);
 268           return setbits36_6 (w, 0, c);
 269 
 270         case 1:
 271           //`return bitfieldInsert36 (w, c, 24, 6);
 272           return setbits36_6 (w, 6, c);
 273 
 274         case 2:
 275           //return bitfieldInsert36 (w, c, 18, 6);
 276           return setbits36_6 (w, 12, c);
 277 
 278         case 3:
 279           //return bitfieldInsert36 (w, c, 12, 6);
 280           return setbits36_6 (w, 18, c);
 281 
 282         case 4:
 283           //return bitfieldInsert36 (w, c, 6, 6);
 284           return setbits36_6 (w, 24, c);
 285 
 286         case 5:
 287           //return bitfieldInsert36 (w, c, 0, 6);
 288           return setbits36_6 (w, 30, c);
 289 
 290       }
 291     sim_printf ("put6(): How'd we get here?\n");
 292     return 0;
 293   }
 294 
 295 // AL39, Figure 2-5
 296 static word36 put9 (word36 w, int pos, word9 c)
     /* [previous][next][first][last][top][bottom][index][help] */
 297   {
 298 
 299     switch (pos)
 300       {
 301         case 0:
 302           //return bitfieldInsert36 (w, c, 27, 9);
 303           return setbits36_9 (w, 0, c);
 304 
 305         case 1:
 306           //return bitfieldInsert36 (w, c, 18, 9);
 307           return setbits36_9 (w, 9, c);
 308 
 309         case 2:
 310           //return bitfieldInsert36 (w, c, 9, 9);
 311           return setbits36_9 (w, 18, c);
 312 
 313         case 3:
 314           //return bitfieldInsert36 (w, c, 0, 9);
 315           return setbits36_9 (w, 27, c);
 316 
 317       }
 318     sim_printf ("put9(): How'd we get here?\n");
 319     return 0;
 320   }
 321 
 322 /*
 323  * get register value indicated by reg for Address Register operations
 324  * (not for use with address modifications)
 325  */
 326 
 327 static word36 getCrAR (word4 reg)
     /* [previous][next][first][last][top][bottom][index][help] */
 328   {
 329     if (reg == 0)
 330       return 0;
 331 
 332     if (reg & 010) /* Xn */
 333       return cpu.rX [X (reg)];
 334 
 335     switch (reg)
 336       {
 337         case TD_N:
 338           return 0;
 339 
 340         case TD_AU: // C(A)0,17
 341 #ifdef TESTING
 342           HDBGRegAR ("au");
 343 #endif
 344           return GETHI (cpu.rA);
 345 
 346         case TD_QU: //  C(Q)0,17
 347 #ifdef TESTING
 348           HDBGRegAR ("qu");
 349 #endif
 350           return GETHI (cpu.rQ);
 351 
 352         case TD_IC: // C(PPR.IC)
 353           return cpu.PPR.IC;
 354 
 355         case TD_AL: // C(A)18,35
 356 #ifdef TESTING
 357           HDBGRegAR ("al");
 358 #endif
 359           return cpu.rA; // See AL36, Table 4-1
 360 
 361         case TD_QL: // C(Q)18,35
 362 #ifdef TESTING
 363           HDBGRegAR ("ql");
 364 #endif
 365           return cpu.rQ; // See AL36, Table 4-1
 366       }
 367     return 0;
 368   }
 369 
 370 // getMFReg
 371 //  RType reflects the AL-39 R-type and C(op. desc.)32,35 columns
 372 //
 373 //  Table 4-1. R-type Modifiers for REG Fields
 374 //
 375 //                   Meaning as used in:
 376 //
 377 //  Octal  R-type  MF.REG   Indirect operand    C(operand descriptor)32,35
 378 //  Code                    descriptor-pointer
 379 //  00         n       n          n                      IPR
 380 //  01        au      au          au                      au
 381 //  02        qu      qu          qu                      qu
 382 //  03        du     IPR         IPR                      du (a)
 383 //  04        ic      ic          ic                      ic (b)
 384 //  05        al       a (c)      al                       a (c)
 385 //  06        ql       q (c)      ql                       a (c)
 386 //  07        dl     IPR         IPR                     IPR
 387 //  1n        xn      xn          xn                      xn
 388 //
 389 
 390 static word18 getMFReg18 (uint n, bool allowDU, bool allowNIC, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
 391   {
 392     switch (n)
 393       {
 394         case 0: // n
 395           if (! allowNIC)
 396             {
 397               //sim_printf ("getMFReg18 n\n");
 398               *mod_fault |= FR_ILL_MOD;
 399               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 n");
 400             }
 401           return 0;
 402 
 403         case 1: // au
 404 #ifdef TESTING
 405           HDBGRegAR ("au");
 406 #endif
 407           return GETHI (cpu.rA);
 408 
 409         case 2: // qu
 410 #ifdef TESTING
 411           HDBGRegAR ("qu");
 412 #endif
 413           return GETHI (cpu.rQ);
 414 
 415         case 3: // du
 416           // du is a special case for SCD, SCDR, SCM, and SCMR
 417 // XXX needs attention; doesn't work with old code; triggered by
 418 // XXX parseOperandDescriptor;
 419           if (! allowDU)
 420             {
 421 
 422 
 423 
 424 
 425 
 426 
 427 
 428 
 429 
 430 
 431 
 432 
 433               //sim_printf ("getMFReg18 du\n");
 434               *mod_fault |= FR_ILL_MOD;
 435               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 du");
 436             }
 437           return 0;
 438 
 439         case 4: // ic - The ic modifier is permitted in
 440                 // C (od)32,35 only if MFk.RL = 0, that is, if the contents of
 441                 // the register is an address offset, not the designation of
 442                 // a register containing the operand length.
 443                 // Note that AL39 is wrong saying "is permitted in MFk.REG and C(od)32,35". Only C(od)32,35 is correct. cf RJ78
 444           if (! allowNIC)
 445             {
 446               //sim_printf ("getMFReg18 n\n");
 447               *mod_fault |= FR_ILL_MOD;
 448               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 ic");
 449             }
 450           return cpu.PPR.IC;
 451 
 452         case 5: // al / a
 453 #ifdef TESTING
 454           HDBGRegAR ("al/a");
 455 #endif
 456           return GETLO (cpu.rA);
 457 
 458         case 6: // ql / a
 459 #ifdef TESTING
 460           HDBGRegAR ("ql/a");
 461 #endif
 462           return GETLO (cpu.rQ);
 463 
 464         case 7: // dl
 465           *mod_fault |= FR_ILL_MOD;
 466           //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 dl");
 467           return 0;
 468 
 469         case 8:
 470         case 9:
 471         case 10:
 472         case 11:
 473         case 12:
 474         case 13:
 475         case 14:
 476         case 15:
 477           return cpu.rX [n - 8];
 478       }
 479     sim_printf ("getMFReg18(): How'd we get here? n=%d\n", n);
 480     return 0;
 481   }
 482 
 483 static word36 getMFReg36 (uint n, bool allowDU, bool allowNIC, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
 484   {
 485     switch (n)
 486       {
 487         case 0: // n
 488          if (! allowNIC)
 489            {
 490              //sim_printf ("getMFReg36 n\n");
 491              *mod_fault |= FR_ILL_MOD;
 492              //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 n");
 493            }
 494           return 0;
 495         case 1: // au
 496 #ifdef TESTING
 497           HDBGRegAR ("au");
 498 #endif
 499           return GETHI (cpu.rA);
 500 
 501         case 2: // qu
 502 #ifdef TESTING
 503           HDBGRegAR ("qu");
 504 #endif
 505           return GETHI (cpu.rQ);
 506 
 507         case 3: // du
 508           // du is a special case for SCD, SCDR, SCM, and SCMR
 509           if (! allowDU)
 510            *mod_fault |= FR_ILL_MOD;
 511            //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 du");
 512           return 0;
 513 
 514         case 4: // ic - The ic modifier is permitted in MFk.REG and
 515                 // C (od)32,35 only if MFk.RL = 0, that is, if the contents of
 516                 // the register is an address offset, not the designation of
 517                 // a register containing the operand length.
 518                 // Note that AL39 is wrong saying "is permitted in MFk.REG and C(od)32,35". Only C(od)32,35 is correct. cf RJ78
 519           if (! allowNIC)
 520             {
 521               //sim_printf ("getMFReg36 n\n");
 522               *mod_fault |= FR_ILL_MOD;
 523               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 ic");
 524             }
 525           return cpu.PPR.IC;
 526 
 527         case 5: // al / a
 528 #ifdef TESTING
 529           HDBGRegAR ("al/a");
 530 #endif
 531           return cpu.rA;
 532 
 533         case 6: // ql / a
 534 #ifdef TESTING
 535           HDBGRegAR ("ql/a");
 536 #endif
 537             return cpu.rQ;
 538 
 539         case 7: // dl
 540              *mod_fault |= FR_ILL_MOD;
 541              //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 dl");
 542              return 0;
 543 
 544         case 8:
 545         case 9:
 546         case 10:
 547         case 11:
 548         case 12:
 549         case 13:
 550         case 14:
 551         case 15:
 552             return cpu.rX [n - 8];
 553       }
 554     sim_printf ("getMFReg36(): How'd we get here? n=%d\n", n);
 555     return 0;
 556   }
 557 
 558 #define EISADDR_IDX(p) ((p) - cpu.currentEISinstruction.addr)
 559 
 560 static void EISWriteCache (EISaddr * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 561   {
 562     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISWriteCache addr %06o\n", p->cachedAddr);
 563     word3 saveTRR = cpu.TPR.TRR;
 564 
 565     if (p -> cacheValid && p -> cacheDirty)
 566       {
 567         if (p -> mat == viaPR)
 568           {
 569             cpu.TPR.TRR = p -> RNR;
 570             cpu.TPR.TSR = p -> SNR;
 571             cpu.cu.XSF = 0;
 572             if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 573               {
 574                 for (uint i = 0; i < 8; i ++)
 575                   if (p->wordDirty[i])
 576                     {
 577                   sim_debug (DBG_TRACEEXT, & cpu_dev,
 578                              "%s: writeCache (PR) %012"PRIo64"@%o:%06o\n",
 579                              __func__, p -> cachedParagraph [i], p -> SNR, p -> cachedAddr + i);
 580                    }
 581               }
 582 { long eisaddr_idx = EISADDR_IDX (p);
 583 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Write8 TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 584             for (uint i = 0; i < 8; i ++)
 585               if (p->wordDirty[i])
 586                 {
 587                   Write1 (p->cachedAddr+i, p -> cachedParagraph[i], true);
 588                   p->wordDirty[i] = false;
 589                 }
 590           }
 591         else
 592           {
 593             //if (get_addr_mode() == APPEND_mode)
 594               //{
 595             cpu.TPR.TRR = cpu.PPR.PRR;
 596             cpu.TPR.TSR = cpu.PPR.PSR;
 597             cpu.cu.XSF = 0;
 598               //}
 599 
 600             if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 601               {
 602                 for (uint i = 0; i < 8; i ++)
 603                   if (p->wordDirty[i])
 604                     {
 605                   sim_debug (DBG_TRACEEXT, & cpu_dev,
 606                              "%s: writeCache %012"PRIo64"@%o:%06o\n",
 607                              __func__, p -> cachedParagraph [i], cpu.TPR.TSR, p -> cachedAddr + i);
 608                      }
 609               }
 610 { long eisaddr_idx = EISADDR_IDX (p);
 611 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Write8 NO PR TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 612             for (uint i = 0; i < 8; i ++)
 613               if (p->wordDirty[i])
 614                 {
 615                   Write1 (p->cachedAddr+i, p -> cachedParagraph[i], false);
 616                   p->wordDirty[i] = false;
 617                 }
 618           }
 619       }
 620     p -> cacheDirty = false;
 621     cpu.TPR.TRR = saveTRR;
 622   }
 623 
 624 static void EISReadCache (EISaddr * p, word18 address)
     /* [previous][next][first][last][top][bottom][index][help] */
 625   {
 626     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadCache addr %06o\n", address);
 627     word3 saveTRR = cpu.TPR.TRR;
 628 
 629     address &= AMASK;
 630 
 631     word18 paragraphAddress = address & paragraphMask;
 632     //word3 paragraphOffset = address & paragraphOffsetMask;
 633 
 634     if (p -> cacheValid && p -> cachedAddr == paragraphAddress)
 635       {
 636         return;
 637       }
 638 
 639     if (p -> cacheValid && p -> cacheDirty && p -> cachedAddr != paragraphAddress)
 640       {
 641         EISWriteCache (p);
 642       }
 643 
 644     if (p -> mat == viaPR)
 645       {
 646         cpu.TPR.TRR = p -> RNR;
 647         cpu.TPR.TSR = p -> SNR;
 648         cpu.cu.XSF = 0;
 649 { long eisaddr_idx = EISADDR_IDX (p);
 650 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Read8 TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 651         Read8 (paragraphAddress, p -> cachedParagraph, true);
 652 
 653         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 654           {
 655             for (uint i = 0; i < 8; i ++)
 656               sim_debug (DBG_TRACEEXT, & cpu_dev,
 657                          "%s: readCache (PR) %012"PRIo64"@%o:%06o\n",
 658                            __func__, p -> cachedParagraph [i], p -> SNR, paragraphAddress + i);
 659           }
 660       }
 661     else
 662       {
 663         //if (get_addr_mode() == APPEND_mode)
 664           //{
 665         cpu.TPR.TRR = cpu.PPR.PRR;
 666         cpu.TPR.TSR = cpu.PPR.PSR;
 667         cpu.cu.XSF = 0;
 668           //}
 669 
 670 { long eisaddr_idx = EISADDR_IDX (p);
 671 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Read8 NO PR TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 672         Read8 (paragraphAddress, p -> cachedParagraph, false);
 673         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 674           {
 675             for (uint i = 0; i < 8; i ++)
 676               sim_debug (DBG_TRACEEXT, & cpu_dev,
 677                          "%s: readCache %012"PRIo64"@%o:%06o\n",
 678                          __func__, p -> cachedParagraph [i], cpu.TPR.TSR, paragraphAddress + i);
 679           }
 680       }
 681     p -> cacheValid = true;
 682     p -> cacheDirty = false;
 683     for (uint i = 0; i < 8; i ++)
 684       p->wordDirty[i] = false;
 685     p -> cachedAddr = paragraphAddress;
 686     cpu.TPR.TRR = saveTRR;
 687   }
 688 
 689 static void EISWriteIdx (EISaddr *p, uint n, word36 data, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
 690 {
 691 #ifdef EIS_PTR
 692     long eisaddr_idx = EISADDR_IDX (p);
 693 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 694     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISWriteIdx addr %06o n %u\n", cpu.du.Dk_PTR_W[eisaddr_idx], n);
 695     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 696 #else
 697     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISWriteIdx addr %06o n %u\n", p->address, n);
 698     word18 addressN = p -> address + n;
 699 #endif
 700     addressN &= AMASK;
 701 
 702     word18 paragraphAddress = addressN & paragraphMask;
 703     word3 paragraphOffset = addressN & paragraphOffsetMask;
 704 
 705     if (p -> cacheValid && p -> cacheDirty && p -> cachedAddr != paragraphAddress)
 706       {
 707         EISWriteCache (p);
 708       }
 709     if ((! p -> cacheValid) || p -> cachedAddr != paragraphAddress)
 710       {
 711         EISReadCache (p, paragraphAddress);
 712       }
 713     p -> cacheDirty = true;
 714     p -> wordDirty[paragraphOffset] = true;
 715     p -> cachedParagraph [paragraphOffset] = data;
 716     p -> cachedAddr = paragraphAddress;
 717     // This a little brute force; if we fault on the next read, the cached value
 718     // is lost. There might be a way to logic it up so that when the next read
 719     // word offset changes, then we write the cache before doing the read. For
 720     // right now, be pessimistic.
 721     if (flush)
 722       {
 723         EISWriteCache (p);
 724       }
 725 }
 726 
 727 static word36 EISReadIdx (EISaddr * p, uint n)
     /* [previous][next][first][last][top][bottom][index][help] */
 728   {
 729 #ifdef EIS_PTR
 730     long eisaddr_idx = EISADDR_IDX (p);
 731 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 732 
 733     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadIdx addr %06o n %u\n", cpu.du.Dk_PTR_W[eisaddr_idx], n);
 734     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 735 #else
 736     long eisaddr_idx = EISADDR_IDX (p);
 737     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadIdx %ld addr %06o n %u\n", eisaddr_idx, p->address, n);
 738     word18 addressN = p -> address + n;
 739 #endif
 740     addressN &= AMASK;
 741 
 742     word18 paragraphAddress = addressN & paragraphMask;
 743     word3 paragraphOffset = addressN & paragraphOffsetMask;
 744 
 745     if (p -> cacheValid && p -> cachedAddr == paragraphAddress)
 746       {
 747         return p -> cachedParagraph [paragraphOffset];
 748       }
 749     if (p -> cacheValid && p -> cacheDirty)
 750       {
 751         EISWriteCache (p);
 752       }
 753     EISReadCache (p, paragraphAddress);
 754     return p -> cachedParagraph [paragraphOffset];
 755   }
 756 
 757 static word36 EISRead (EISaddr * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 758   {
 759 #ifdef EIS_PTR
 760     long eisaddr_idx = EISADDR_IDX (p);
 761 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 762 
 763     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISRead addr %06o\n", cpu.du.Dk_PTR_W[eisaddr_idx]);
 764 #else
 765     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISRead addr %06o\n", p->address);
 766 #endif
 767     return EISReadIdx (p, 0);
 768   }
 769 
 770 
 771 
 772 
 773 
 774 
 775 
 776 
 777 
 778 
 779 
 780 
 781 
 782 
 783 
 784 
 785 
 786 
 787 static void EISReadPage (EISaddr * p, uint n, word36 * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 788   {
 789 #ifdef EIS_PTR
 790     long eisaddr_idx = EISADDR_IDX (p);
 791 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 792     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 793 #else
 794     word18 addressN = p -> address + n;
 795 #endif
 796     addressN &= AMASK;
 797 
 798     sim_debug (DBG_TRACEEXT, & cpu_dev, "%s addr %06o\n", __func__, addressN);
 799     if ((addressN & PGMK) != 0)
 800       {
 801         sim_warn ("EISReadPage not aligned %06o\n", addressN);
 802         addressN &= (word18) ~PGMK;
 803       }
 804 
 805     word3 saveTRR = cpu.TPR.TRR;
 806 
 807     if (p -> mat == viaPR)
 808       {
 809         cpu.TPR.TRR = p -> RNR;
 810         cpu.TPR.TSR = p -> SNR;
 811         cpu.cu.XSF = 0;
 812         ReadPage (addressN, data, true);
 813 
 814         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 815           {
 816             for (uint i = 0; i < PGSZ; i ++)
 817 #ifdef EIS_PTR
 818               sim_debug (DBG_TRACEEXT, & cpu_dev,
 819                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 820                            __func__, data [i], cpu.TPR.TSR, addressN + i);
 821 #else
 822               sim_debug (DBG_TRACEEXT, & cpu_dev,
 823                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 824                            __func__, data [i], p -> SNR, addressN + i);
 825 #endif
 826           }
 827       }
 828     else
 829       {
 830         //if (get_addr_mode() == APPEND_mode)
 831           //{
 832         cpu.TPR.TRR = cpu.PPR.PRR;
 833         cpu.TPR.TSR = cpu.PPR.PSR;
 834         cpu.cu.XSF = 0;
 835           //}
 836 
 837         ReadPage (addressN, data, false);
 838         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 839           {
 840             for (uint i = 0; i < PGSZ; i ++)
 841               sim_debug (DBG_TRACEEXT, & cpu_dev,
 842                          "%s: %012"PRIo64"@%o:%06o\n",
 843                          __func__, data [i], cpu.TPR.TSR, addressN + i);
 844           }
 845       }
 846     cpu.TPR.TRR = saveTRR;
 847   }
 848 
 849 static void EISWritePage (EISaddr * p, uint n, word36 * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 850   {
 851 #ifdef EIS_PTR
 852     long eisaddr_idx = EISADDR_IDX (p);
 853 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 854     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 855 #else
 856     word18 addressN = p -> address + n;
 857 #endif
 858     addressN &= AMASK;
 859 
 860     sim_debug (DBG_TRACEEXT, & cpu_dev, "%s addr %06o\n", __func__, addressN);
 861     if ((addressN & PGMK) != 0)
 862       {
 863         sim_warn ("EISWritePage not aligned %06o\n", addressN);
 864         addressN &= (uint) ~PGMK;
 865       }
 866 
 867     word3 saveTRR = cpu.TPR.TRR;
 868 
 869     if (p -> mat == viaPR)
 870       {
 871         cpu.TPR.TRR = p -> RNR;
 872         cpu.TPR.TSR = p -> SNR;
 873         cpu.cu.XSF = 0;
 874         WritePage (addressN, data, true);
 875 
 876         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 877           {
 878             for (uint i = 0; i < PGSZ; i ++)
 879 #ifdef EIS_PTR
 880               sim_debug (DBG_TRACEEXT, & cpu_dev,
 881                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 882                            __func__, data [i], cpu.TPR.TSR, addressN + i);
 883 #else
 884               sim_debug (DBG_TRACEEXT, & cpu_dev,
 885                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 886                            __func__, data [i], p -> SNR, addressN + i);
 887 #endif
 888           }
 889       }
 890     else
 891       {
 892         //if (get_addr_mode() == APPEND_mode)
 893           //{
 894         cpu.TPR.TRR = cpu.PPR.PRR;
 895         cpu.TPR.TSR = cpu.PPR.PSR;
 896         cpu.cu.XSF = 0;
 897           //}
 898 
 899         WritePage (addressN, data, false);
 900         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 901           {
 902             for (uint i = 0; i < PGSZ; i ++)
 903               sim_debug (DBG_TRACEEXT, & cpu_dev,
 904                          "%s: %012"PRIo64"@%o:%06o\n",
 905                          __func__, data [i], cpu.TPR.TSR, addressN + i);
 906           }
 907       }
 908     cpu.TPR.TRR = saveTRR;
 909   }
 910 
 911 static word9 EISget469 (int k, uint i)
     /* [previous][next][first][last][top][bottom][index][help] */
 912   {
 913     EISstruct * e = & cpu.currentEISinstruction;
 914 
 915     uint nPos = 4; // CTA9
 916 #ifdef EIS_PTR3
 917     switch (cpu.du.TAk[k-1])
 918 #else
 919     switch (e -> TA [k - 1])
 920 #endif
 921       {
 922         case CTA4:
 923             nPos = 8;
 924             break;
 925 
 926         case CTA6:
 927             nPos = 6;
 928             break;
 929       }
 930 
 931     word18 address = e -> WN [k - 1];
 932     uint nChars = i + e -> CN [k - 1];
 933 
 934     address += nChars / nPos;
 935     uint residue = nChars % nPos;
 936 
 937     PNL (cpu.du.Dk_PTR_W[k-1] = address);
 938 #ifdef EIS_PTR
 939     cpu.du.Dk_PTR_W[k-1] = address;
 940 #else
 941     e -> addr [k - 1].address = address;
 942 #endif
 943     word36 data = EISRead (& e -> addr [k - 1]);    // read it from memory
 944 
 945     word9 c = 0;
 946 #ifdef EIS_PTR3
 947     switch (cpu.du.TAk[k-1])
 948 #else
 949     switch (e -> TA [k - 1])
 950 #endif
 951       {
 952         case CTA4:
 953           c = (word9) get4 (data, (int) residue);
 954           break;
 955 
 956         case CTA6:
 957           c = (word9) get6 (data, (int) residue);
 958           break;
 959 
 960         case CTA9:
 961           c = get9 (data, (int) residue);
 962           break;
 963       }
 964 #ifdef EIS_PTR3
 965     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISGet469 : k: %u TAk %u coffset %u c %o \n", k, cpu.du.TAk[k - 1], residue, c);
 966 #else
 967     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISGet469 : k: %u TAk %u coffset %u c %o \n", k, e -> TA [k - 1], residue, c);
 968 #endif
 969 
 970     return c;
 971   }
 972 
 973 static void EISput469 (int k, uint i, word9 c469)
     /* [previous][next][first][last][top][bottom][index][help] */
 974   {
 975     EISstruct * e = & cpu.currentEISinstruction;
 976 
 977     uint nPos = 4; // CTA9
 978 #ifdef EIS_PTR3
 979     switch (cpu.du.TAk[k-1])
 980 #else
 981     switch (e -> TA [k - 1])
 982 #endif
 983       {
 984         case CTA4:
 985           nPos = 8;
 986           break;
 987 
 988         case CTA6:
 989           nPos = 6;
 990           break;
 991       }
 992 
 993     word18 address = e -> WN [k - 1];
 994     uint nChars = i + e -> CN [k - 1];
 995 
 996     address += nChars / nPos;
 997     uint residue = nChars % nPos;
 998 
 999     PNL (cpu.du.Dk_PTR_W[k-1] = address);
1000 #ifdef EIS_PTR
1001     cpu.du.Dk_PTR_W[k-1] = address;
1002 #else
1003     e -> addr [k - 1].address = address;
1004 #endif
1005     word36 data = EISRead (& e -> addr [k - 1]);    // read it from memory
1006 
1007     word36 w = 0;
1008 #ifdef EIS_PTR3
1009     switch (cpu.du.TAk[k-1])
1010 #else
1011     switch (e -> TA [k - 1])
1012 #endif
1013       {
1014         case CTA4:
1015           w = put4 (data, (int) residue, (word4) c469);
1016           break;
1017 
1018         case CTA6:
1019           w = put6 (data, (int) residue, (word6) c469);
1020           break;
1021 
1022         case CTA9:
1023           w = put9 (data, (int) residue, c469);
1024           break;
1025       }
1026     EISWriteIdx (& e -> addr [k - 1], 0, w, true);
1027   }
1028 
1029 /*
1030  * return a 4- or 9-bit character at memory "*address" and position "*pos".
1031  * Increment pos (and address if necessary)
1032  */
1033 
1034 static word9 EISget49 (EISaddr * p, int * pos, int tn)
     /* [previous][next][first][last][top][bottom][index][help] */
1035   {
1036     int maxPos = tn == CTN4 ? 7 : 3;
1037 
1038     if (* pos > maxPos)        // overflows to next word?
1039       {   // yep....
1040         * pos = 0;        // reset to 1st byte
1041         // bump source to next address
1042 #ifdef EIS_PTR
1043         long eisaddr_idx = EISADDR_IDX (p);
1044 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
1045         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;
1046 #else
1047         p -> address = (p -> address + 1) & AMASK;
1048 #endif
1049         p -> data = EISRead (p);    // read it from memory
1050       }
1051     else
1052       {
1053         p -> data = EISRead (p);   // read data word from memory
1054       }
1055 
1056     word9 c = 0;
1057     switch (tn)
1058       {
1059         case CTN4:
1060           c = get4 (p -> data, * pos);
1061           break;
1062         case CTN9:
1063           c = get9 (p -> data, * pos);
1064           break;
1065       }
1066 
1067     (* pos) ++;
1068     return c;
1069   }
1070 
1071 static bool EISgetBitRWN (EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
1072   {
1073 #ifdef EIS_PTR
1074     long eisaddr_idx = EISADDR_IDX (p);
1075 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
1076 
1077 #endif
1078     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
1079     int baseBitPosn = baseCharPosn + p -> bPos;
1080     baseBitPosn += (int) cpu.du.CHTALLY;
1081 
1082     int bitPosn = baseBitPosn % 36;
1083     int woff = baseBitPosn / 36;
1084 
1085 #ifdef EIS_PTR
1086     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
1087     cpu.du.Dk_PTR_W[eisaddr_idx] += (uint) woff;
1088     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
1089 #else
1090     word18 saveAddr = p -> address;
1091     p -> address += (uint) woff;
1092 #endif
1093 
1094     p -> data = EISRead (p); // read data word from memory
1095 
1096     if (p -> mode == eRWreadBit)
1097       {
1098         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
1099       }
1100     else if (p -> mode == eRWwriteBit)
1101       {
1102         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
1103 
1104         EISWriteIdx (p, 0, p -> data, flush); // write data word to memory
1105       }
1106 
1107     p->last_bit_posn = bitPosn;
1108 
1109 #ifdef EIS_PTR
1110     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
1111 #else
1112     p -> address = saveAddr;
1113 #endif
1114     return p -> bit;
1115   }
1116 
1117 static void setupOperandDescriptorCache (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
1118   {
1119     EISstruct * e = & cpu.currentEISinstruction;
1120     e -> addr [k - 1]. cacheValid = false;
1121   }
1122 
1123 //
1124 // 5.2.10.5  Operand Descriptor Address Preparation Flowchart
1125 //
1126 // A flowchart of the operations involved in operand descriptor address
1127 // preparation is shown in Figure 5-2. The chart depicts the address
1128 // preparation for operand descriptor 1 of a multiword instruction as described
1129 // by modification field 1 (MF1). A similar type address preparation would be
1130 // carried out for each operand descriptor as specified by its MF code.
1131 //    (Bull Nova 9000 pg 5-40  67 A2 RJ78 REV02)
1132 //
1133 // 1. The multiword instruction is obtained from memory.
1134 //
1135 // 2. The indirect (ID) bit of MF1 is queried to determine if the descriptor
1136 // for operand 1 is present or is an indirect word.
1137 //
1138 // 3. This step is reached only if an indirect word was in the operand
1139 // descriptor location. Address modification for the indirect word is now
1140 // performed. If the AR bit of the indirect word is 1, address register
1141 // modification step 4 is performed.
1142 //
1143 // 4. The y field of the indirect word is added to the contents of the
1144 // specified address register.
1145 //
1146 // 5. A check is now made to determine if the REG field of the indirect word
1147 // specifies that a register type modification be performed.
1148 //
1149 // 6. The indirect address as modified by the address register is now modified
1150 // by the contents of the specified register, producing the effective address
1151 // of the operand descriptor.
1152 //
1153 // 7. The operand descriptor is obtained from the location determined by the
1154 // generated effective address in item 6.
1155 //
1156 
1157 static void setupOperandDescriptor (int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1158   {
1159     EISstruct * e = & cpu.currentEISinstruction;
1160     switch (k)
1161       {
1162         case 1:
1163           PNL (L68_ (DU_CYCLE_FA_I1;))
1164           PNL (L68_ (DU_CYCLE_GDLDA;))
1165           e -> MF1 = getbits36_7 (cpu.cu.IWB, 29);
1166           break;
1167         case 2:
1168           PNL (L68_ (DU_CYCLE_FA_I2;))
1169           PNL (L68_ (DU_CYCLE_GDLDB;))
1170           e -> MF2 = getbits36_7 (cpu.cu.IWB, 11);
1171           break;
1172         case 3:
1173           PNL (L68_ (DU_CYCLE_FA_I3;))
1174           PNL (L68_ (DU_CYCLE_GDLDC;))
1175           e -> MF3 = getbits36_7 (cpu.cu.IWB,  2);
1176           break;
1177       }
1178 
1179     word18 MFk = e -> MF [k - 1];
1180 
1181     if (MFk & MFkID)
1182     {
1183         PNL (L68_ (if (k == 1)
1184                      DU_CYCLE_LDWRT1;
1185                    if (k == 2)
1186                      DU_CYCLE_LDWRT2;))
1187 
1188         word36 opDesc = e -> op [k - 1];
1189 
1190 // 18-28 MBZ check breaks Multics; line 161 of sys_trouble.alm contains
1191 //
1192 // 000103 aa 040100 1006 20    160   mlr     (id),(pr),fill(040) copy error message
1193 // 000104 0a 000126 0002 05    161   arg     trouble_messages-1,al
1194 // 000105 aa 300063 200063     162   desc9a  bb|fgbx.message+3(1),64-13
1195 //
1196 // bit 28 of 000104 is set
1197 //
1198 
1199 
1200 
1201 
1202 
1203 
1204 
1205 
1206 
1207 
1208 
1209 
1210 
1211 
1212 
1213 
1214 
1215 
1216 
1217 
1218 
1219 
1220         // Bits 30, 31 MBZ
1221         // RJ78 p. 5-39, ISOLTS 840 07a,07b
1222         if (opDesc & 060)
1223           {
1224             *mod_fault |= FR_ILL_MOD;
1225             //doFault (FAULT_IPR, fst_ill_mod, "setupOperandDescriptor 30,31 MBZ");
1226           }
1227 
1228         // fill operand according to MFk....
1229         word18 address = GETHI (opDesc);
1230         PNL (cpu.du.Dk_PTR_W[k-1] = address);
1231 #ifdef EIS_PTR
1232         cpu.du.Dk_PTR_W[k-1] = address;
1233 #else
1234         e -> addr [k - 1].address = address;
1235 #endif
1236 
1237         // Indirect descriptor control. If ID = 1 for Mfk, then the kth word
1238         // following the instruction word is an indirect pointer to the operand
1239         // descriptor for the kth operand; otherwise, that word is the operand
1240         // descriptor.
1241         //
1242         // If MFk.ID = 1, then the kth word following an EIS multiword
1243         // instruction word is not an operand descriptor, but is an indirect
1244         // pointer to an operand descriptor and is interpreted as shown in
1245         // Figure 4-5.
1246 
1247         // Mike Mondy michael.mondy@coffeebird.net sez' ...
1248         // EIS indirect pointers to operand descriptors use PR registers.
1249         // However, operand descriptors use AR registers according to the
1250         // description of the AR registers and the description of EIS operand
1251         // descriptors. However, the description of the MF field
1252         // claims that operands use PR registers. The AR doesn't have a
1253         // segment field. Emulation confirms that operand descriptors
1254         // need to be fetched via segments given in PR registers.
1255 
1256         bool a = opDesc & (1 << 6);
1257         if (a)
1258           {
1259             // A 3-bit pointer register number (n) and a 15-bit offset relative
1260             // to C(PRn.WORDNO) if A = 1 (all modes)
1261             word3 n = (word3) getbits18 (address, 0, 3);
1262             CPTUR (cptUsePRn + n);
1263             word15 offset = address & MASK15;  // 15-bit signed number
1264             address = (cpu.AR [n].WORDNO + SIGNEXT15_18 (offset)) & AMASK;
1265 
1266             PNL (cpu.du.Dk_PTR_W[k-1] = address);
1267 #ifdef EIS_PTR
1268             cpu.du.Dk_PTR_W[k-1] = address;
1269 #else
1270             e -> addr [k - 1].address = address;
1271 #endif
1272             cpu.cu.TSN_PRNO[k-1] = n;
1273             cpu.cu.TSN_VALID[k-1] = 1;
1274             e -> addr [k - 1].SNR = cpu.PR [n].SNR;
1275             e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR,
1276                                             cpu.TPR.TRR,
1277                                             cpu.PPR.PRR);
1278 
1279             e -> addr [k - 1].mat = viaPR;   // ARs involved
1280 sim_debug (DBG_TRACEEXT, & cpu_dev, "AR n %u k %u\n", n, k - 1);
1281           }
1282         else
1283           {
1284             e->addr [k - 1].mat = OperandRead;      // no ARs involved yet
1285 sim_debug (DBG_TRACEEXT, & cpu_dev, "No ARb %u\n", k - 1);
1286           }
1287 
1288         // Address modifier for ADDRESS. All register modifiers except du and
1289         // dl may be used. If the ic modifier is used, then ADDRESS is an
1290         // 18-bit offset relative to value of the instruction counter for the
1291         // instruction word. C(REG) is always interpreted as a word offset. REG
1292 
1293         uint reg = opDesc & 017;
1294         // XXX RH03/RJ78 say a,q modifiers are also available here. AL39 says al/ql only
1295         address += getMFReg18 (reg, false, true, mod_fault); // ID=1: disallow du, allow n,ic
1296         address &= AMASK;
1297 
1298         PNL (cpu.du.Dk_PTR_W[k-1] = address);
1299 
1300 #ifdef EIS_PTR
1301         cpu.du.Dk_PTR_W[k-1] = address;
1302 #else
1303         e -> addr [k - 1].address = address;
1304 #endif
1305 
1306         // read EIS operand .. this should be an indirectread
1307         e -> op [k - 1] = EISRead (& e -> addr [k - 1]);
1308     }
1309     else
1310     {
1311           e->addr [k - 1].mat = OperandRead;      // no ARs involved yet
1312 sim_debug (DBG_TRACEEXT, & cpu_dev, "No ARa %u\n", k - 1);
1313     }
1314     setupOperandDescriptorCache (k);
1315 }
1316 
1317 void setupEISoperands (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1318   {
1319     PNL (cpu.du.POP = 0);
1320     PNL (cpu.du.POL = 0);
1321 
1322 #ifdef EIS_SETUP
1323     for (int i = 0; i < 3; i ++)
1324       {
1325         if (i < cpu.currentInstruction.info -> ndes)
1326           setupOperandDescriptor (i + 1);
1327         else
1328           setupOperandDescriptorCache (i + 1);
1329       }
1330 #endif
1331   }
1332 
1333 static void parseAlphanumericOperandDescriptor (uint k, uint useTA, bool allowDU, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1334   {
1335     EISstruct * e = & cpu.currentEISinstruction;
1336     word18 MFk = e -> MF [k - 1];
1337 
1338     PNL (L68_ (if (k == 1)
1339       DU_CYCLE_ANLD1;
1340     else if (k == 2)
1341       DU_CYCLE_ANLD2;
1342     else if (k == 3)
1343       DU_CYCLE_ANSTR;))
1344 
1345     PNL (cpu.du.POP = 1);
1346 
1347     word36 opDesc = e -> op [k - 1];
1348 
1349     word8 ARn_CHAR = 0;
1350     word6 ARn_BITNO = 0;
1351 
1352     word18 address = GETHI (opDesc);
1353 
1354 #ifdef EIS_PTR3
1355     if (useTA != k)
1356       cpu.du.TAk[k-1] = cpu.du.TAk[useTA-1];
1357     else
1358       cpu.du.TAk[k-1] = getbits36_2 (opDesc, 21);    // type alphanumeric
1359 #else
1360     if (useTA != k)
1361       e -> TA [k - 1] = e -> TA [useTA - 1];
1362     else
1363       e -> TA [k - 1] = getbits36_2 (opDesc, 21);    // type alphanumeric
1364 #endif
1365 
1366 #ifdef PANEL68
1367     if (k == 1) // Use data from first operand
1368       {
1369         switch (e->TA[0])
1370           {
1371             case CTA9:
1372               cpu.dataMode = 0102; // 9 bit an
1373               cpu.ou.opsz = is_9 >> 12;
1374               break;
1375             case CTA6:
1376               cpu.dataMode = 0042; // 6 bit an
1377               cpu.ou.opsz = is_6 >> 12;
1378               break;
1379             case CTA4:
1380               cpu.dataMode = 0022; // 4 bit an
1381               cpu.ou.opsz = is_4 >> 12;
1382               break;
1383           }
1384       }
1385 #endif
1386 
1387 // 8. Modification of the operand descriptor address begins. This step is
1388 // reached directly from 2 if no indirection is involved. The AR bit of MF1 is
1389 // checked to determine if address register modification is specified.
1390 //
1391 // 9. Address register modification is performed on the operand descriptor as
1392 // described under "Address Modification with Address Registers" above. The
1393 // character and bit positions of the specified address register are used in
1394 // one of two ways, depending on the type of operand descriptor, i.e., whether
1395 // the type is a bit string, a numeric, or an alphanumeric descriptor.
1396 //
1397 // 10. The REG field of MF1 is checked for a legal code. If DU is specified in
1398 // the REG field of MF2 in one of the four multiword instructions (SCD, SCDR,
1399 // SCM, or SCMR) for which DU is legal, the CN field is ignored and the
1400 // character or characters are arranged within the 18 bits of the word address
1401 // portion of the operand descriptor.
1402 //
1403 // 11. The count contained in the register specified by the REG field code is
1404 // appropriately converted and added to the operand address.
1405 //
1406 // 12. The operand is retrieved from the calculated effective address location.
1407 //
1408 
1409     if (MFk & MFkAR)
1410       {
1411         // if MKf contains ar then it Means Y-charn is not the memory address
1412         // of the data but is a reference to a pointer register pointing to the
1413         // data.
1414         word3 n = (word3) getbits18 (address, 0, 3);
1415         CPTUR (cptUsePRn + n);
1416         word18 offset = SIGNEXT15_18 ((word15) address);  // 15-bit signed number
1417         address = (cpu.AR [n].WORDNO + offset) & AMASK;
1418 
1419         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1420         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1421 
1422         cpu.cu.TSN_PRNO[k-1] = n;
1423         cpu.cu.TSN_VALID[k-1] = 1;
1424         e -> addr [k - 1].SNR = cpu.PR [n].SNR;
1425         e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1426 
1427         e -> addr [k - 1].mat = viaPR;   // ARs involved
1428 sim_debug (DBG_TRACEEXT, & cpu_dev, "AR n %u k %u\n", n, k - 1);
1429       }
1430 
1431     PNL (cpu.du.POL = 1);
1432 
1433     uint CN = getbits36_3 (opDesc, 18);    // character number
1434 
1435     sim_debug (DBG_TRACEEXT, & cpu_dev, "initial CN%u %u\n", k, CN);
1436 
1437     if (MFk & MFkRL)
1438     {
1439         uint reg = opDesc & 017;
1440 // XXX Handle N too big intelligently....
1441         e -> N [k - 1] = (uint) getMFReg36 (reg, false, false, mod_fault); // RL=1: disallow du,n,ic
1442 #ifdef EIS_PTR3
1443         switch (cpu.du.TAk[k-1])
1444 #else
1445         switch (e -> TA [k - 1])
1446 #endif
1447           {
1448             case CTA4:
1449               e -> N [k - 1] &= 017777777; // 22-bits of length
1450               break;
1451 
1452             case CTA6:
1453             case CTA9:
1454               e -> N [k - 1] &= 07777777;  // 21-bits of length.
1455               break;
1456 
1457             default:
1458               L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TA 3");)
1459               // DPS8M
1460               *mod_fault |= FR_ILL_PROC;
1461               break;
1462           }
1463       }
1464     else
1465       e -> N [k - 1] = opDesc & 07777;
1466 
1467     //if (e->N [k - 1] == 0)
1468       //doFault (FAULT_IPR, FR_ILL_PROC, "parseAlphanumericOperandDescriptor N 0");
1469 
1470     sim_debug (DBG_TRACEEXT, & cpu_dev, "N%u %o\n", k, e->N[k-1]);
1471 
1472     word36 r = getMFReg36 (MFk & 017, allowDU, true, mod_fault); // allow du based on instruction, allow n,ic
1473 
1474     if ((MFk & 017) == 4)   // reg == IC ?
1475       {
1476         address += r;
1477         address &= AMASK;
1478         r = 0;
1479       }
1480 
1481     // If seems that the effect address calcs given in AL39 p.6-27 are not
1482     // quite right. E.g. For CTA4/CTN4 because of the 4 "slop" bits you need
1483     // to do 32-bit calcs not 36-bit!
1484     uint effBITNO = 0;
1485     uint effCHAR = 0;
1486     uint effWORDNO = 0;
1487 
1488 #ifdef EIS_PTR3
1489     switch (cpu.du.TAk[k-1])
1490 #else
1491     switch (e -> TA [k - 1])
1492 #endif
1493       {
1494         case CTA4:
1495           {
1496             // Calculate character number of ARn CHAR and BITNO
1497             uint bitoffset = ARn_CHAR * 9u + ARn_BITNO;
1498             uint arn_char4 = bitoffset * 2 / 9; // / 4.5
1499             // 8 chars per word plus the number of chars in r, plus the
1500             // number of chars in ARn CHAR/BITNO plus the CN from the operand
1501 // XXX Handle 'r' too big intelligently...
1502             uint nchars = address * 8 + (uint) r + arn_char4 + CN;
1503 
1504             effWORDNO = nchars / 8; // 8 chars/word
1505             effCHAR = nchars % 8; // effCHAR is the 4 bit char number, not
1506                                   // the 9-bit char no
1507             effBITNO = (nchars & 1) ? 5 : 0;
1508 
1509             effWORDNO &= AMASK;
1510 
1511             e -> CN [k - 1] = effCHAR;
1512             e -> WN [k - 1] = effWORDNO;
1513 
1514             sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA4\n",
1515                        k, e -> CN [k - 1]);
1516           }
1517           break;
1518 
1519         case CTA6:
1520           if (CN >= 6) {
1521             L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TAn CTA6 CN >= 6");)
1522             // DPS8M
1523             *mod_fault |= FR_ILL_PROC;
1524           }
1525           effBITNO = (9u * ARn_CHAR + 6u * r + ARn_BITNO) % 9u;
1526           effCHAR = ((6u * CN +
1527                       9u * ARn_CHAR +
1528                       6u * r + ARn_BITNO) % 36u) / 6u;//9;
1529           effWORDNO = (uint) (address +
1530                            (6u * CN +
1531                             9u * ARn_CHAR +
1532                             6u * r +
1533                             ARn_BITNO) / 36u);
1534           effWORDNO &= AMASK;
1535 
1536           e -> CN [k - 1] = effCHAR;   // ??????
1537           e -> WN [k - 1] = effWORDNO;
1538           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA6\n",
1539                      k, e -> CN [k - 1]);
1540           break;
1541 
1542         case CTA9:
1543           if (CN & 01) {
1544             L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor CTA9 & CN odd");)
1545             // DPS8M
1546             *mod_fault |= FR_ILL_PROC;
1547           }
1548           CN = (CN >> 1);
1549 
1550           effBITNO = 0;
1551           effCHAR = (CN + ARn_CHAR + r) % 4;
1552           sim_debug (DBG_TRACEEXT, & cpu_dev,
1553                      "effCHAR %d = (CN %d + ARn_CHAR %d + r %"PRId64") %% 4)\n",
1554                      effCHAR, CN, ARn_CHAR, r);
1555           effWORDNO = (uint) (address +
1556                            ((9u * CN +
1557                              9u * ARn_CHAR +
1558                              9u * r +
1559                              ARn_BITNO) / 36u));
1560           effWORDNO &= AMASK;
1561 
1562           e -> CN [k - 1] = effCHAR;   // ??????
1563           e -> WN [k - 1] = effWORDNO;
1564           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA9\n",
1565                      k, e -> CN [k - 1]);
1566           break;
1567 
1568         default:
1569           L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TA1 3");)
1570           // DPS8M
1571           *mod_fault |= FR_ILL_PROC;
1572           break;
1573     }
1574 
1575     EISaddr * a = & e -> addr [k - 1];
1576     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1577 #ifdef EIS_PTR
1578     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1579 #else
1580     a -> address = effWORDNO;
1581 #endif
1582     a -> cPos= (int) effCHAR;
1583     a -> bPos = (int) effBITNO;
1584 
1585 #ifndef EIS_PTR3
1586     // a->_type = eisTA;
1587     a -> TA = (int) e -> TA [k - 1];
1588 #endif
1589   }
1590 
1591 static void parseArgOperandDescriptor (uint k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1592   {
1593     PNL (L68_ (if (k == 1)
1594       DU_CYCLE_NLD1;
1595     else if (k == 2)
1596       DU_CYCLE_NLD2;
1597     else if (k == 3)
1598       DU_CYCLE_GSTR;))
1599 
1600     EISstruct * e = & cpu.currentEISinstruction;
1601     word36 opDesc = e -> op [k - 1];
1602     word18 y = GETHI (opDesc);
1603     word1 yA = GET_A (opDesc);
1604 
1605     uint yREG = opDesc & 0xf;
1606 
1607     word36 r = getMFReg36 (yREG, false, true, mod_fault); // disallow du, allow n,ic
1608 
1609     word8 ARn_CHAR = 0;
1610     word6 ARn_BITNO = 0;
1611 
1612     PNL (cpu.du.POP = 1);
1613 
1614     if (yA)
1615       {
1616         // if operand contains A (bit-29 set) then it Means Y-char9n is not
1617         // the memory address of the data but is a reference to a pointer
1618         // register pointing to the data.
1619         word3 n = GET_ARN (opDesc);
1620         CPTUR (cptUsePRn + n);
1621         word15 offset = y & MASK15;  // 15-bit signed number
1622         y = (cpu.AR [n].WORDNO + SIGNEXT15_18 (offset)) & AMASK;
1623 
1624         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1625         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1626 
1627         cpu.cu.TSN_PRNO[k-1] = n;
1628         cpu.cu.TSN_VALID[k-1] = 1;
1629         e -> addr [k - 1].SNR = cpu.PR[n].SNR;
1630         e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1631         e -> addr [k - 1].mat = viaPR;
1632       }
1633 
1634     y += ((9u * ARn_CHAR + 36u * r + ARn_BITNO) / 36u);
1635     y &= AMASK;
1636 
1637     PNL (cpu.du.Dk_PTR_W[k-1] = y);
1638 
1639 #ifdef EIS_PTR
1640     cpu.du.Dk_PTR_W[k-1] = y;
1641 #else
1642     e -> addr [k - 1].address = y;
1643 #endif
1644   }
1645 
1646 static void parseNumericOperandDescriptor (int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1647 {
1648     PNL (L68_ (if (k == 1)
1649       DU_CYCLE_NLD1;
1650     else if (k == 2)
1651       DU_CYCLE_NLD2;
1652     else if (k == 3)
1653       DU_CYCLE_GSTR;))
1654 
1655     EISstruct * e = & cpu.currentEISinstruction;
1656     word18 MFk = e->MF[k-1];
1657 
1658     PNL (cpu.du.POP = 1);
1659 
1660     word36 opDesc = e->op[k-1];
1661 
1662     word8 ARn_CHAR = 0;
1663     word6 ARn_BITNO = 0;
1664 
1665     word18 address = GETHI(opDesc);
1666     if (MFk & MFkAR)
1667     {
1668         // if MKf contains ar then it Means Y-charn is not the memory address
1669         // of the data but is a reference to a pointer register pointing to the
1670         // data.
1671         word3 n = (word3) getbits18 (address, 0, 3);
1672         CPTUR (cptUsePRn + n);
1673         word15 offset = address & MASK15;  // 15-bit signed number
1674         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1675 
1676         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1677         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1678 
1679         cpu.cu.TSN_PRNO[k-1] = n;
1680         cpu.cu.TSN_VALID[k-1] = 1;
1681         e->addr[k-1].SNR = cpu.PR[n].SNR;
1682         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1683 
1684         e->addr[k-1].mat = viaPR;   // ARs involved
1685     }
1686 
1687     PNL (cpu.du.POL = 1);
1688 
1689     word3 CN = getbits36_3 (opDesc, 18);    // character number
1690     e->TN[k-1] = getbits36_1 (opDesc, 21); // type numeric
1691 
1692 #ifdef PANEL68
1693     if (k == 1)
1694       {
1695         if (e->TN[0])
1696           cpu.dataMode = 0021; // 4 bit numeric
1697         else
1698           cpu.dataMode = 0101; // 9 bit numeric
1699       }
1700 #endif
1701 
1702     e->S[k-1]  = getbits36_2 (opDesc, 22);    // Sign and decimal type of data
1703     e->SF[k-1] = SIGNEXT6_int (getbits36_6 (opDesc, 24));    // Scaling factor.
1704 
1705     // Operand length. If MFk.RL = 0, this field contains the operand length in
1706     // digits. If MFk.RL = 1, it contains the REG code for the register holding
1707     // the operand length and C(REG) is treated as a 0 modulo 64 number. See
1708     // Table 4-1 and EIS modification fields (MF) above for a discussion of
1709     // register codes.
1710 
1711     if (MFk & MFkRL)
1712     {
1713         uint reg = opDesc & 017;
1714         e->N[k-1] = getMFReg18(reg, false, false, mod_fault) & 077; // RL=1: disallow du,n,ic
1715     }
1716     else
1717         e->N[k-1] = opDesc & 077;
1718 
1719     sim_debug (DBG_TRACEEXT, & cpu_dev, "parseNumericOperandDescriptor(): N%u %0o\n", k, e->N[k-1]);
1720 
1721     word36 r = getMFReg36(MFk & 017, false, true, mod_fault); // disallow du, allow n, ic
1722     if ((MFk & 017) == 4)   // reg == IC ?
1723     {
1724         address += r;
1725         address &= AMASK;
1726         r = 0;
1727     }
1728 
1729 // handled in numeric instructions
1730 
1731 
1732 
1733 
1734 
1735 
1736 
1737 
1738 
1739 
1740 // Causes:
1741 //DBG(662088814)> CPU0 FAULT: Fault 10(012), sub 4294967296(040000000000), dfc N, 'parseNumericOperandDescriptor N=1 S=0|1|2'
1742 //DBG(662088814)> CPU0 FAULT: 00257:004574 bound_process_env_:command_query_+04574
1743 //DBG(662088814)> CPU0 FAULT:       664 end print_question;
1744 //DBG(662088814)> CPU0 FAULT: 00257:004574 4 000100301500 (BTD PR0|100) 000100 301(1) 0 0 0 00
1745 
1746     uint effBITNO = 0;
1747     uint effCHAR = 0;
1748     uint effWORDNO = 0;
1749 
1750     // If seems that the effect address calcs given in AL39 p.6-27 are not
1751     // quite right.
1752     // E.g. For CTA4/CTN4 because of the 4 "slop" bits you need to do 32-bit
1753     // calcs not 36-bit!
1754 
1755     switch (e->TN[k-1])
1756     {
1757         case CTN4:
1758           {
1759             // Calculate character number of ARn CHAR and BITNO
1760             uint bitoffset = ARn_CHAR * 9u + ARn_BITNO;
1761             uint arn_char4 = bitoffset * 2u / 9u; // / 4.5
1762             //// The odd chars start at the 6th bit, not the 5th
1763             //if (bitoffset & 1) // if odd
1764             //  arn_char4 ++;
1765             // 8 chars per word plus the number of chars in r, plus the number of chars in ARn CHAR/BITNO
1766 // XXX Handle 'r' too big intelligently...
1767             uint nchars = (uint) (address * 8u + r + arn_char4 + CN);
1768 
1769             effWORDNO = nchars / 8u; // 8 chars/word
1770             effCHAR = nchars % 8u; // effCHAR is the 4 bit char number, not the 9-bit char no
1771             effBITNO = (nchars & 1u) ? 5u : 0u;
1772             effWORDNO &= AMASK;
1773 
1774             e->CN[k-1] = effCHAR;        // ?????
1775           }
1776           break;
1777 
1778         case CTN9:
1779             if (CN & 1u) {
1780               L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseNumericOperandDescriptor CTA9 & CN odd");)
1781               // DPS8M
1782               *mod_fault |= FR_ILL_PROC;
1783             }
1784             CN = (CN >> 1u) & 03u;
1785 
1786             effBITNO = 0;
1787             effCHAR = ((word36) CN + (word36) ARn_CHAR + r) % 4u;
1788             effWORDNO = (uint) (address + (9u*CN + 9u*ARn_CHAR + 9u*r + ARn_BITNO) / 36);
1789             effWORDNO &= AMASK;
1790 
1791             e->CN[k-1] = effCHAR;        // ?????
1792 
1793             break;
1794         default:
1795 #ifdef EIS_PTR3
1796             sim_printf ("parseNumericOperandDescriptor(ta=%d) How'd we get here 2?\n", cpu.du.TAk[k-1]);
1797 #else
1798             sim_printf ("parseNumericOperandDescriptor(ta=%d) How'd we get here 2?\n", e->TA[k-1]);
1799 #endif
1800             break;
1801     }
1802 
1803     EISaddr *a = &e->addr[k-1];
1804     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1805 #ifdef EIS_PTR
1806     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1807 #else
1808     a->address = effWORDNO;
1809 #endif
1810     a->cPos = (int) effCHAR;
1811     a->bPos = (int) effBITNO;
1812 
1813     // a->_type = eisTN;
1814     a->TN = (int) e->TN[k-1];
1815 
1816 #ifdef EIS_PTR
1817     sim_debug (DBG_TRACEEXT, & cpu_dev, "parseNumericOperandDescriptor(): address:%06o cPos:%d bPos:%d N%u %u\n", cpu.du.Dk_PTR_W[k-1], a->cPos, a->bPos, k, e->N[k-1]);
1818 #else
1819     sim_debug (DBG_TRACEEXT, & cpu_dev, "parseNumericOperandDescriptor(): address:%06o cPos:%d bPos:%d N%u %u\n", a->address, a->cPos, a->bPos, k, e->N[k-1]);
1820 #endif
1821 
1822 }
1823 
1824 static void parseBitstringOperandDescriptor (int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1825 {
1826     PNL (L68_ (if (k == 1)
1827       DU_CYCLE_ANLD1;
1828     else if (k == 2)
1829       DU_CYCLE_ANLD2;
1830     else if (k == 3)
1831       DU_CYCLE_ANSTR;))
1832 
1833     EISstruct * e = & cpu.currentEISinstruction;
1834     word18 MFk = e->MF[k-1];
1835     word36 opDesc = e->op[k-1];
1836 
1837 #ifdef PANEL68
1838     if (k == 1)
1839       cpu.dataMode = 0010; // 1 bit not alpha, not alpha numeric
1840 #endif
1841     word8 ARn_CHAR = 0;
1842     word6 ARn_BITNO = 0;
1843 
1844     PNL (cpu.du.POP = 1);
1845 
1846     word18 address = GETHI(opDesc);
1847     if (MFk & MFkAR)
1848     {
1849         // if MKf contains ar then it Means Y-charn is not the memory address
1850         // of the data but is a reference to a pointer register pointing to the
1851         // data.
1852         word3 n = (word3) getbits18 (address, 0, 3);
1853         CPTUR (cptUsePRn + n);
1854         word15 offset = address & MASK15;  // 15-bit signed number
1855         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1856 
1857         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d AR%d\n", k, n);
1858 
1859         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1860         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1861         cpu.cu.TSN_PRNO[k-1] = n;
1862         cpu.cu.TSN_VALID[k-1] = 1;
1863         e->addr[k-1].SNR = cpu.PR[n].SNR;
1864         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1865         e->addr[k-1].mat = viaPR;   // ARs involved
1866     }
1867     PNL (cpu.du.POL = 1);
1868 
1869     //Operand length. If MFk.RL = 0, this field contains the string length of
1870     //the operand. If MFk.RL = 1, this field contains the code for a register
1871     //holding the operand string length. See Table 4-1 and EIS modification
1872     //fields (MF) above for a discussion of register codes.
1873     if (MFk & MFkRL)
1874     {
1875         uint reg = opDesc & 017;
1876         e->N[k-1] = getMFReg36(reg, false, false, mod_fault) & 077777777;  // RL=1: disallow du,n,ic
1877         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d RL reg %u val %"PRIo64"\n", k, reg, (word36)e->N[k-1]);
1878     }
1879     else
1880     {
1881         e ->N[k-1] = opDesc & 07777;
1882     }
1883 
1884     sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d opdesc %012"PRIo64"\n", k, opDesc);
1885     sim_debug (DBG_TRACEEXT, & cpu_dev, "N%u %u\n", k, e->N[k-1]);
1886 
1887     word4 B = getbits36_4(opDesc, 20);    // bit# from descriptor
1888     word2 C = getbits36_2 (opDesc, 18);     // char# from descriptor
1889 
1890     if (B >= 9) {
1891       L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseBitstringOperandDescriptor B >= 9");)
1892       // DPS8M
1893       *mod_fault |= FR_ILL_PROC;
1894     }
1895 
1896     word36 r = getMFReg36(MFk & 017, false, true, mod_fault);  // disallow du, allow n,ic
1897     if ((MFk & 017) == 4)   // reg == IC ?
1898     {
1899         // If reg == IC, then R is in words, not bits.
1900         //r *= 36;
1901         address += r;
1902         address &= AMASK;
1903         r = 0;
1904     }
1905 
1906     uint effBITNO = (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 9u;
1907     uint effCHAR = ((9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 36u) / 9u;
1908     uint effWORDNO = (uint) (address + (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) / 36u);
1909     effWORDNO &= AMASK;
1910 
1911     e->B[k-1] = effBITNO;
1912     e->C[k-1] = effCHAR;
1913 
1914     EISaddr *a = &e->addr[k-1];
1915     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1916 #ifdef EIS_PTR
1917     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1918 #else
1919     a->address = effWORDNO;
1920 #endif
1921     a->cPos = (int) effCHAR;
1922     a->bPos = (int) effBITNO;
1923 }
1924 
1925 static void cleanupOperandDescriptor (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
1926   {
1927     EISstruct * e = & cpu.currentEISinstruction;
1928     if (e -> addr [k - 1].cacheValid && e -> addr [k - 1].cacheDirty)
1929       {
1930         EISWriteCache(& e -> addr [k - 1]);
1931       }
1932     e -> addr [k - 1].cacheDirty = false;
1933   }
1934 
1935 // For a4bd/s4bd, the world is made of 32 bit words, so the address space
1936 // is 2^18 * 32 bits
1937 #define n4bits (1 << 23)
1938 // For a4bd/s4bd, the world is made of 8 4-bitcharacter words, so the address space
1939 // is 2^18 * 8 characters
1940 #define n4chars (1 << 21)
1941 // For axbd/sxbd, the world is made of 36 bits words, so the address space
1942 // is 2^18 * 36 bits
1943 #define nxbits ((1 << 18) * 36)
1944 
1945 // 2 * (s->BITNO / 9) + (s->BITNO % 9) / 4;
1946 static unsigned int cntFromBit[36] = {
1947     0, 0, 0, 0, 0, 1, 1, 1, 1,
1948     2, 2, 2, 2, 2, 3, 3, 3, 3,
1949     4, 4, 4, 4, 4, 5, 5, 5, 5,
1950     6, 6, 6, 6, 6, 7, 7, 7, 7
1951 };
1952 
1953 static word6 bitFromCnt[8] = {1, 5, 10, 14, 19, 23, 28, 32};
1954 
1955 void a4bd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1956   {
1957     // 8 4-bit characters/word
1958 
1959     uint ARn = GET_ARN (cpu.cu.IWB);
1960     CPTUR (cptUsePRn + ARn);
1961     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
1962 //if (current_running_cpu_idx)
1963 //sim_printf ("a4bd address %o %d.\n", address, address);
1964 
1965     word4 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
1966                                      // au, qu, al, ql, xn)
1967     // r is the count of 4bit characters
1968     word36 ur = getCrAR (reg);
1969     int32 r = SIGNEXT22_32 ((word22) ur);
1970 //if (current_running_cpu_idx)
1971 //sim_printf ("a4bd r %o %d.\n", r, r);
1972 
1973     uint augend = 0; // in 4bit characters
1974     if (GET_A (cpu.cu.IWB))
1975        {
1976 //if (current_running_cpu_idx)
1977 //sim_printf ("a4bd AR%d WORDNO %o %d. CHAR %o BITNO %o\n", cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR, cpu.AR[ARn].BITNO);
1978 
1979          //augend = cpu.AR[ARn].WORDNO * 32u + cntFromBit [GET_AR_BITNO (ARn)];
1980          // force to 4 bit character boundary
1981          //augend = augend & ~3;
1982          //augend = cpu.AR[ARn].WORDNO * 8 + cpu.AR[ARn].CHAR * 2;
1983          augend = cpu.AR[ARn].WORDNO * 8u + GET_AR_CHAR (ARn) * 2u;
1984 
1985          //if (cpu.AR[ARn].BITNO >= 5)
1986          if (GET_AR_BITNO (ARn) >= 5u)
1987            augend ++;
1988        }
1989 
1990 //if (current_running_cpu_idx)
1991 //sim_printf ("a4bd augend %o %d.\n", augend, augend);
1992 
1993     int32_t addend = address * 8 + r;  // in characters
1994 
1995 //if (current_running_cpu_idx)
1996 //sim_printf ("a4bd addend %o %d.\n", addend, addend);
1997 
1998     int32_t sum = (int32_t) augend + addend;
1999 //if (current_running_cpu_idx)
2000 //sim_printf ("a4bd sum %o %d.\n", sum, sum);
2001 
2002     // Handle over/under flow
2003     while (sum < 0)
2004       sum += n4chars;
2005     sum = sum % n4chars;
2006 //if (current_running_cpu_idx)
2007 //sim_printf ("a4bd sum %o %d.\n", sum, sum);
2008 
2009     cpu.AR[ARn].WORDNO = (word18) (sum / 8) & AMASK;
2010 //if (current_running_cpu_idx)
2011 //sim_printf ("a4bd WORDNO %o %d.\n", cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO);
2012 
2013 //    // 0aaaabbbb0ccccdddd0eeeeffff0gggghhhh
2014 //    //             111111 11112222 22222233
2015 //    //  01234567 89012345 67890123 45678901   // 4 bit notation offset
2016 //    static int tab [32] = { 1,  2,  3,  4,  5,  6,  7,  8,
2017 //                           10, 11, 12, 13, 14, 15, 16, 17,
2018 //                           19, 20, 21, 22, 23, 24, 25, 26,
2019 //                           28, 29, 30, 31, 32, 33, 34, 35};
2020 //
2021     //uint bitno = sum % 32;
2022 //    AR [ARn].BITNO = tab [bitno];
2023     //cpu.AR [ARn].BITNO = bitFromCnt[bitno % 8];
2024     //SET_PR_BITNO (ARn, bitFromCnt[bitno % 8]);
2025     uint char4no = (uint) (sum % 8);
2026 //if (current_running_cpu_idx)
2027 //sim_printf ("a4bd char4no %d.\n", char4no);
2028 
2029     SET_AR_CHAR_BITNO (ARn, (word2) (char4no / 2), (char4no % 2) ? 5 : 0);
2030 #ifdef TESTING
2031     HDBGRegARW (ARn, "a4bd");
2032 #endif
2033 //if (current_running_cpu_idx)
2034 //sim_printf ("a4bd CHAR %o %d.\n", cpu.AR[ARn].CHAR, cpu.AR[ARn].CHAR);
2035 //if (current_running_cpu_idx)
2036 //sim_printf ("a4bd BITNO %o %d.\n", cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2037   }
2038 
2039 void s4bd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2040   {
2041     uint ARn = GET_ARN (cpu.cu.IWB);
2042     CPTUR (cptUsePRn + ARn);
2043     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2044     word4 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2045                                   // au, qu, al, ql, xn)
2046     // r is the count of characters
2047     word36 ur = getCrAR (reg);
2048     int32 r = SIGNEXT22_32 ((word22) ur);
2049 
2050     uint minuend = 0;
2051     if (GET_A (cpu.cu.IWB))
2052        {
2053          //minuend = cpu.AR [ARn].WORDNO * 32 + cntFromBit [GET_PR_BITNO (ARn)];
2054          minuend = cpu.AR [ARn].WORDNO * 32 + cntFromBit [GET_AR_CHAR (ARn) * 9 + GET_AR_BITNO (ARn)];
2055          // force to 4 bit character boundary
2056          minuend = minuend & (unsigned int) ~3;
2057        }
2058     int32_t subtractend = address * 32 + r * 4;
2059     int32_t difference = (int32_t) minuend - subtractend;
2060 
2061     // Handle over/under flow
2062     while (difference < 0)
2063       difference += n4bits;
2064     difference = difference % n4bits;
2065 
2066     cpu.AR [ARn].WORDNO = (word18) (difference / 32) & AMASK;
2067 
2068 //    // 0aaaabbbb0ccccdddd0eeeeffff0gggghhhh
2069 //    //             111111 11112222 22222233
2070 //    //  01234567 89012345 67890123 45678901   // 4 bit notation offset
2071 //    static int tab [32] = { 1,  2,  3,  4,  5,  6,  7,  8,
2072 //                       10, 11, 12, 13, 14, 15, 16, 17,
2073 //                       19, 20, 21, 22, 23, 24, 25, 26,
2074 //                       28, 29, 30, 31, 32, 33, 34, 35};
2075 //
2076 
2077     uint bitno = (uint) (difference % 32);
2078 //    cpu.AR [ARn].BITNO = tab [bitno];
2079     // SET_PR_BITNO (ARn, bitFromCnt[bitno % 8]);
2080     SET_AR_CHAR_BITNO (ARn, bitFromCnt[bitno % 8] / 9, bitFromCnt[bitno % 8] % 9);
2081 #ifdef TESTING
2082     HDBGRegARW (ARn, "s4bd");
2083 #endif
2084   }
2085 
2086 void axbd (uint sz)
     /* [previous][next][first][last][top][bottom][index][help] */
2087   {
2088     uint ARn = GET_ARN (cpu.cu.IWB);
2089     CPTUR (cptUsePRn + ARn);
2090     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2091     word6 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2092                                   // au, qu, al, ql, xn)
2093     // r is the count of characters
2094     word36 rcnt = getCrAR (reg);
2095     int32_t r;
2096 
2097     if (sz == 1)
2098       r = SIGNEXT24_32 ((word24) rcnt);
2099     else if (sz == 4)
2100       r = SIGNEXT22_32 ((word22) rcnt);
2101     else if (sz == 6)
2102       r = SIGNEXT21_32 ((word21) rcnt);
2103     else if (sz == 9)
2104       r = SIGNEXT21_32 ((word21) rcnt);
2105     else // if (sz == 36)
2106       r = SIGNEXT18_32 ((word18) rcnt);
2107 
2108     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd sz %d ARn 0%o address 0%o reg 0%o r 0%o\n", sz, ARn, address, reg, r);
2109 
2110     uint augend = 0;
2111     if (GET_A (cpu.cu.IWB))
2112       {
2113        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\n", ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn), GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2114        augend = cpu.AR[ARn].WORDNO * 36u + GET_AR_CHAR (ARn) * 9u + GET_AR_BITNO (ARn);
2115       }
2116     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd augend 0%o\n", augend);
2117     // force to character boundary
2118     //if (sz == 9 || sz == 36 || GET_A (cpu.cu.IWB))
2119     if (sz == 9 || GET_A (cpu.cu.IWB))
2120       {
2121         augend = (augend / sz) * sz;
2122         sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd force augend 0%o\n", augend);
2123       }
2124 // If sz == 9, this is an a9bd instruction; ISOLTS says that r is in characters, not bits.
2125 // wow. That breaks the boot bad.
2126 //    if (sz == 9)
2127 //      {
2128 //        r *= 9;
2129 //if (current_running_cpu_idx)
2130 //sim_printf ("axbd force chars 0%o %d. bits\n", r, r);
2131 //      }
2132 
2133     int32_t addend = address * 36 + r * (int32_t) sz;
2134     int32_t sum = (int32_t) augend + addend;
2135 
2136     // Handle over/under flow
2137     while (sum < 0)
2138       sum += nxbits;
2139     sum = sum % nxbits;
2140 
2141     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2142 
2143     cpu.AR [ARn].WORDNO = (word18) (sum / 36) & AMASK;
2144     //SET_PR_BITNO (ARn, sum % 36);
2145 #ifdef TESTING
2146     HDBGRegARR (ARn, "axbd");
2147 #endif
2148     SET_AR_CHAR_BITNO (ARn, (word2)((sum % 36) / 9), (word2)(sum % 9));
2149 #ifdef TESTING
2150     HDBGRegARW (ARn, "axbd");
2151 #endif
2152   }
2153 
2154 
2155 void abd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2156   {
2157     uint ARn = GET_ARN (cpu.cu.IWB);
2158     CPTUR (cptUsePRn + ARn);
2159 
2160     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2161 //if (current_running_cpu_idx)
2162 //sim_printf ("address %o\n", address);
2163     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2164     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2165     word24 r = getCrAR ((word4) reg) & MASK24;
2166 //if (current_running_cpu_idx)
2167 //sim_printf ("r 0%o %d.\n", r, r);
2168 //if (current_running_cpu_idx)
2169 //sim_printf ("abd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\n", cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR, cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2170 
2171     //if (cpu.AR[ARn].BITNO > 8)
2172       //cpu.AR[ARn].BITNO = 8;
2173     if (GET_AR_BITNO (ARn) > 8)
2174       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2175 
2176     if (GET_A (cpu.cu.IWB))
2177       {
2178 //if (current_running_cpu_idx)
2179 //sim_printf ("A 1\n");
2180         //word24 bits = 9 * cpu.AR[ARn].CHAR + cpu.AR[ARn].BITNO + r;
2181         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) + r;
2182 //if (current_running_cpu_idx)
2183 //sim_printf ("bits 0%o %d.\n", bits, bits);
2184         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO + address +
2185                               bits / 36) & MASK18;
2186         if (r % 36)
2187           {
2188             //cpu.AR[ARn].CHAR = (bits % 36) / 9;
2189             //cpu.AR[ARn].BITNO = bits % 9;
2190             SET_AR_CHAR_BITNO (ARn, (bits % 36) / 9,
2191                                     bits % 9);
2192           }
2193       }
2194     else
2195       {
2196 //if (current_running_cpu_idx)
2197 //sim_printf ("A 0\n");
2198         cpu.AR[ARn].WORDNO = (address + r / 36) & MASK18;
2199         if (r % 36)
2200           {
2201             //cpu.AR[ARn].CHAR = (r % 36) / 9;
2202             //cpu.AR[ARn].BITNO = r % 9;
2203             SET_AR_CHAR_BITNO (ARn, (r % 36) / 9,
2204                                     r % 9);
2205           }
2206       }
2207 # ifdef TESTING
2208     HDBGRegARW (ARn, "abd");
2209 # endif
2210 //if (current_running_cpu_idx)
2211 //sim_printf ("abd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\n", cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR, cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2212   }
2213 
2214 
2215 
2216 
2217 
2218 
2219 
2220 
2221 
2222 
2223 
2224 
2225 
2226 
2227 
2228 
2229 
2230 
2231 
2232 
2233 
2234 
2235 
2236 
2237 
2238 
2239 
2240 
2241 
2242 
2243 
2244 
2245 
2246 
2247 
2248 
2249 
2250 
2251 
2252 
2253 
2254 
2255 
2256 
2257 
2258 
2259 
2260 
2261 
2262 
2263 
2264 
2265 
2266 
2267 
2268 
2269 
2270 
2271 
2272 
2273 
2274 
2275 
2276 
2277 
2278 
2279 
2280 
2281 
2282 
2283 
2284 
2285 
2286 
2287 
2288 
2289 
2290 
2291 
2292 
2293 
2294 
2295 
2296 
2297 
2298 
2299 
2300 
2301 
2302 
2303 
2304 
2305 
2306 
2307 
2308 
2309 
2310 
2311 
2312 
2313 
2314 
2315 
2316 
2317 
2318 
2319 
2320 
2321 
2322 
2323 
2324 
2325 
2326 
2327 
2328 
2329 
2330 
2331 
2332 
2333 
2334 
2335 
2336 
2337 
2338 
2339 
2340 
2341 
2342 
2343 
2344 
2345 
2346 
2347 
2348 
2349 
2350 
2351 
2352 
2353 
2354 
2355 
2356 
2357 void awd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2358   {
2359     uint ARn = GET_ARN (cpu.cu.IWB);
2360     CPTUR (cptUsePRn + ARn);
2361     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2362     // 4-bit register modification (None except
2363     // au, qu, al, ql, xn)
2364     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2365     // r is the count of characters
2366 // XXX This code is assuming that 'r' has 18 bits of data....
2367     int32_t r = (int32_t) (getCrAR (reg) & MASK18);
2368     r = SIGNEXT18_32 ((word18) r);
2369 
2370     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2371                "awd ARn 0%o address 0%o reg 0%o r 0%o\n", ARn, address, reg, r);
2372 
2373     uint augend = 0;
2374     if (GET_A (cpu.cu.IWB))
2375       {
2376        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "awd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\n", ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn), GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2377 
2378        //augend = cpu.AR [ARn].WORDNO * 36 + GET_AR_CHAR (ARn) * 9 + GET_AR_BITNO (ARn);
2379        augend = cpu.AR [ARn].WORDNO;
2380       }
2381 
2382     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "awd augend 0%o\n", augend);
2383 
2384     int32_t addend = address + r;
2385     int32_t sum = (int32_t) augend + addend;
2386 
2387     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "awd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2388 
2389     cpu.AR[ARn].WORDNO = (word18) sum & AMASK;
2390     SET_AR_CHAR_BITNO (ARn, 0, 0);
2391 #ifdef TESTING
2392     HDBGRegARW (ARn, "awd");
2393 #endif
2394   }
2395 
2396 void sbd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2397   {
2398     uint ARn = GET_ARN (cpu.cu.IWB);
2399 
2400     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2401     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2402     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2403     word24 r = getCrAR ((word4) reg) & MASK24;
2404     if (GET_AR_BITNO (ARn) > 8)
2405       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2406 
2407     if (GET_A (cpu.cu.IWB))
2408       {
2409         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) - r;
2410         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2411                              address + bits / 36) & MASK18;
2412         if (r % 36)
2413           {
2414             SET_AR_CHAR_BITNO (ARn, (- ((bits % 36) / 9)) & MASK2,
2415                                     (- (bits % 9)) & MASK4);
2416           }
2417       }
2418     else
2419       {
2420         cpu.AR[ARn].WORDNO = (- (address + r / 36)) & MASK18;
2421         if (r % 36)
2422           {
2423             SET_AR_CHAR_BITNO (ARn, (- ((r % 36) / 9)) & MASK2,
2424                                     (- (r % 9)) & MASK4);
2425           }
2426       }
2427 #ifdef TESTING
2428     HDBGRegARW (ARn, "sbd");
2429 #endif
2430   }
2431 
2432 void swd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2433   {
2434     uint ARn = GET_ARN (cpu.cu.IWB);
2435     CPTUR (cptUsePRn + ARn);
2436     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2437     // 4-bit register modification (None except
2438     // au, qu, al, ql, xn)
2439     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2440     // r is the count of characters
2441 // XXX This code is assuming that 'r' has 18 bits of data....
2442     int32_t r = (int32_t) (getCrAR (reg) & MASK18);
2443     r = SIGNEXT18_32 ((word18) r);
2444 
2445     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "swd ARn 0%o address 0%o reg 0%o r 0%o\n", ARn, address, reg, r);
2446 
2447     uint minued = 0;
2448     if (GET_A (cpu.cu.IWB))
2449       {
2450        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "swd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\n", ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn), GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2451 
2452        //minued = cpu.AR [ARn].WORDNO * 36 + GET_AR_BITNO (ARn);
2453        minued = cpu.AR [ARn].WORDNO;
2454       }
2455 
2456     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "swd minued 0%o\n", minued);
2457 
2458     int32_t subtractend = address + r;
2459     int32_t difference = (int32_t) minued - subtractend;
2460 
2461     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "swd minued 0%o subtractend 0%o difference 0%o\n", minued, subtractend, difference);
2462 
2463     cpu.AR [ARn].WORDNO = (word18) difference & AMASK;
2464     SET_AR_CHAR_BITNO (ARn, 0, 0);
2465 #ifdef TESTING
2466     HDBGRegARW (ARn, "swd");
2467 #endif
2468   }
2469 
2470 void s9bd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2471   {
2472     uint ARn = GET_ARN (cpu.cu.IWB);
2473     CPTUR (cptUsePRn + ARn);
2474     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2475     // 4-bit register modification (None except
2476     // au, qu, al, ql, xn)
2477     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2478 
2479     // r is the count of 9-bit characters
2480     word21 r = getCrAR (reg) & MASK21;;
2481 
2482     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "s9bd r 0%o\n", r);
2483 
2484     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "s9bd ARn 0%o address 0%o reg 0%o r 0%o\n", ARn, address, reg, r);
2485 
2486     if (GET_A (cpu.cu.IWB))
2487       {
2488         //cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2489         //                      address +
2490         //                      (cpu.AR[ARn].CHAR - r) / 4) & MASK18;
2491         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2492                               address +
2493                               (GET_AR_CHAR (ARn) - r) / 4) & MASK18;
2494         //if (r % 36)
2495           //{
2496             //cpu.AR[ARn].CHAR = ((cpu.AR[ARn].CHAR - r) % 4) & MASK2;
2497             //cpu.AR[ARn].CHAR = (cpu.AR[ARn].CHAR - r)  & MASK2;
2498             SET_AR_CHAR_BITNO (ARn, (GET_AR_CHAR (ARn) - r)  & MASK2, 0);
2499           //}
2500       }
2501     else
2502       {
2503         cpu.AR[ARn].WORDNO = (- (address + (r + 3) / 4)) & MASK18;
2504         //if (r % 36)
2505           //{
2506             //cpu.AR[ARn].CHAR = (-r) & MASK2;
2507             SET_AR_CHAR_BITNO (ARn, (-r) & MASK2, 0);
2508           //}
2509       }
2510     //cpu.AR[ARn].BITNO = 0;
2511 #ifdef TESTING
2512     HDBGRegARW (ARn, "s9bd");
2513 #endif
2514 //if (current_running_cpu_idx)
2515 //sim_printf ("s9bd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\n", cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR, cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2516   }
2517 
2518 //
2519 // Address Register arithmetic
2520 //
2521 // This code handles Address Register arithmetic
2522 //
2523 // asxbd (  ,       )
2524 // ABD     1   false
2525 // A4BD    4   false
2526 // A6BD    6   false
2527 // A9BD    9   false
2528 // AWD    36   false
2529 // SBD     1   true
2530 // S4BD    4   true
2531 // S6BD    6   true
2532 // S9BD    9   true
2533 // SWD    36   true
2534 //
2535 
2536 // The general approach is do all of the math as unsigned number of bits,
2537 // modulo 2^18 * 36 (the number of bits in a segment).
2538 //
2539 // To handle subtraction underflow, a preemptive borrow is done if the
2540 // the operation will underflow.
2541 //
2542 // Notes:
2543 //   According to ISOLTS 805, WORDNO is unsigned; this disagrees with AL-39
2544 
2545 void asxbd (uint sz, bool sub)
     /* [previous][next][first][last][top][bottom][index][help] */
2546   {
2547     // Map charno:bitno to bit offset for 4 bit char set
2548     uint map4 [64] =
2549       {      // 9-bit    4-bit
2550           0, // 0  0      0
2551           0, // 0  1      0
2552           0, // 0  2      0
2553           0, // 0  3      0
2554           0, // 0  4      0
2555           5, // 0  5      1
2556           5, // 0  6      1
2557           5, // 0  7      1
2558           5, // 0  8      1
2559           5, // 0  9  ill     guess
2560           5, // 0 10  ill     guess
2561           5, // 0 11  ill     guess
2562           5, // 0 12  ill     guess
2563           5, // 0 13  ill     guess
2564           5, // 0 14  ill     guess
2565           5, // 0 15  ill     guess
2566           9, // 1  0      2
2567           9, // 1  1      2
2568           9, // 1  2      2
2569           9, // 1  3      2
2570           9, // 1  4      2
2571          14, // 1  5      3
2572          14, // 1  6      3
2573          14, // 1  7      3
2574          14, // 1  8      3
2575          14, // 1  9  ill     guess
2576          14, // 1 10  ill ISOLTS 805 loop point 010226 sxbd test no 28 (4bit)
2577          14, // 1 11  ill     guess
2578          14, // 1 12  ill     guess
2579          14, // 1 13  ill     guess
2580          14, // 1 14  ill     guess
2581          14, // 1 15  ill     guess
2582          18, // 2  0      4
2583          18, // 2  1      4
2584          18, // 2  2      4
2585          18, // 2  3      4
2586          18, // 2  4      4
2587          23, // 2  5      5
2588          23, // 2  6      5
2589          23, // 2  7      5
2590          23, // 2  8      5
2591          23, // 2  9  ill     guess
2592          23, // 2 10  ill     guess
2593          23, // 2 11  ill     guess
2594          23, // 2 12  ill   ISOLTS 805 loop point 010226 sxbd test no 26 (4bit)
2595          23, // 2 13  ill     guess
2596          23, // 2 14  ill     guess
2597          23, // 2 15  ill     guess
2598          27, // 3  0      6
2599          27, // 3  1      6
2600          27, // 3  2      6
2601          27, // 3  3      6
2602          27, // 3  4      6
2603          32, // 3  5      7
2604          32, // 3  6      7
2605          32, // 3  7      7
2606          32, // 3  8      7
2607          32, // 3  9  ill     guess
2608          32, // 3 10  ill     guess
2609          32, // 3 11  ill     guess
2610          32, // 3 12  ill     guess
2611          32, // 3 13  ill     guess
2612          32, // 3 14  ill   ISOLTS 805 loop point 010226 sxbd test no 24 (4bit)
2613          32  // 3 15  ill     guess
2614       };
2615     // Map charno:bitno to bit offset for 6 bit char set
2616     uint map6 [64] =
2617       {      // 9-bit    6-bit
2618           0, // 0  0      0
2619           1, // 0  1      0
2620           2, // 0  2      0
2621           3, // 0  3      0
2622           4, // 0  4      0
2623           5, // 0  5      0
2624           6, // 0  6      1
2625           7, // 0  7      1
2626           8, // 0  8      1
2627           6, // 0  9  ill  ISOLTS 805 loop point 010100 sxbd test no 12
2628           6, // 0 10  ill     guess
2629           6, // 0 11  ill     guess
2630           6, // 0 12  ill     guess
2631           6, // 0 13  ill     guess
2632           6, // 0 14  ill     guess
2633           6, // 0 15  ill     guess
2634           9, // 1  0      1
2635          10, // 1  1      1
2636          11, // 1  2      1
2637          12, // 1  3      2
2638          13, // 1  4      2
2639          14, // 1  5      2
2640          15, // 1  6      2
2641          16, // 1  7      2
2642          17, // 1  8      2
2643          12, // 1  9  ill     guess
2644          12, // 1 10  ill     guess
2645          12, // 1 11  ill ISOLTS 805 loop point 010100 sxbd test no 12
2646          12, // 1 12  ill     guess
2647          12, // 1 13  ill     guess
2648          12, // 1 14  ill     guess
2649          12, // 1 15  ill     guess
2650          18, // 2  0      3
2651          19, // 2  1      3
2652          20, // 2  2      3
2653          21, // 2  3      3
2654          22, // 2  4      3
2655          23, // 2  5      3
2656          24, // 2  6      4
2657          25, // 2  7      4
2658          26, // 2  8      4
2659          24, // 2  9  ill     guess
2660          24, // 2 10  ill     guess
2661          24, // 2 11  ill     guess
2662          24, // 2 12  ill     guess
2663          24, // 2 13  ill   ISOLTS 805 loop point 010100 sxbd test no 10
2664          24, // 2 14  ill     guess
2665          24, // 2 15  ill     guess
2666          27, // 3  0      4
2667          28, // 3  1      4
2668          29, // 3  2      4
2669          30, // 3  3      5
2670          31, // 3  4      5
2671          32, // 3  5      5
2672          33, // 3  6      5
2673          34, // 3  7      5
2674          35, // 3  8      5
2675          30, // 3  9  ill     guess
2676          30, // 3 10  ill     guess
2677          30, // 3 11  ill     guess
2678          30, // 3 12  ill     guess
2679          30, // 3 13  ill     guess
2680          30, // 3 14  ill     guess
2681          30  // 3 15  ill   ISOLTS 805 loop point 010100 sxbd test no 8 (6bit)
2682       };
2683     // Map charno:bitno to 1 and 9 bit offset
2684     uint map9 [64] =
2685       {      // 9-bit
2686           0, // 0  0
2687           1, // 0  1
2688           2, // 0  2
2689           3, // 0  3
2690           4, // 0  4
2691           5, // 0  5
2692           6, // 0  6
2693           7, // 0  7
2694           8, // 0  8
2695           8, // 0  9  ill     guess
2696           8, // 0 10  ill     guess
2697           8, // 0 11  ill     guess
2698           8, // 0 12  ill     guess
2699           8, // 0 13  ill     guess
2700           8, // 0 14  ill     guess
2701           8, // 0 15  ill     guess
2702           9, // 1  0
2703          10, // 1  1
2704          11, // 1  2
2705          12, // 1  3
2706          13, // 1  4
2707          14, // 1  5
2708          15, // 1  6
2709          16, // 1  7
2710          17, // 1  8
2711          17, // 1  9  ill     guess
2712          17, // 1 10  ill     guess
2713          17, // 1 11  ill     guess
2714          17, // 1 12  ill     guess
2715          17, // 1 13  ill     guess
2716          17, // 1 14  ill     guess
2717          17, // 1 15  ill     guess
2718          18, // 2  0
2719          19, // 2  1
2720          20, // 2  2
2721          21, // 2  3
2722          22, // 2  4
2723          23, // 2  5
2724          24, // 2  6
2725          25, // 2  7
2726          26, // 2  8
2727          26, // 2  9  ill     guess
2728          26, // 2 10  ill     guess
2729          26, // 2 11  ill     guess
2730          26, // 2 12  ill     guess
2731          26, // 2 13  ill     guess
2732          26, // 2 14  ill     guess
2733          26, // 2 15  ill     guess
2734          27, // 3  0
2735          28, // 3  1
2736          29, // 3  2
2737          30, // 3  3
2738          31, // 3  4
2739          32, // 3  5
2740          33, // 3  6
2741          34, // 3  7
2742          35, // 3  8
2743          35, // 3  9  ill     guess
2744          35, // 3 10  ill     guess
2745          35, // 3 11  ill     guess
2746          35, // 3 12  ill     guess
2747          35, // 3 13  ill     guess
2748          35, // 3 14  ill     guess
2749          35  // 3 15  ill     guess
2750       };
2751 
2752 //
2753 // Extract the operand data from the instruction
2754 //
2755 
2756     uint ARn = GET_ARN (cpu.cu.IWB);
2757     uint address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2758     word4 reg = (word4) GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2759                                   // au, qu, al, ql, xn)
2760 
2761 //
2762 // Calculate r
2763 //
2764 
2765     // r is the count of characters (or bits if sz is 1; words if sz == 36)
2766     word36 rcnt = getCrAR (reg);
2767 
2768     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd sz %d r 0%"PRIo64"\n", sz, rcnt);
2769 
2770     // Crop rcnt into r based on the operand size.
2771     uint r = 0;
2772 
2773     if (sz == 1)
2774       r = (uint) (rcnt & MASK24);
2775     else if (sz == 4)
2776       r = (uint) (rcnt & MASK22);
2777     else if (sz == 6)
2778       r = (uint) (rcnt & MASK21);
2779     else if (sz == 9)
2780       r = (uint) (rcnt & MASK21);
2781     else // if (sz == 36)
2782       r = (uint) (rcnt & MASK18);
2783 
2784     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd sz %d ARn 0%o address 0%o reg 0%o r 0%o\n", sz, ARn, address, reg, r);
2785 
2786 //
2787 // Calculate augend
2788 //
2789 
2790     // If A is set, the instruction is AR = AR op operand; if not, AR = 0 op operand.
2791     uint augend = 0;
2792     if (GET_A (cpu.cu.IWB))
2793       {
2794         // For AWD/SWD, leave CHAR/BITNO alone
2795         if (sz == 36)
2796           {
2797             augend = cpu.AR[ARn].WORDNO * 36u;
2798           }
2799         else
2800           {
2801             uint bitno = GET_AR_BITNO (ARn);
2802             uint charno = GET_AR_CHAR (ARn);
2803 
2804             // The behavior of the DU for cases of CHAR > 9 is not defined; some values
2805             // are tested by ISOLTS, and have been recorded in the mapx tables; the
2806             // missing values are guessed at.
2807 
2808             uint * map;
2809             if (sz == 4)
2810               map = map4;
2811             else if (sz == 6)
2812               map = map6;
2813             else
2814               map = map9;
2815 
2816             augend = cpu.AR[ARn].WORDNO * 36u + map [charno * 16 + bitno];
2817             augend = augend % nxbits;
2818           }
2819       }
2820 
2821 //
2822 // Calculate addend
2823 //
2824 
2825     uint addend = 0;
2826     if (sz == 4)
2827       {
2828         // r is the number of 4 bit characters; each character is actually
2829         // 4.5 bits long
2830         addend = address * 36u + (r * 9) / 2;
2831 
2832         // round the odd character up one bit
2833         // (the odd character starts at bit n/2 + 1, not n/2.)
2834         if ((! sub) && r % 2) // r is odd
2835           addend ++;
2836       }
2837     else
2838       addend = address * 36u + r * sz;
2839 
2840     // Handle overflow
2841     addend = addend % nxbits;
2842 
2843 //
2844 // Calculate sum or difference
2845 //
2846 
2847     uint sum = 0;
2848     if (sub)
2849       {
2850         // Prevent underflow
2851         if (addend > augend)
2852           augend += nxbits;
2853         sum = augend - addend;
2854       }
2855     else
2856       {
2857         sum = augend + addend;
2858         sum %= nxbits;
2859       }
2860 
2861     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2862 
2863 //
2864 // Adjust to character boundary
2865 //
2866 
2867     if (sz == 6 || sz == 9)
2868       {
2869         sum = (sum / sz) * sz;
2870       }
2871 
2872 //
2873 // Convert sum to WORDNO/CHAR/BITNO
2874 //
2875 
2876     cpu.AR [ARn].WORDNO = (word18) (sum / 36u) & AMASK;
2877 
2878     // If AWD/SWD clear CHAR/BITNO
2879 
2880     if (sz == 36)
2881       {
2882         SET_AR_CHAR_BITNO (ARn, 0, 0);
2883       }
2884     else
2885       {
2886         if (sz == 4)
2887           {
2888             static uint tab [36] [2] =
2889               {
2890                 // char bitno  offset  4-bit charno
2891                 { 0, 0 }, // 0   0
2892                 { 0, 0 }, // 1
2893                 { 0, 0 }, // 2
2894                 { 0, 0 }, // 3
2895                 { 0, 0 }, // 4
2896 
2897                 { 0, 5 }, // 5   1
2898                 { 0, 5 }, // 6
2899                 { 0, 5 }, // 7
2900                 { 0, 5 }, // 8
2901 
2902                 { 1, 0 }, // 9   2
2903                 { 1, 0 }, // 10
2904                 { 1, 0 }, // 11
2905                 { 1, 0 }, // 12
2906                 { 1, 0 }, // 13
2907 
2908                 { 1, 5 }, // 15  3
2909                 { 1, 5 }, // 15
2910                 { 1, 5 }, // 16
2911                 { 1, 5 }, // 17
2912 
2913                 { 2, 0 }, // 18  4
2914                 { 2, 0 }, // 19
2915                 { 2, 0 }, // 20
2916                 { 2, 0 }, // 21
2917                 { 2, 0 }, // 22
2918 
2919                 { 2, 5 }, // 23  5
2920                 { 2, 5 }, // 24
2921                 { 2, 5 }, // 25
2922                 { 2, 5 }, // 26
2923 
2924                 { 3, 0 }, // 27  6
2925                 { 3, 0 }, // 28
2926                 { 3, 0 }, // 29
2927                 { 3, 0 }, // 30
2928                 { 3, 0 }, // 31
2929 
2930                 { 3, 5 }, // 32  7
2931                 { 3, 5 }, // 33
2932                 { 3, 5 }, // 34
2933                 { 3, 5 }  // 35
2934               };
2935             uint charno = tab [sum % 36u] [0];
2936             uint bitno = tab [sum % 36u] [1];
2937             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
2938           }
2939         else
2940           {
2941             uint charno = (sum % 36u) / 9;
2942             uint bitno = sum % 9;
2943             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
2944           }
2945       }
2946 #ifdef TESTING
2947     HDBGRegARW (ARn, "asxbd");
2948 #endif
2949   }
2950 
2951 void cmpc (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2952   {
2953     EISstruct * e = & cpu.currentEISinstruction;
2954 
2955     // For i = 1, 2, ..., minimum (N1,N2)
2956     //    C(Y-charn1)i-1 :: C(Y-charn2)i-1
2957     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
2958     //    C(FILL) :: C(Y-charn2)i-1
2959     // If N1 > N2, then for i = N2+1, N2+2, ..., N1
2960     //    C(Y-charn1)i-1 :: C(FILL)
2961     //
2962     // Indicators:
2963     //     Zero: If C(Y-charn1)i-1 = C(Y-charn2)i-1 for all i, then ON;
2964     //       otherwise, OFF
2965     //     Carry: If C(Y-charn1)i-1 < C(Y-charn2)i-1 for any i, then OFF;
2966     //       otherwise ON
2967 
2968     // Both strings are treated as the data type given for the left-hand
2969     // string, TA1. A data type given for the right-hand string, TA2, is
2970     // ignored.
2971     //
2972     // Comparison is made on full 9-bit fields. If the given data type is not
2973     // 9-bit (TA1 ≠ 0), then characters from C(Y-charn1) and C(Y-charn2) are
2974     // high- order zero filled. All 9 bits of C(FILL) are used.
2975     //
2976     // Instruction execution proceeds until an inequality is found or the
2977     // larger string length count is exhausted.
2978 
2979     fault_ipr_subtype_ mod_fault = 0;
2980 
2981 #ifndef EIS_SETUP
2982     setupOperandDescriptor (1, &mod_fault);
2983     setupOperandDescriptor (2, &mod_fault);
2984 #endif
2985     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
2986     parseAlphanumericOperandDescriptor (2, 1, false, &mod_fault);
2987 
2988     L68_ (
2989       // L68 raises it immediately
2990       if (mod_fault)
2991         {
2992           doFault (FAULT_IPR,
2993                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
2994                    "Illegal modifier");
2995         }
2996     )
2997 
2998     // Bits 9-10 MBZ
2999     if (IWB_IRODD & 0000600000000)
3000       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpc 9-10 MBZ");
3001 
3002     // Bit 23 of OP1 MBZ
3003     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3004       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "cmpc op1 23 MBZ");
3005 
3006 // ISOLTS ps846    test-07a    dec add test
3007 // Sets TA2 to the same as TA1. AL39 says TA2 ignored.
3008 // Try only check bit 23.
3009 // ISOLTS 880 test-04c sets bit 23.
3010 
3011 
3012 
3013 
3014 
3015 
3016 
3017 
3018     DPS8M_ (
3019       // DPS8M raises it delayed
3020       if (mod_fault)
3021         {
3022           doFault (FAULT_IPR,
3023                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3024                    "Illegal modifier");
3025         }
3026     )
3027 
3028     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
3029 
3030     SET_I_ZERO;  // set ZERO flag assuming strings are equal ...
3031     SET_I_CARRY; // set CARRY flag assuming strings are equal ...
3032 
3033     PNL (L68_ (if (max (e->N1, e->N2) < 128)
3034       DU_CYCLE_FLEN_128;))
3035 
3036     for (; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
3037       {
3038         word9 c1 = EISget469 (1, cpu.du.CHTALLY); // get Y-char1n
3039         word9 c2 = EISget469 (2, cpu.du.CHTALLY); // get Y-char2n
3040 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpc tally %d c1 %03o c2 %03o\n", cpu.du.CHTALLY, c1, c2);
3041         if (c1 != c2)
3042           {
3043             CLR_I_ZERO;  // an inequality found
3044             SC_I_CARRY (c1 > c2);
3045             cleanupOperandDescriptor (1);
3046             cleanupOperandDescriptor (2);
3047             return;
3048           }
3049       }
3050 
3051     if (e -> N1 < e -> N2)
3052       {
3053         for( ; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY ++)
3054           {
3055             word9 c1 = fill;     // use fill for Y-char1n
3056             word9 c2 = EISget469 (2, cpu.du.CHTALLY); // get Y-char2n
3057 
3058             if (c1 != c2)
3059               {
3060                 CLR_I_ZERO;  // an inequality found
3061                 SC_I_CARRY (c1 > c2);
3062                 cleanupOperandDescriptor (1);
3063                 cleanupOperandDescriptor (2);
3064                 return;
3065               }
3066           }
3067       }
3068     else if (e->N1 > e->N2)
3069       {
3070         for ( ; cpu.du.CHTALLY < e->N1; cpu.du.CHTALLY ++)
3071           {
3072             word9 c1 = EISget469 (1, cpu.du.CHTALLY); // get Y-char1n
3073             word9 c2 = fill;   // use fill for Y-char2n
3074 
3075             if (c1 != c2)
3076               {
3077                 CLR_I_ZERO;  // an inequality found
3078                 SC_I_CARRY (c1 > c2);
3079                 cleanupOperandDescriptor (1);
3080                 cleanupOperandDescriptor (2);
3081                 return;
3082               }
3083           }
3084       }
3085     // else ==
3086     cleanupOperandDescriptor (1);
3087     cleanupOperandDescriptor (2);
3088   }
3089 
3090 /*
3091  * SCD - Scan Characters Double
3092  */
3093 
3094 void scd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3095   {
3096     EISstruct * e = & cpu.currentEISinstruction;
3097 
3098     // For i = 1, 2, ..., N1-1
3099     //   C(Y-charn1)i-1,i :: C(Y-charn2)0,1
3100     // On instruction completion, if a match was found:
3101     //   00...0 → C(Y3)0,11
3102     //   i-1 → C(Y3)12,35
3103     // If no match was found:
3104     //   00...0 → C(Y3)0,11
3105     //      N1-1→ C(Y3)12,35
3106     //
3107 
3108     // The REG field of MF1 is checked for a legal code. If DU is specified in
3109     // the REG field of MF2 in one of the four multiword instructions (SCD,
3110     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3111     // the character or characters are arranged within the 18 bits of the word
3112     // address portion of the operand descriptor.
3113 
3114     fault_ipr_subtype_ mod_fault = 0;
3115 
3116 #ifndef EIS_SETUP
3117     setupOperandDescriptor (1, &mod_fault);
3118     setupOperandDescriptor (2, &mod_fault);
3119     setupOperandDescriptorCache (3);
3120 #endif
3121 
3122     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3123     parseAlphanumericOperandDescriptor (2, 1, true, &mod_fault); // use TA1
3124     parseArgOperandDescriptor (3, &mod_fault);
3125 
3126     L68_ (
3127       // L68 raises it immediately
3128       if (mod_fault)
3129         {
3130           doFault (FAULT_IPR,
3131                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3132                    "Illegal modifier");
3133         }
3134     )
3135 
3136     // Bits 0-10 MBZ
3137     if (IWB_IRODD & 0777600000000)
3138       {
3139         //sim_printf ("scd %12"PRIo64"\n", IWB_IRODD);
3140         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scd 0-10 MBZ");
3141       }
3142 
3143     // Bit 23 of OP1 MBZ
3144     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3145       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op1 23 MBZ");
3146 
3147     // Bits 18-28. 30-31 of OP3 MBZ
3148     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3149       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op3 18-28. 30-31 MBZ");
3150 
3151     DPS8M_ (
3152       // DPS8M raises it delayed
3153       if (mod_fault)
3154         {
3155           doFault (FAULT_IPR,
3156                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3157                    "Illegal modifier");
3158         }
3159     )
3160 
3161     // Both the string and the test character pair are treated as the data type
3162     // given for the string, TA1. A data type given for the test character
3163     // pair, TA2, is ignored.
3164 
3165     // fetch 'test' char - double
3166     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3167     // instruction word does not contain an operand descriptor for the test
3168     // character; instead, it contains the test character as a direct upper
3169     // operand in bits 0,8.
3170 
3171     word9 c1 = 0;
3172     word9 c2 = 0;
3173 
3174     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3175       {
3176         // per Bull RJ78, p. 5-45
3177 #ifdef EIS_PTR3
3178         switch (TA1) // Use TA1, not TA2
3179 #else
3180         switch (e -> TA1) // Use TA1, not TA2
3181 #endif
3182         {
3183             case CTA4:
3184 #ifdef EIS_PTR
3185               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3186               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3187 #else
3188               c1 = (e -> ADDR2.address >> 13) & 017;
3189               c2 = (e -> ADDR2.address >>  9) & 017;
3190 #endif
3191               break;
3192 
3193             case CTA6:
3194 #ifdef EIS_PTR
3195               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3196               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3197 #else
3198               c1 = (e -> ADDR2.address >> 12) & 077;
3199               c2 = (e -> ADDR2.address >>  6) & 077;
3200 #endif
3201               break;
3202 
3203             case CTA9:
3204 #ifdef EIS_PTR
3205               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3206               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3207 #else
3208               c1 = (e -> ADDR2.address >> 9) & 0777;
3209               c2 = (e -> ADDR2.address     ) & 0777;
3210 #endif
3211               break;
3212           }
3213       }
3214     else
3215       {
3216         c1 = EISget469 (2, 0);
3217         c2 = EISget469 (2, 1);
3218       }
3219 
3220 #ifdef EIS_PTR3
3221     switch (TA1) // Use TA1, not TA2
3222 #else
3223     switch (e -> TA1) // Use TA1, not TA2
3224 #endif
3225       {
3226         case CTA4:
3227           c1 &= 017;    // keep 4-bits
3228           c2 &= 017;    // keep 4-bits
3229           break;
3230 
3231         case CTA6:
3232           c1 &= 077;    // keep 6-bits
3233           c2 &= 077;    // keep 6-bits
3234           break;
3235 
3236         case CTA9:
3237           c1 &= 0777;   // keep 9-bits
3238           c2 &= 0777;   // keep 9-bits
3239           break;
3240       }
3241 
3242     PNL (L68_ (if (e->N1 < 128)
3243       DU_CYCLE_FLEN_128;))
3244 
3245     word9 yCharn11;
3246     word9 yCharn12;
3247     if (e -> N1)
3248       {
3249         uint limit = e -> N1 - 1;
3250         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3251           {
3252             yCharn11 = EISget469 (1, cpu.du.CHTALLY);
3253             yCharn12 = EISget469 (1, cpu.du.CHTALLY + 1);
3254             if (yCharn11 == c1 && yCharn12 == c2)
3255               break;
3256           }
3257         SC_I_TALLY (cpu.du.CHTALLY == limit);
3258       }
3259     else
3260       {
3261         SET_I_TALLY;
3262       }
3263 
3264     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3265     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3266     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3267 
3268     cleanupOperandDescriptor (1);
3269     cleanupOperandDescriptor (2);
3270     cleanupOperandDescriptor (3);
3271  }
3272 
3273 /*
3274  * SCDR - Scan Characters Double Reverse
3275  */
3276 
3277 void scdr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3278   {
3279     EISstruct * e = & cpu.currentEISinstruction;
3280 
3281     // For i = 1, 2, ..., N1-1
3282     //   C(Y-charn1)N1-i-1,N1-i :: C(Y-charn2)0,1
3283     // On instruction completion, if a match was found:
3284     //   00...0 → C(Y3)0,11
3285     //   i-1 → C(Y3)12,35
3286     // If no match was found:
3287     //   00...0 → C(Y3)0,11
3288     //      N1-1→ C(Y3)12,35
3289     //
3290 
3291     // The REG field of MF1 is checked for a legal code. If DU is specified in
3292     // the REG field of MF2 in one of the four multiword instructions (SCD,
3293     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3294     // the character or characters are arranged within the 18 bits of the word
3295     // address portion of the operand descriptor.
3296 
3297     fault_ipr_subtype_ mod_fault = 0;
3298 
3299 #ifndef EIS_SETUP
3300     setupOperandDescriptor(1, &mod_fault);
3301     setupOperandDescriptor(2, &mod_fault);
3302     setupOperandDescriptorCache(3);
3303 #endif
3304 
3305     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
3306     parseAlphanumericOperandDescriptor(2, 1, true, &mod_fault); // Use TA1
3307     parseArgOperandDescriptor (3, &mod_fault);
3308 
3309     L68_ (
3310       // L68 raises it immediately
3311       if (mod_fault)
3312         {
3313           doFault (FAULT_IPR,
3314                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3315                    "Illegal modifier");
3316         }
3317     )
3318 
3319     // Bits 0-10 MBZ
3320     if (IWB_IRODD & 0777600000000)
3321       {
3322         //sim_printf ("scdr %12"PRIo64"\n", IWB_IRODD);
3323         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scdr 0-10 MBZ");
3324       }
3325 
3326     // Bit 23 of OP1 MBZ
3327     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3328       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op1 23 MBZ");
3329 
3330     // Bits 18-28. 30-31 of OP3 MBZ
3331     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3332       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op3 18-28. 30-31 MBZ");
3333 
3334     DPS8M_ (
3335       // DPS8M raises it delayed
3336       if (mod_fault)
3337         {
3338           doFault (FAULT_IPR,
3339                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3340                    "Illegal modifier");
3341         }
3342     )
3343 
3344     // Both the string and the test character pair are treated as the data type
3345     // given for the string, TA1. A data type given for the test character
3346     // pair, TA2, is ignored.
3347 
3348     // fetch 'test' char - double
3349     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3350     // instruction word does not contain an operand descriptor for the test
3351     // character; instead, it contains the test character as a direct upper
3352     // operand in bits 0,8.
3353 
3354     word9 c1 = 0;
3355     word9 c2 = 0;
3356 
3357     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3358       {
3359         // per Bull RJ78, p. 5-45
3360 #ifdef EIS_PTR3
3361         switch (TA1) // Use TA1, not TA2
3362 #else
3363         switch (e -> TA1)
3364 #endif
3365           {
3366             case CTA4:
3367 #ifdef EIS_PTR
3368               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3369               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3370 #else
3371               c1 = (e -> ADDR2.address >> 13) & 017;
3372               c2 = (e -> ADDR2.address >>  9) & 017;
3373 #endif
3374               break;
3375 
3376             case CTA6:
3377 #ifdef EIS_PTR
3378               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3379               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3380 #else
3381               c1 = (e -> ADDR2.address >> 12) & 077;
3382               c2 = (e -> ADDR2.address >>  6) & 077;
3383 #endif
3384               break;
3385 
3386             case CTA9:
3387 #ifdef EIS_PTR
3388               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3389               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3390 #else
3391               c1 = (e -> ADDR2.address >> 9) & 0777;
3392               c2 = (e -> ADDR2.address     ) & 0777;
3393 #endif
3394               break;
3395           }
3396       }
3397     else
3398       {
3399         c1 = EISget469 (2, 0);
3400         c2 = EISget469 (2, 1);
3401       }
3402 
3403 #ifdef EIS_PTR3
3404     switch (TA1) // Use TA1, not TA2
3405 #else
3406     switch (e -> TA1) // Use TA1, not TA2
3407 #endif
3408       {
3409         case CTA4:
3410           c1 &= 017;    // keep 4-bits
3411           c2 &= 017;    // keep 4-bits
3412           break;
3413 
3414         case CTA6:
3415           c1 &= 077;    // keep 6-bits
3416           c2 &= 077;    // keep 6-bits
3417           break;
3418 
3419         case CTA9:
3420           c1 &= 0777;   // keep 9-bits
3421           c2 &= 0777;   // keep 9-bits
3422           break;
3423       }
3424 
3425     word9 yCharn11;
3426     word9 yCharn12;
3427 
3428     PNL (L68_ (if (e->N1 < 128)
3429       DU_CYCLE_FLEN_128;))
3430 
3431     if (e -> N1)
3432       {
3433         uint limit = e -> N1 - 1;
3434 
3435         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3436           {
3437             yCharn11 = EISget469 (1, limit - cpu.du.CHTALLY - 1);
3438             yCharn12 = EISget469 (1, limit - cpu.du.CHTALLY);
3439 
3440             if (yCharn11 == c1 && yCharn12 == c2)
3441                 break;
3442           }
3443         SC_I_TALLY (cpu.du.CHTALLY == limit);
3444       }
3445     else
3446       {
3447         SET_I_TALLY;
3448       }
3449 
3450     //word36 CY3 = bitfieldInsert36(0, cpu.du.CHTALLY, 0, 24);
3451     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3452     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3453 
3454     cleanupOperandDescriptor (1);
3455     cleanupOperandDescriptor (2);
3456     cleanupOperandDescriptor (3);
3457   }
3458 
3459 /*
3460  * SCM - Scan with Mask
3461  */
3462 
3463 void scm (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3464   {
3465     EISstruct * e = & cpu.currentEISinstruction;
3466 
3467     // For characters i = 1, 2, ..., N1
3468     //   For bits j = 0, 1, ..., 8
3469     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j ⊕ (C(Y-charn2)0)j)
3470     //      If C(Z)0,8 = 00...0, then
3471     //           00...0 → C(Y3)0,11
3472     //           i-1 → C(Y3)12,35
3473     //      otherwise, continue scan of C(Y-charn1)
3474     // If a masked character match was not found, then
3475     //   00...0 → C(Y3)0,11
3476     //   N1 → C(Y3)12,35
3477 
3478     // Starting at location YC1, the L1 type TA1 characters are masked and
3479     // compared with the assumed type TA1 character contained either in
3480     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3481     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3482     // mask is right-justified in bit positions 0-8 of the instruction word.
3483     // Each bit position of the mask that is a 1 prevents that bit position in
3484     // the two characters from entering into the compare.
3485 
3486     // The masked compare operation continues until either a match is found or
3487     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3488     // incremented by 1. When a match is found or when the L1 tally runs out,
3489     // this count is stored right-justified in bits 12-35 of location Y3 and
3490     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3491     // string remain unchanged. The RL bit of the MF2 field is not used.
3492 
3493     // The REG field of MF1 is checked for a legal code. If DU is specified in
3494     // the REG field of MF2 in one of the four multiword instructions (SCD,
3495     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3496     // the character or characters are arranged within the 18 bits of the word
3497     // address portion of the operand descriptor.
3498 
3499     fault_ipr_subtype_ mod_fault = 0;
3500 
3501 #ifndef EIS_SETUP
3502     setupOperandDescriptor (1, &mod_fault);
3503     setupOperandDescriptor (2, &mod_fault);
3504     setupOperandDescriptorCache (3);
3505 #endif
3506 
3507     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3508     parseAlphanumericOperandDescriptor (2, 1, true, &mod_fault);
3509     parseArgOperandDescriptor (3, &mod_fault);
3510 
3511     L68_ (
3512       // L68 raises it immediately
3513       if (mod_fault)
3514         {
3515           doFault (FAULT_IPR,
3516                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3517                    "Illegal modifier");
3518         }
3519     )
3520 
3521     // Bits 9-10 MBZ
3522     if (IWB_IRODD & 0000600000000)
3523       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scm 9-10 MBZ");
3524 
3525     // Bit 23 of OP1 MBZ
3526     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3527       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op1 23 MBZ");
3528 
3529     // Bits 18-28, 39-31 of OP3 MBZ
3530     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3531       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op3 18-28, 39-31 MBZ");
3532 
3533     DPS8M_ (
3534       // DPS8M raises it delayed
3535       if (mod_fault)
3536         {
3537           doFault (FAULT_IPR,
3538                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3539                    "Illegal modifier");
3540         }
3541     )
3542 
3543     // Both the string and the test character pair are treated as the data type
3544     // given for the string, TA1. A data type given for the test character
3545     // pair, TA2, is ignored.
3546 
3547     // get 'mask'
3548     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3549 
3550     // fetch 'test' char
3551     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3552     // instruction word does not contain an operand descriptor for the test
3553     // character; instead, it contains the test character as a direct upper
3554     // operand in bits 0,8.
3555 
3556     word9 ctest = 0;
3557     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3558       {
3559         word18 duo = GETHI (e -> OP2);
3560         // per Bull RJ78, p. 5-45
3561 #ifdef EIS_PTR3
3562         switch (TA1) // Use TA1, not TA2
3563 #else
3564         switch (e -> TA1)
3565 #endif
3566           {
3567             case CTA4:
3568               ctest = (duo >> 13) & 017;
3569               break;
3570             case CTA6:
3571               ctest = (duo >> 12) & 077;
3572               break;
3573             case CTA9:
3574               ctest = (duo >> 9) & 0777;
3575               break;
3576           }
3577       }
3578     else
3579       {
3580         ctest = EISget469 (2, 0);
3581       }
3582 
3583 #ifdef EIS_PTR3
3584     switch (TA1) // Use TA1, not TA2
3585 #else
3586     switch (e -> TA1) // use TA1, not TA2
3587 #endif
3588       {
3589         case CTA4:
3590             ctest &= 017;    // keep 4-bits
3591             break;
3592         case CTA6:
3593             ctest &= 077;    // keep 6-bits
3594             break;
3595         case CTA9:
3596             ctest &= 0777;   // keep 9-bits
3597       }
3598 
3599     PNL (L68_ (if (e->N1 < 128)
3600       DU_CYCLE_FLEN_128;))
3601 
3602     uint limit = e -> N1;
3603 
3604     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3605       {
3606         word9 yCharn1 = EISget469 (1, cpu.du.CHTALLY);
3607         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3608         if (c == 0)
3609           {
3610             //00...0 → C(Y3)0,11
3611             //i-1 → C(Y3)12,35
3612             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3613             break;
3614           }
3615       }
3616     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3617     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3618 
3619     SC_I_TALLY (cpu.du.CHTALLY == limit);
3620 
3621     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3622 
3623     cleanupOperandDescriptor (1);
3624     cleanupOperandDescriptor (2);
3625     cleanupOperandDescriptor (3);
3626   }
3627 /*
3628  * SCMR - Scan with Mask in Reverse
3629  */
3630 
3631 void scmr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3632   {
3633     EISstruct * e = & cpu.currentEISinstruction;
3634 
3635     // For characters i = 1, 2, ..., N1
3636     //   For bits j = 0, 1, ..., 8
3637     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j ⊕ (C(Y-charn2)0)j)
3638     //      If C(Z)0,8 = 00...0, then
3639     //           00...0 → C(Y3)0,11
3640     //           i-1 → C(Y3)12,35
3641     //      otherwise, continue scan of C(Y-charn1)
3642     // If a masked character match was not found, then
3643     //   00...0 → C(Y3)0,11
3644     //   N1 → C(Y3)12,35
3645 
3646     // Starting at location YC1, the L1 type TA1 characters are masked and
3647     // compared with the assumed type TA1 character contained either in
3648     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3649     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3650     // mask is right-justified in bit positions 0-8 of the instruction word.
3651     // Each bit position of the mask that is a 1 prevents that bit position in
3652     // the two characters from entering into the compare.
3653 
3654     // The masked compare operation continues until either a match is found or
3655     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3656     // incremented by 1. When a match is found or when the L1 tally runs out,
3657     // this count is stored right-justified in bits 12-35 of location Y3 and
3658     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3659     // string remain unchanged. The RL bit of the MF2 field is not used.
3660 
3661     // The REG field of MF1 is checked for a legal code. If DU is specified in
3662     // the REG field of MF2 in one of the four multiword instructions (SCD,
3663     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3664     // the character or characters are arranged within the 18 bits of the word
3665     // address portion of the operand descriptor.
3666 
3667     fault_ipr_subtype_ mod_fault = 0;
3668 
3669 #ifndef EIS_SETUP
3670     setupOperandDescriptor (1, &mod_fault);
3671     setupOperandDescriptor (2, &mod_fault);
3672     setupOperandDescriptorCache (3);
3673 #endif
3674 
3675     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3676     parseAlphanumericOperandDescriptor (2, 1, true, &mod_fault);
3677     parseArgOperandDescriptor (3, &mod_fault);
3678 
3679     L68_ (
3680       // L68 raises it immediately
3681       if (mod_fault)
3682         {
3683           doFault (FAULT_IPR,
3684                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3685                    "Illegal modifier");
3686         }
3687     )
3688 
3689     // Bits 9-10 MBZ
3690     if (IWB_IRODD & 0000600000000)
3691       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scmr 9-10 MBZ");
3692 
3693     // Bit 23 of OP1 MBZ
3694     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3695       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op1 23 MBZ");
3696 
3697     // Bits 18 of OP3 MBZ
3698     //if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000400000)
3699     //  doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18 MBZ");
3700 
3701     // Bits 18-28, 39-31 of OP3 MBZ
3702     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3703       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18-28, 39-31 MBZ");
3704 
3705     DPS8M_ (
3706       // DPS8M raises it delayed
3707       if (mod_fault)
3708         {
3709           doFault (FAULT_IPR,
3710                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3711                    "Illegal modifier");
3712         }
3713     )
3714 
3715     // Both the string and the test character pair are treated as the data type
3716     // given for the string, TA1. A data type given for the test character
3717     // pair, TA2, is ignored.
3718 
3719     // get 'mask'
3720     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3721 
3722     // fetch 'test' char
3723     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3724     // instruction word does not contain an operand descriptor for the test
3725     // character; instead, it contains the test character as a direct upper
3726     // operand in bits 0,8.
3727 
3728     word9 ctest = 0;
3729     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3730       {
3731         word18 duo = GETHI (e -> OP2);
3732         // per Bull RJ78, p. 5-45
3733 #ifdef EIS_PTR3
3734         switch (TA1) // Use TA1, not TA2
3735 #else
3736         switch (e -> TA1)
3737 #endif
3738           {
3739             case CTA4:
3740               ctest = (duo >> 13) & 017;
3741               break;
3742             case CTA6:
3743               ctest = (duo >> 12) & 077;
3744               break;
3745             case CTA9:
3746               ctest = (duo >> 9) & 0777;
3747               break;
3748           }
3749       }
3750     else
3751       {
3752         ctest = EISget469 (2, 0);
3753       }
3754 
3755 #ifdef EIS_PTR3
3756     switch (TA1) // Use TA1, not TA2
3757 #else
3758     switch (e -> TA1) // use TA1, not TA2
3759 #endif
3760       {
3761         case CTA4:
3762             ctest &= 017;    // keep 4-bits
3763             break;
3764         case CTA6:
3765             ctest &= 077;    // keep 6-bits
3766             break;
3767         case CTA9:
3768             ctest &= 0777;   // keep 9-bits
3769       }
3770 
3771     PNL (L68_ (if (e->N1 < 128)
3772       DU_CYCLE_FLEN_128;))
3773 
3774     uint limit = e -> N1;
3775     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3776       {
3777         word9 yCharn1 = EISget469 (1, limit - cpu.du.CHTALLY - 1);
3778         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3779         if (c == 0)
3780           {
3781             //00...0 → C(Y3)0,11
3782             //i-1 → C(Y3)12,35
3783             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3784             break;
3785           }
3786       }
3787     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3788     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3789 
3790     SC_I_TALLY (cpu.du.CHTALLY == limit);
3791 
3792     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3793 
3794     cleanupOperandDescriptor (1);
3795     cleanupOperandDescriptor (2);
3796     cleanupOperandDescriptor (3);
3797   }
3798 
3799 /*
3800  * TCT - Test Character and Translate
3801  */
3802 
3803 
3804 
3805 
3806 
3807 
3808 
3809 
3810 
3811 
3812 
3813 
3814 
3815 
3816 
3817 
3818 
3819 
3820 
3821 
3822 
3823 
3824 static word9 xlate (EISaddr * xlatTbl, uint dstTA, uint c)
     /* [previous][next][first][last][top][bottom][index][help] */
3825   {
3826     uint idx = (c / 4) & 0177;      // max 128-words (7-bit index)
3827     word36 entry = EISReadIdx(xlatTbl, idx);
3828 
3829     uint pos9 = c % 4;      // lower 2-bits
3830     word9 cout = GETBYTE (entry, pos9);
3831     switch (dstTA)
3832       {
3833         case CTA4:
3834           return cout & 017;
3835         case CTA6:
3836           return cout & 077;
3837         case CTA9:
3838           return cout;
3839       }
3840     return 0;
3841   }
3842 
3843 void tct (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3844   {
3845     EISstruct * e = & cpu.currentEISinstruction;
3846 
3847     // For i = 1, 2, ..., N1
3848     //   m = C(Y-charn1)i-1
3849     //   If C(Y-char92)m ≠ 00...0, then
3850     //     C(Y-char92)m → C(Y3)0,8
3851     //     000 → C(Y3)9,11
3852     //     i-1 → C(Y3)12,35
3853     //   otherwise, continue scan of C(Y-charn1)
3854     // If a non-zero table entry was not found, then 00...0 → C(Y3)0,11
3855     // N1 → C(Y3)12,35
3856     //
3857     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
3858     // otherwise, OFF
3859     //
3860     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
3861     // then characters from C(Y-charn1) are high-order zero filled in forming
3862     // the table index, m.
3863     // Instruction execution proceeds until a non-zero table entry is found or
3864     // the string length count is exhausted.
3865     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
3866     // on a word boundary.
3867 
3868     fault_ipr_subtype_ mod_fault = 0;
3869 
3870 #ifndef EIS_SETUP
3871     setupOperandDescriptor (1, &mod_fault);
3872     setupOperandDescriptorCache (2);
3873     setupOperandDescriptorCache (3);
3874 #endif
3875 
3876     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3877     parseArgOperandDescriptor (2, &mod_fault);
3878     parseArgOperandDescriptor (3, &mod_fault);
3879 
3880     L68_ (
3881       // L68 raises it immediately
3882       if (mod_fault)
3883         {
3884           doFault (FAULT_IPR,
3885                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3886                    "Illegal modifier");
3887         }
3888     )
3889 
3890     // Bits 0-17 MBZ
3891     if (IWB_IRODD & 0777777000000)
3892       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tct 0-17 MBZ");
3893 
3894     // Bit 23 of OP1 MBZ
3895     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3896       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op1 23 MBZ");
3897 
3898     // Bits 18-28, 39-31 of OP2 MBZ
3899     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
3900       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op2 18-28, 39-31 MBZ");
3901 
3902     // Bits 18-28, 39-31 of OP3 MBZ
3903     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3904       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op3 18-28, 39-31 MBZ");
3905 
3906     DPS8M_ (
3907       // DPS8M raises it delayed
3908       if (mod_fault)
3909         {
3910           doFault (FAULT_IPR,
3911                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3912                    "Illegal modifier");
3913         }
3914     )
3915 
3916 #ifdef EIS_PTR3
3917     sim_debug (DBG_TRACEEXT, & cpu_dev,
3918                "TCT CN1: %d TA1: %d\n", e -> CN1, TA1);
3919 #else
3920     sim_debug (DBG_TRACEEXT, & cpu_dev,
3921                "TCT CN1: %d TA1: %d\n", e -> CN1, e -> TA1);
3922 #endif
3923 
3924     uint srcSZ = 0;
3925 
3926 #ifdef EIS_PTR3
3927     switch (TA1)
3928 #else
3929     switch (e -> TA1)
3930 #endif
3931       {
3932         case CTA4:
3933             srcSZ = 4;
3934             break;
3935         case CTA6:
3936             srcSZ = 6;
3937             break;
3938         case CTA9:
3939             srcSZ = 9;
3940             break;
3941       }
3942 
3943     // ISOLTS-878 01h asserts no prepaging
3944 
3945 
3946 
3947 
3948 
3949 
3950 
3951 
3952 
3953 
3954 
3955 
3956 
3957 
3958 
3959 
3960 
3961 
3962 
3963 
3964 
3965 
3966 
3967 
3968 
3969 
3970 
3971 
3972 
3973 
3974 
3975 
3976 
3977 
3978 
3979 
3980 
3981 
3982     word36 CY3 = 0;
3983 
3984     sim_debug (DBG_TRACEEXT, & cpu_dev,
3985                "TCT N1 %d\n", e -> N1);
3986 
3987     PNL (L68_ (if (e->N1 < 128)
3988       DU_CYCLE_FLEN_128;))
3989 
3990     for ( ; cpu.du.CHTALLY < e -> N1; cpu.du.CHTALLY ++)
3991       {
3992         word9 c = EISget469 (1, cpu.du.CHTALLY); // get src char
3993 
3994         uint m = 0;
3995 
3996         switch (srcSZ)
3997           {
3998             case 4:
3999               m = c & 017;    // truncate upper 2-bits
4000               break;
4001             case 6:
4002               m = c & 077;    // truncate upper 3-bits
4003               break;
4004             case 9:
4005               m = c;          // keep all 9-bits
4006               break;              // should already be 0-filled
4007           }
4008 
4009         word9 cout = xlate (&e->ADDR2, CTA9, m);
4010 
4011         sim_debug (DBG_TRACEEXT, & cpu_dev,
4012                    "TCT c %03o %c cout %03o %c\n",
4013                    m, isprint ((int) m) ? '?' : (char) m,
4014                    cout, isprint ((int) cout) ? '?' : (char) cout);
4015 
4016         if (cout)
4017           {
4018             // CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4019             CY3 = setbits36_9 (0, 0, cout);
4020             break;
4021           }
4022       }
4023 
4024     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4025 
4026     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4027     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4028     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
4029 
4030     cleanupOperandDescriptor (1);
4031     cleanupOperandDescriptor (2);
4032     cleanupOperandDescriptor (3);
4033   }
4034 
4035 void tctr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
4036   {
4037     EISstruct * e = & cpu.currentEISinstruction;
4038 
4039     // For i = 1, 2, ..., N1
4040     //   m = C(Y-charn1)N1-i
4041     //   If C(Y-char92)m ≠ 00...0, then
4042     //     C(Y-char92)m → C(Y3)0,8
4043     //     000 → C(Y3)9,11
4044     //     i-1 → C(Y3)12,35
4045     //   otherwise, continue scan of C(Y-charn1) If a non-zero table entry was
4046     //   not found, then
4047     // 00...0 → C(Y3)0,11
4048     // N1 → C(Y3)12,35
4049     //
4050     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
4051     // otherwise, OFF
4052     //
4053     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
4054     // then characters from C(Y-charn1) are high-order zero filled in forming
4055     // the table index, m.
4056 
4057     // Instruction execution proceeds until a non-zero table entry is found or
4058     // the string length count is exhausted.
4059 
4060     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
4061     // on a word boundary.
4062 
4063     fault_ipr_subtype_ mod_fault = 0;
4064 
4065 #ifndef EIS_SETUP
4066     setupOperandDescriptor (1, &mod_fault);
4067     setupOperandDescriptorCache (2);
4068     setupOperandDescriptorCache (3);
4069 #endif
4070 
4071     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
4072     parseArgOperandDescriptor (2, &mod_fault);
4073     parseArgOperandDescriptor (3, &mod_fault);
4074 
4075     L68_ (
4076       // L68 raises it immediately
4077       if (mod_fault)
4078         {
4079           doFault (FAULT_IPR,
4080                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4081                    "Illegal modifier");
4082         }
4083     )
4084 
4085     // Bits 0-17 MBZ
4086     if (IWB_IRODD & 0777777000000)
4087       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tctr 0-17 MBZ");
4088 
4089     // Bit 23 of OP1 MBZ
4090     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4091       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op1 23 MBZ");
4092 
4093     // Bits 18-28, 39-31 of OP2 MBZ
4094     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
4095       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op2 18-28, 39-31 MBZ");
4096 
4097     // Bits 18-28, 39-31 of OP3 MBZ
4098     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
4099       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op3 18-28, 39-31 MBZ");
4100 
4101     DPS8M_ (
4102       // DPS8M raises it delayed
4103       if (mod_fault)
4104         {
4105           doFault (FAULT_IPR,
4106                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4107                    "Illegal modifier");
4108         }
4109     )
4110 
4111 #ifdef EIS_PTR3
4112     sim_debug (DBG_TRACEEXT, & cpu_dev,
4113                "TCTR CN1: %d TA1: %d\n", e -> CN1, TA1);
4114 #else
4115     sim_debug (DBG_TRACEEXT, & cpu_dev,
4116                "TCTR CN1: %d TA1: %d\n", e -> CN1, e -> TA1);
4117 #endif
4118 
4119     uint srcSZ = 0;
4120 
4121 #ifdef EIS_PTR3
4122     switch (TA1)
4123 #else
4124     switch (e -> TA1)
4125 #endif
4126       {
4127         case CTA4:
4128             srcSZ = 4;
4129             break;
4130         case CTA6:
4131             srcSZ = 6;
4132             break;
4133         case CTA9:
4134             srcSZ = 9;
4135             break;
4136       }
4137 
4138     // ISOLTS-878 01i asserts no prepaging
4139 
4140 
4141 
4142 
4143 
4144 
4145 
4146 
4147 
4148 
4149 
4150 
4151 
4152 
4153 
4154 
4155 
4156 
4157 
4158 
4159 
4160 
4161 
4162 
4163 
4164 
4165 
4166 
4167 
4168 
4169 
4170 
4171 
4172 
4173 
4174 
4175 
4176 
4177     word36 CY3 = 0;
4178 
4179     sim_debug (DBG_TRACEEXT, & cpu_dev,
4180                "TCT N1 %d\n", e -> N1);
4181 
4182     PNL (L68_ (if (e->N1 < 128)
4183       DU_CYCLE_FLEN_128;))
4184 
4185     uint limit = e -> N1;
4186     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
4187       {
4188         word9 c = EISget469 (1, limit - cpu.du.CHTALLY - 1); // get src char
4189 
4190         uint m = 0;
4191 
4192         switch (srcSZ)
4193           {
4194             case 4:
4195               m = c & 017;    // truncate upper 2-bits
4196               break;
4197             case 6:
4198               m = c & 077;    // truncate upper 3-bits
4199               break;
4200             case 9:
4201               m = c;          // keep all 9-bits
4202               break;              // should already be 0-filled
4203           }
4204 
4205         word9 cout = xlate (&e->ADDR2, CTA9, m);
4206 
4207         sim_debug (DBG_TRACEEXT, & cpu_dev,
4208                    "TCT c %03o %c cout %03o %c\n",
4209                    m, isprint ((int) m) ? '?' : (char) m,
4210                    cout, isprint ((int) cout) ? '?' : (char) cout);
4211 
4212         if (cout)
4213           {
4214             //CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4215             CY3 = setbits36_9 (0, 0, cout);
4216             break;
4217           }
4218       }
4219 
4220     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4221 
4222     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4223     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4224     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
4225 
4226     cleanupOperandDescriptor (1);
4227     cleanupOperandDescriptor (2);
4228     cleanupOperandDescriptor (3);
4229   }
4230 
4231 /*
4232  * MLR - Move Alphanumeric Left to Right
4233  *
4234  * (Nice, simple instruction if it weren't for the stupid overpunch stuff that ruined it!!!!)
4235  */
4236 
4237 /*
4238  * does 6-bit char represent a GEBCD negative overpunch? if so, which numeral?
4239  * Refer to Bull NovaScale 9000 RJ78 Rev2 p11-178
4240  */
4241 
4242 
4243 
4244 
4245 
4246 
4247 
4248 
4249 
4250 
4251 
4252 
4253 
4254 
4255 
4256 
4257 
4258 
4259 
4260 
4261 
4262 
4263 
4264 
4265 
4266 // RJ78 p.11-178,D-6
4267 static bool isGBCDOvp (uint c, bool * isNeg)
     /* [previous][next][first][last][top][bottom][index][help] */
4268   {
4269     if (c & 020)
4270       {
4271         * isNeg = false;
4272         return true;
4273       }
4274     if (c & 040)
4275       {
4276         * isNeg = true;
4277         return true;
4278       }
4279     return false;
4280   }
4281 
4282 // Applies to both MLR and MRL
4283 //
4284 // If L1 is greater than L2, the least significant (L1-L2) characters are not moved and
4285 // the Truncation indicator is set. If L1 is less than L2, bits 0-8, 3-8, or 5-8 of the FILL
4286 // character (depending on TA2) are inserted as the least significant (L2-L1)
4287 // characters. If L1 is less than L2, bit 0 of C(FILL) = 1, TA1 = 01, and TA2 = 10
4288 // (6-4 move); the hardware looks for a 6-bit overpunched sign. If a negative
4289 // overpunch sign is found, a negative sign (octal 15) is inserted as the last FILL
4290 // character. If a negative overpunch sign is not found, a positive sign (octal 14) is
4291 // inserted as the last FILL character
4292 
4293 void mlr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
4294   {
4295     EISstruct * e = & cpu.currentEISinstruction;
4296 
4297     // For i = 1, 2, ..., minimum (N1,N2)
4298     //     C(Y-charn1)N1-i → C(Y-charn2)N2-i
4299     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4300     //    C(FILL) → C(Y-charn2)N2-i
4301     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4302 
4303     fault_ipr_subtype_ mod_fault = 0;
4304 
4305 #ifndef EIS_SETUP
4306     setupOperandDescriptor (1, &mod_fault);
4307     setupOperandDescriptor (2, &mod_fault);
4308     //setupOperandDescriptorCache (3);
4309 #endif
4310 
4311     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
4312     parseAlphanumericOperandDescriptor(2, 2, false, &mod_fault);
4313 
4314     L68_ (
4315       // L68 raises it immediately
4316       if (mod_fault)
4317         {
4318           doFault (FAULT_IPR,
4319                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4320                    "Illegal modifier");
4321         }
4322     )
4323 
4324     // Bit 10 MBZ
4325     if (IWB_IRODD & 0000200000000)
4326       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mlr 10 MBZ");
4327 
4328     // Bit 23 of OP1 MBZ
4329     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4330       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op1 23 MBZ");
4331 
4332     // Bit 23 of OP2 MBZ
4333     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4334       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op2 23 MBZ");
4335 
4336     DPS8M_ (
4337       // DPS8M raises it delayed
4338       if (mod_fault)
4339         {
4340           doFault (FAULT_IPR,
4341                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4342                    "Illegal modifier");
4343         }
4344     )
4345 
4346     int srcSZ = 0, dstSZ = 0;
4347 
4348 #ifdef EIS_PTR3
4349     switch (TA1)
4350 #else
4351     switch (e -> TA1)
4352 #endif
4353       {
4354         case CTA4:
4355           srcSZ = 4;
4356           break;
4357         case CTA6:
4358           srcSZ = 6;
4359           break;
4360         case CTA9:
4361           srcSZ = 9;
4362           break;
4363       }
4364 
4365 #ifdef EIS_PTR3
4366     switch (TA2)
4367 #else
4368     switch (e -> TA2)
4369 #endif
4370       {
4371         case CTA4:
4372           dstSZ = 4;
4373           break;
4374         case CTA6:
4375           dstSZ = 6;
4376           break;
4377         case CTA9:
4378           dstSZ = 9;
4379           break;
4380       }
4381 
4382     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4383 
4384     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4385     word9 fillT = fill;  // possibly truncated fill pattern
4386 
4387     // play with fill if we need to use it
4388     switch (dstSZ)
4389       {
4390         case 4:
4391           fillT = fill & 017;    // truncate upper 5-bits
4392           break;
4393         case 6:
4394           fillT = fill & 077;    // truncate upper 3-bits
4395           break;
4396       }
4397 
4398     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4399     // and the truncation indicator is set ON.
4400 
4401     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4402     // characters are high-order truncated as they are moved to C(Y-charn2). No
4403     // character conversion takes place.
4404 
4405     // The user of string replication or overlaying is warned that the decimal
4406     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4407     // units of Y-block8 words and that the overlayed string, C(Y-charn2), is
4408     // not returned to main memory until the unit of Y-block8 words is filled or
4409     // the instruction completes.
4410 
4411     // If T = 1 and the truncation indicator is set ON by execution of the
4412     // instruction, then a truncation (overflow) fault occurs.
4413 
4414     // Attempted execution with the xed instruction causes an illegal procedure
4415     // fault.
4416 
4417     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4418     // illegal procedure fault.
4419 
4420     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4421       DU_CYCLE_FLEN_128;))
4422 
4423 #ifdef EIS_PTR3
4424     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4425                (TA2 == 2); // (6-4 move)
4426 #else
4427     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4428                (e -> TA2 == 2); // (6-4 move)
4429 #endif
4430     //word9 on;     // number overpunch represents (if any)
4431     bool isNeg = false;
4432     //bool bOvp = false;  // true when a negative overpunch character has been
4433                         // found @ N1-1
4434 
4435 #ifdef EIS_PTR3
4436     sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR TALLY %u TA1 %u TA2 %u N1 %u N2 %u CN1 %u CN2 %u\n", cpu.du.CHTALLY, TA1, TA2, e -> N1, e -> N2, e -> CN1, e -> CN2);
4437 #else
4438     sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR TALLY %u TA1 %u TA2 %u N1 %u N2 %u CN1 %u CN2 %u\n", cpu.du.CHTALLY, e -> TA1, e -> TA2, e -> N1, e -> N2, e -> CN1, e -> CN2);
4439 #endif
4440 
4441 //
4442 // Multics frequently uses certain code sequences which are easily detected
4443 // and optimized; eg. it uses the MLR instruction to copy or zero segments.
4444 //
4445 // The MLR implementation is correct, not efficient. Copy invokes 12 append
4446 // cycles per word, and fill 8.
4447 //
4448 
4449 //
4450 // Page copy
4451 //
4452 
4453     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4454 #ifdef EIS_PTR3
4455         TA1 == CTA9 &&  // src and dst are both char 9
4456         TA2 == CTA9 &&
4457 #else
4458         e -> TA1 == CTA9 &&  // src and dst are both char 9
4459         e -> TA2 == CTA9 &&
4460 #endif
4461         (e -> N1 % (PGSZ * 4)) == 0 &&  // a page
4462         e -> N2 == e -> N1 && // the src is the same size as the dest.
4463         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4464         e -> CN2 == 0 &&
4465 #ifdef EIS_PTR
4466         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4467         (cpu.du.D2_PTR_W & PGMK) == 0)
4468 #else
4469         (e -> ADDR1.address & PGMK) == 0 &&
4470         (e -> ADDR2.address & PGMK) == 0)
4471 #endif
4472       {
4473         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #3\n");
4474         while (cpu.du.CHTALLY < e -> N1)
4475           {
4476             word36 pg [PGSZ];
4477             EISReadPage (& e -> ADDR1, cpu.du.CHTALLY / 4, pg);
4478             EISWritePage (& e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4479             cpu.du.CHTALLY += PGSZ * 4;
4480           }
4481         cleanupOperandDescriptor (1);
4482         cleanupOperandDescriptor (2);
4483         // truncation fault check does need to be checked for here since
4484         // it is known that N1 == N2
4485         CLR_I_TRUNC;
4486         return;
4487       }
4488 
4489 //
4490 // Page zero
4491 //
4492 
4493     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4494 #ifdef EIS_PTR3
4495         TA1 == CTA9 &&  // src and dst are both char 9
4496         TA2 == CTA9 &&
4497 #else
4498         e -> TA1 == CTA9 &&  // src and dst are both char 9
4499         e -> TA2 == CTA9 &&
4500 #endif
4501         e -> N1 == 0 && // the source is entirely fill
4502         (e -> N2 % (PGSZ * 4)) == 0 &&  // a page
4503         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4504         e -> CN2 == 0 &&
4505 #ifdef EIS_PTR
4506         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4507         (cpu.du.D2_PTR_W& PGMK) == 0)
4508 #else
4509         (e -> ADDR1.address & PGMK) == 0 &&
4510         (e -> ADDR2.address & PGMK) == 0)
4511 #endif
4512       {
4513         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #4\n");
4514         word36 pg [PGSZ];
4515         if (fill)
4516           {
4517             word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4518             for (uint i = 0; i < PGSZ; i ++)
4519               pg [i] = w;
4520           }
4521         else
4522           {
4523            memset (pg, 0, sizeof (pg));
4524           }
4525         while (cpu.du.CHTALLY < e -> N2)
4526           {
4527             EISWritePage (& e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4528             cpu.du.CHTALLY += PGSZ * 4;
4529           }
4530         cleanupOperandDescriptor (1);
4531         cleanupOperandDescriptor (2);
4532         // truncation fault check does need to be checked for here since
4533         // it is known that N1 == N2
4534         CLR_I_TRUNC;
4535         return;
4536       }
4537 
4538 // Test for the case of aligned word move; and do things a word at a time,
4539 // instead of a byte at a time...
4540 
4541 #ifdef EIS_PTR3
4542     if (TA1 == CTA9 &&  // src and dst are both char 9
4543         TA2 == CTA9 &&
4544 #else
4545     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4546         e -> TA2 == CTA9 &&
4547 #endif
4548         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4549         e -> N2 == e -> N1 && // the src is the same size as the dest.
4550         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4551         e -> CN2 == 0)
4552       {
4553         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #1\n");
4554         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4555           {
4556             uint n = cpu.du.CHTALLY / 4;
4557             word36 w = EISReadIdx (& e -> ADDR1, n);
4558             EISWriteIdx (& e -> ADDR2, n, w, true);
4559           }
4560         cleanupOperandDescriptor (1);
4561         cleanupOperandDescriptor (2);
4562         // truncation fault check does need to be checked for here since
4563         // it is known that N1 == N2
4564         CLR_I_TRUNC;
4565         return;
4566       }
4567 
4568 // Test for the case of aligned word fill; and do things a word at a time,
4569 // instead of a byte at a time...
4570 
4571 #ifdef EIS_PTR3
4572     if (TA1 == CTA9 && // src and dst are both char 9
4573         TA2 == CTA9 &&
4574 #else
4575     if (e -> TA1 == CTA9 && // src and dst are both char 9
4576         e -> TA2 == CTA9 &&
4577 #endif
4578         e -> N1 == 0 && // the source is entirely fill
4579         e -> N2 % 4 == 0 && // a whole number of words in the dest
4580         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4581         e -> CN2 == 0)
4582       {
4583         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #2\n");
4584         word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4585         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4586           {
4587             uint n = cpu.du.CHTALLY / 4;
4588             EISWriteIdx (& e -> ADDR2, n, w, true);
4589           }
4590         cleanupOperandDescriptor (1);
4591         cleanupOperandDescriptor (2);
4592         // truncation fault check does need to be checked for here since
4593         // it is known that N1 <= N2
4594         CLR_I_TRUNC;
4595         return;
4596       }
4597 
4598     for ( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
4599       {
4600         word9 c = EISget469 (1, cpu.du.CHTALLY); // get src char
4601         word9 cout = 0;
4602 
4603 #ifdef EIS_PTR3
4604         if (TA1 == TA2)
4605 #else
4606         if (e -> TA1 == e -> TA2)
4607 #endif
4608           EISput469 (2, cpu.du.CHTALLY, c);
4609         else
4610           {
4611             // If data types are dissimilar (TA1 ≠ TA2), each character is
4612             // high-order truncated or zero filled, as appropriate, as it is
4613             // moved. No character conversion takes place.
4614             cout = c;
4615             switch (srcSZ)
4616               {
4617                 case 6:
4618                   switch(dstSZ)
4619                     {
4620                       case 4:
4621                         cout = c & 017;    // truncate upper 2-bits
4622                         break;
4623                       case 9:
4624                         break;              // should already be 0-filled
4625                     }
4626                   break;
4627                 case 9:
4628                   switch(dstSZ)
4629                     {
4630                       case 4:
4631                         cout = c & 017;    // truncate upper 5-bits
4632                         break;
4633                       case 6:
4634                         cout = c & 077;    // truncate upper 3-bits
4635                         break;
4636                     }
4637                   break;
4638               }
4639 
4640             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
4641             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
4642             // negative overpunch sign is found, then the minus sign character
4643             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
4644             // is placed in C(Y-charn2)N2-1.
4645 
4646             if (ovp && (cpu.du.CHTALLY == e -> N1 - 1))
4647               {
4648                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
4649                 // ISOLTS-838 01e, RJ78 p. 11-126
4650                 isGBCDOvp (c, & isNeg);
4651               }
4652             EISput469 (2, cpu.du.CHTALLY, cout);
4653           }
4654       }
4655 
4656     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4657     //    C(FILL) → C(Y-charn2)N2-i
4658     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4659     // characters are high-order truncated as they are moved to C(Y-charn2). No
4660     // character conversion takes place.
4661 
4662     if (e -> N1 < e -> N2)
4663       {
4664         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
4665           {
4666             // if there's an overpunch then the sign will be the last of the fill
4667             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
4668               {
4669                 if (isNeg)
4670                   EISput469 (2, cpu.du.CHTALLY, 015); // 015 is decimal -
4671                 else
4672                   EISput469 (2, cpu.du.CHTALLY, 014); // 014 is decimal +
4673               }
4674             else
4675               EISput469 (2, cpu.du.CHTALLY, fillT);
4676           }
4677     }
4678     cleanupOperandDescriptor (1);
4679     cleanupOperandDescriptor (2);
4680 
4681     if (e -> N1 > e -> N2)
4682       {
4683         SET_I_TRUNC;
4684         if (T && ! TST_I_OMASK)
4685           doFault (FAULT_OFL, fst_zero, "mlr truncation fault");
4686       }
4687     else
4688       CLR_I_TRUNC;
4689   }
4690 
4691 void mrl (void)
     /* [previous][next][first][last][top][bottom][index][help] */
4692   {
4693     EISstruct * e = & cpu.currentEISinstruction;
4694 
4695     // For i = 1, 2, ..., minimum (N1,N2)
4696     //     C(Y-charn1)N1-i → C(Y-charn2)N2-i
4697     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4698     //    C(FILL) → C(Y-charn2)N2-i
4699     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4700 
4701     fault_ipr_subtype_ mod_fault = 0;
4702 
4703 #ifndef EIS_SETUP
4704     setupOperandDescriptor (1, &mod_fault);
4705     setupOperandDescriptor (2, &mod_fault);
4706     //setupOperandDescriptorCache (3);
4707 #endif
4708 
4709     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
4710     parseAlphanumericOperandDescriptor(2, 2, false, &mod_fault);
4711 
4712     L68_ (
4713       // L68 raises it immediately
4714       if (mod_fault)
4715         {
4716           doFault (FAULT_IPR,
4717                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4718                    "Illegal modifier");
4719         }
4720     )
4721 
4722     // Bit 10 MBZ
4723     if (IWB_IRODD & 0000200000000)
4724       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mrl 10 MBZ");
4725 
4726     // Bit 23 of OP1 MBZ
4727     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4728       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op1 23 MBZ");
4729 
4730     // Bit 23 of OP2 MBZ
4731     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4732       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op2 23 MBZ");
4733 
4734     DPS8M_ (
4735       // DPS8M raises it delayed
4736       if (mod_fault)
4737         {
4738           doFault (FAULT_IPR,
4739                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4740                    "Illegal modifier");
4741         }
4742     )
4743 
4744     int srcSZ = 0, dstSZ = 0;
4745 
4746 #ifdef EIS_PTR3
4747     switch (TA1)
4748 #else
4749     switch (e -> TA1)
4750 #endif
4751       {
4752         case CTA4:
4753           srcSZ = 4;
4754           break;
4755         case CTA6:
4756           srcSZ = 6;
4757           break;
4758         case CTA9:
4759           srcSZ = 9;
4760           break;
4761       }
4762 
4763 #ifdef EIS_PTR3
4764     switch (TA2)
4765 #else
4766     switch (e -> TA2)
4767 #endif
4768       {
4769         case CTA4:
4770           dstSZ = 4;
4771           break;
4772         case CTA6:
4773           dstSZ = 6;
4774           break;
4775         case CTA9:
4776           dstSZ = 9;
4777           break;
4778       }
4779 
4780     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4781 
4782     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4783     word9 fillT = fill;  // possibly truncated fill pattern
4784 
4785     // play with fill if we need to use it
4786     switch (dstSZ)
4787       {
4788         case 4:
4789           fillT = fill & 017;    // truncate upper 5-bits
4790           break;
4791         case 6:
4792           fillT = fill & 077;    // truncate upper 3-bits
4793           break;
4794       }
4795 
4796     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4797     // and the truncation indicator is set ON.
4798 
4799     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4800     // characters are high-order truncated as they are moved to C(Y-charn2). No
4801     // character conversion takes place.
4802 
4803     // The user of string replication or overlaying is warned that the decimal
4804     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4805     // units of Y-block8 words and that the overlayed string, C(Y-charn2), is
4806     // not returned to main memory until the unit of Y-block8 words is filled or
4807     // the instruction completes.
4808 
4809     // If T = 1 and the truncation indicator is set ON by execution of the
4810     // instruction, then a truncation (overflow) fault occurs.
4811 
4812     // Attempted execution with the xed instruction causes an illegal procedure
4813     // fault.
4814 
4815     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4816     // illegal procedure fault.
4817 
4818 #ifdef EIS_PTR3
4819     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4820                (TA2 == 2); // (6-4 move)
4821 #else
4822     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4823                (e -> TA2 == 2); // (6-4 move)
4824 #endif
4825     bool isNeg = false;
4826     //bool bOvp = false;  // true when a negative overpunch character has been
4827                         // found @ N1-1
4828 
4829     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4830       DU_CYCLE_FLEN_128;))
4831 
4832 //
4833 // Test for the case of aligned word move; and do things a word at a time,
4834 // instead of a byte at a time...
4835 
4836 #ifdef EIS_PTR3
4837     if (TA1 == CTA9 &&  // src and dst are both char 9
4838         TA2 == CTA9 &&
4839 #else
4840     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4841         e -> TA2 == CTA9 &&
4842 #endif
4843         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4844         e -> N2 == e -> N1 && // the src is the same size as the dest.
4845         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4846         e -> CN2 == 0)
4847       {
4848         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #1\n");
4849         uint limit = e -> N2;
4850         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY += 4)
4851           {
4852             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
4853             word36 w = EISReadIdx (& e -> ADDR1, n);
4854             EISWriteIdx (& e -> ADDR2, n, w, true);
4855           }
4856         cleanupOperandDescriptor (1);
4857         cleanupOperandDescriptor (2);
4858         // truncation fault check does need to be checked for here since
4859         // it is known that N1 == N2
4860         CLR_I_TRUNC;
4861         return;
4862       }
4863 
4864 // Test for the case of aligned word fill; and do things a word at a time,
4865 // instead of a byte at a time...
4866 
4867 #ifdef EIS_PTR3
4868     if (TA1 == CTA9 && // src and dst are both char 9
4869         TA2 == CTA9 &&
4870 #else
4871     if (e -> TA1 == CTA9 && // src and dst are both char 9
4872         e -> TA2 == CTA9 &&
4873 #endif
4874         e -> N1 == 0 && // the source is entirely fill
4875         e -> N2 % 4 == 0 && // a whole number of words in the dest
4876         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4877         e -> CN2 == 0)
4878       {
4879         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #2\n");
4880         word36 w = (word36) fill |
4881                   ((word36) fill << 9) |
4882                   ((word36) fill << 18) |
4883                   ((word36) fill << 27);
4884         uint limit = e -> N2;
4885         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4886           {
4887             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
4888             EISWriteIdx (& e -> ADDR2, n, w, true);
4889           }
4890         cleanupOperandDescriptor (1);
4891         cleanupOperandDescriptor (2);
4892         // truncation fault check does need to be checked for here since
4893         // it is known that N1 <= N2
4894         CLR_I_TRUNC;
4895         return;
4896       }
4897 
4898     for ( ; cpu.du.CHTALLY < min (e -> N1, e -> N2); cpu.du.CHTALLY ++)
4899       {
4900         word9 c = EISget469 (1, e -> N1 - cpu.du.CHTALLY - 1); // get src char
4901         word9 cout = 0;
4902 
4903 #ifdef EIS_PTR3
4904         if (TA1 == TA2)
4905 #else
4906         if (e -> TA1 == e -> TA2)
4907 #endif
4908           EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, c);
4909         else
4910           {
4911             // If data types are dissimilar (TA1 ≠ TA2), each character is
4912             // high-order truncated or zero filled, as appropriate, as it is
4913             // moved. No character conversion takes place.
4914             cout = c;
4915             switch (srcSZ)
4916               {
4917                 case 6:
4918                   switch(dstSZ)
4919                     {
4920                       case 4:
4921                         cout = c & 017;    // truncate upper 2-bits
4922                         break;
4923                       case 9:
4924                         break;              // should already be 0-filled
4925                     }
4926                   break;
4927                 case 9:
4928                   switch(dstSZ)
4929                     {
4930                       case 4:
4931                         cout = c & 017;    // truncate upper 5-bits
4932                         break;
4933                       case 6:
4934                         cout = c & 077;    // truncate upper 3-bits
4935                         break;
4936                     }
4937                   break;
4938               }
4939 
4940             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
4941             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
4942             // negative overpunch sign is found, then the minus sign character
4943             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
4944             // is placed in C(Y-charn2)N2-1.
4945 
4946 // ISOLTS 838 01f, RJ78 p.11-154 - the rightmost digit is examined for overpunch.
4947             if (ovp && (cpu.du.CHTALLY == 0))
4948               {
4949                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
4950                 isGBCDOvp (c, & isNeg);
4951               }
4952             EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, cout);
4953           }
4954       }
4955 
4956     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4957     //    C(FILL) → C(Y-charn2)N2-i
4958     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4959     // characters are high-order truncated as they are moved to C(Y-charn2). No
4960     // character conversion takes place.
4961 
4962     if (e -> N1 < e -> N2)
4963       {
4964         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
4965           {
4966             // if there's an overpunch then the sign will be the last of the fill
4967             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
4968               {
4969                 if (isNeg)
4970                   EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, 015); // 015 is decimal -
4971                 else
4972                   EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, 014); // 014 is decimal +
4973               }
4974             else
4975               {
4976                  EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, fillT);
4977               }
4978           }
4979     }
4980     cleanupOperandDescriptor (1);
4981     cleanupOperandDescriptor (2);
4982 
4983     if (e -> N1 > e -> N2)
4984       {
4985         SET_I_TRUNC;
4986         if (T && ! TST_I_OMASK)
4987           doFault (FAULT_OFL, fst_zero, "mrl truncation fault");
4988       }
4989     else
4990       CLR_I_TRUNC;
4991   }
4992 
4993 // decimalZero
4994 //
4995 //  Try 1:
4996 //
4997 // This makes MVE 1-28 and all of MVNE work
4998 // Fails MVE 29-37 (6->6)
4999 //    #define decimalZero (e->srcTA != CTA4 ? '0' : 0)
5000 //
5001 // Try 2
5002 // This makes MVE 1-10 and 20-37 and all of MVNE work
5003 // Fails MVE 11-19 (6->9)
5004 //    #define decimalZero (e->srcTA == CTA9 ? '0' : 0)
5005 //
5006 // Try 4
5007 //
5008 #define isDecimalZero(c) ((e->srcTA == CTA9) ? \
5009                           ((c) == '0') : \
5010                           (((c) & 017) == 0))
5011 
5012 /*
5013  * Load the entire sending string number (maximum length 63 characters) into
5014  * the decimal unit input buffer as 4-bit digits (high-order truncating 9-bit
5015  * data). Strip the sign and exponent characters (if any), put them aside into
5016  * special holding registers and decrease the input buffer count accordingly.
5017  */
5018 
5019 static void EISloadInputBufferNumeric (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5020 {
5021     EISstruct * e = & cpu.currentEISinstruction;
5022 
5023     word9 *p = e->inBuffer; // p points to position in inBuffer where 4-bit chars are stored
5024     memset(e->inBuffer, 0, sizeof(e->inBuffer));   // initialize to all 0's
5025 
5026     int pos = (int) e->CN[k-1];
5027 
5028     int TN = (int) e->TN[k-1];
5029     int S = (int) e->S[k-1];  // This is where MVNE gets really nasty.
5030     // I spit on the designers of this instruction set (and of COBOL.) >Ptui!<
5031 
5032     int N = (int) e->N[k-1];  // number of chars in src string
5033 
5034     EISaddr *a = &e->addr[k-1];
5035 
5036     e->sign = 1;
5037     e->exponent = 0;
5038 
5039     for(int n = 0 ; n < N ; n += 1)
5040     {
5041         word9 c = EISget49(a, &pos, TN);
5042         sim_debug (DBG_TRACEEXT, & cpu_dev, "src: %d: %o\n", n, c);
5043 
5044         /*
5045          * Here we need to distinguish between 4 type of numbers.
5046          *
5047          * CSFL - Floating-point, leading sign
5048          * CSLS - Scaled fixed-point, leading sign
5049          * CSTS - Scaled fixed-point, trailing sign
5050          * CSNS - Scaled fixed-point, unsigned
5051          */
5052         switch(S)
5053         {
5054             case CSFL:  // this is the real evil one ....
5055                 // Floating-point:
5056                 // [sign=c0] c1×10(n-3) + c2×10(n-4) + ... + c(n-3) [exponent=8
5057                 // bits]
5058                 //
5059                 // where:
5060                 //
5061                 //  ci is the decimal value of the byte in the ith byte
5062                 //  position.
5063                 //
5064                 //  [sign=ci] indicates that ci is interpreted as a sign byte.
5065                 //
5066                 //  [exponent=8 bits] indicates that the exponent value is
5067                 //  taken from the last 8 bits of the string. If the data is in
5068                 //  9-bit bytes, the exponent is bits 1-8 of c(n-1). If the
5069                 //  data is in 4- bit bytes, the exponent is the binary value
5070                 //  of the concatenation of c(n-2) and c(n-1).
5071 
5072                 if (n == 0) // first had better be a sign ....
5073                 {
5074                     c &= 0xf;   // hack off all but lower 4 bits
5075 
5076                     if (c < 012 || c > 017) //-V560
5077                       doFault (FAULT_IPR,
5078                                fst_ill_dig,
5079                                "loadInputBufferNumeric(1): illegal char in "
5080                                "input");
5081 
5082                     if (c == 015)   // '-'
5083                         e->sign = -1;
5084 
5085                     e->srcTally -= 1;   // 1 less source char
5086                 }
5087                 else if (TN == CTN9 && n == N-1)    // the 9-bit exponent (of which only 8-bits are used)
5088                 {
5089                     e->exponent = (signed char)(c & 0377); // want to do a sign extend
5090                     e->srcTally -= 1;   // 1 less source char
5091                 }
5092                 else if (TN == CTN4 && n == N-2)    // the 1st 4-chars of the 8-bit exponent
5093                 {
5094                     e->exponent = (c & 0xf);// << 4;
5095                     e->exponent <<= 4;
5096                     e->srcTally -= 1;   // 1 less source char
5097                 }
5098                 else if (TN == CTN4 && n == N-1)    // the 2nd 4-chars of the 8-bit exponent
5099                 {
5100                     e->exponent |= (c & 0xf);
5101 
5102                     signed char ce = (signed char) (e->exponent & 0xff);
5103                     e->exponent = ce;
5104 
5105                     e->srcTally -= 1;   // 1 less source char
5106                 }
5107                 else
5108                 {
5109                     c &= 0xf;   // hack off all but lower 4 bits
5110                     if (c > 011)
5111                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(2): illegal char in input"); // TODO: generate ill proc fault
5112 
5113                     *p++ = c; // store 4-bit char in buffer
5114                 }
5115                 break;
5116 
5117             case CSLS:
5118                 // Only the byte values [0,11]8 are legal in digit positions and only the byte values [12,17]8 are legal in sign positions. Detection of an illegal byte value causes an illegal procedure fault
5119                 c &= 0xf;   // hack off all but lower 4 bits
5120 
5121                 if (n == 0) // first had better be a sign ....
5122                 {
5123                     if (c < 012 || c > 017) //-V560
5124                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(3): illegal char in input"); // TODO: generate ill proc fault
5125 
5126                     if (c == 015)  // '-'
5127                         e->sign = -1;
5128                     e->srcTally -= 1;   // 1 less source char
5129                 }
5130                 else
5131                 {
5132                     if (c > 011) //-V560
5133                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(4): illegal char in input");
5134                     *p++ = c; // store 4-bit char in buffer
5135                 }
5136                 break;
5137 
5138             case CSTS:
5139                 c &= 0xf;   // hack off all but lower 4 bits
5140 
5141                 if (n == N-1) // last had better be a sign ....
5142                 {
5143                     if (c < 012 || c > 017) //-V560
5144                          doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(5): illegal char in input");
5145                     if (c == 015)   // '-'
5146                         e->sign = -1;
5147                     e->srcTally -= 1;   // 1 less source char
5148                 }
5149                 else
5150                 {
5151                     if (c > 011)
5152                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(6): illegal char in input");
5153                     *p++ = c; // store 4-bit char in buffer
5154                 }
5155                 break;
5156 
5157             case CSNS:
5158                 c &= 0xf; // hack off all but lower 4 bits
5159 
5160                 *p++ = c; // the "easy" one
5161                 break;
5162         }
5163     }
5164     if_sim_debug (DBG_TRACEEXT, & cpu_dev)
5165       {
5166         sim_debug (DBG_TRACEEXT, & cpu_dev, "inBuffer:");
5167         for (word9 *q = e->inBuffer; q < p; q ++)
5168           sim_debug (DBG_TRACEEXT, & cpu_dev, " %02o", * q);
5169         sim_debug (DBG_TRACEEXT, & cpu_dev, "\n");
5170       }
5171 }
5172 
5173 /*
5174  * Load decimal unit input buffer with sending string characters. Data is read
5175  * from main memory in unaligned units (not modulo 8 boundary) of Y-block8
5176  * words. The number of characters loaded is the minimum of the remaining
5177  * sending string count, the remaining receiving string count, and 64.
5178  */
5179 
5180 static void EISloadInputBufferAlphnumeric (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5181   {
5182     EISstruct * e = & cpu.currentEISinstruction;
5183     // p points to position in inBuffer where 4-bit chars are stored
5184     word9 * p = e -> inBuffer;
5185     memset (e -> inBuffer, 0, sizeof (e -> inBuffer));// initialize to all 0's
5186 
5187     // minimum of the remaining sending string count, the remaining receiving
5188     // string count, and 64.
5189     // uint N = min3 (e -> N1, e -> N3, 64);
5190     // The above AL39 rule doesn't work with IGN and possibly other MOPs as
5191     // well. Workaround: Load all source, but max 63 characters (as RJ78
5192     // suggests).
5193     uint N = min (e-> N1, 63);
5194 
5195     for (uint n = 0 ; n < N ; n ++)
5196       {
5197         word9 c = EISget469 (k, n);
5198         * p ++ = c;
5199       }
5200 }
5201 
5202 static void EISwriteOutputBufferToMemory (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5203   {
5204     EISstruct * e = & cpu.currentEISinstruction;
5205 
5206     for (uint n = 0 ; n < (uint) e -> dstTally; n ++)
5207       {
5208         word9 c49 = e -> outBuffer [n];
5209         EISput469 (k, n, c49);
5210       }
5211   }
5212 
5213 static void writeToOutputBuffer (word9 **dstAddr, int szSrc, int szDst, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
5214 {
5215     EISstruct * e = & cpu.currentEISinstruction;
5216     // 4. If an edit insertion table entry or MOP insertion character is to be
5217     // stored, ANDed, or ORed into a receiving string of 4- or 6-bit
5218     // characters, high-order truncate the character accordingly.
5219     // 5. (MVNE) If the receiving string is 9-bit characters, high-order fill
5220     // the (4-bit) digits from the input buffer with bits 0-4 of character 8 of
5221     // the edit insertion table. If the receiving string is 6-bit characters,
5222     // high-order fill the digits with "00"b.
5223 
5224     if (e -> mvne)
5225       {
5226         switch (szSrc)   // XXX according to rule 1 of Numeric Edit,
5227                          // input should be 4bits. this needs cleaning
5228           {
5229             case 4:
5230               switch (szDst)
5231                 {
5232                   case 4:
5233                     ** dstAddr = c49 & 0xf;
5234                     break;
5235                   case 6:
5236                     ** dstAddr = c49 & 077;   // high-order fill the digits with "00"b.
5237                     break;
5238                   case 9:
5239                     ** dstAddr = c49 | (e -> editInsertionTable [7] & 0760);
5240                     break;
5241                 }
5242               break;
5243             case 6:
5244               switch (szDst)
5245                 {
5246                   case 4:
5247                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5248                     break;
5249                   case 6:
5250                     ** dstAddr = c49; //-V1037 // XXX is this safe? shouldn't it be & 077 ???
5251                     break;
5252                   case 9:
5253                     ** dstAddr = c49; //-V1037
5254                     break;
5255                 }
5256               break;
5257             // Note: case szSrc == 9 is also used for writing edit table
5258             // entries and MOP insertion characters which shall NOT be
5259             // transformed by rule 5
5260             case 9:
5261               switch(szDst)
5262                 {
5263                   case 4:
5264                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5265                     break;
5266                   case 6:
5267                     ** dstAddr = c49 & 077;   // write only 6-bits
5268                     break;
5269                   case 9:
5270                     ** dstAddr = c49;
5271                     break;
5272                 }
5273               break;
5274           }
5275       }
5276     else // mve
5277       {
5278         switch(szDst)
5279           {
5280             case 4:
5281               ** dstAddr = c49 & 0xf;    // write only-4-bits
5282               break;
5283             case 6:
5284               ** dstAddr = c49 & 077;   // write only 6-bits
5285               break;
5286             case 9:
5287               ** dstAddr = c49;
5288               break;
5289           }
5290       }
5291     e->dstTally -= 1;
5292     *dstAddr += 1;
5293 }
5294 
5295 /*!
5296  * This is the Micro Operation Executor/Interpreter
5297  */
5298 
5299 static char* defaultEditInsertionTable = " *+-$,.0";
5300 
5301 // Edit Flags
5302 //
5303 // The processor provides the following four edit flags for use by the micro
5304 // operations.
5305 //
5306 // bool mopES = false; // End Suppression flag; initially OFF, set ON by a
5307 // micro operation when zero-suppression ends.
5308 //
5309 // bool mopSN = false;
5310 // Sign flag; initially set OFF if the sending string has an alphanumeric
5311 // descriptor or an unsigned numeric descriptor. If the sending string has a
5312 // signed numeric descriptor, the sign is initially read from the sending
5313 // string from the digit position defined by the sign and the decimal type
5314 // field (S); SN is set OFF if positive, ON if negative. If all digits are
5315 // zero, the data is assumed positive and the SN flag is set OFF, even when the
5316 // sign is negative.
5317 //
5318 //bool mopBZ = false; i
5319 // Blank-when-zero flag; initially set OFF and set ON by either the ENF or SES
5320 // micro operation. If, at the completion of a move (L1 exhausted), both the Z
5321 // and BZ flags are ON, the receiving string is filled with character 1 of the
5322 // edit insertion table.
5323 
5324 /*!
5325  * CHT Micro Operation - Change Table
5326  * EXPLANATION: The edit insertion table is replaced by the string of eight
5327  * 9-bit characters immediately following the CHT micro operation.
5328  * FLAGS: None affected
5329  * NOTE: C(IF) is not interpreted for this operation.
5330  */
5331 
5332 static int mopCHT (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5333 {
5334     EISstruct * e = & cpu.currentEISinstruction;
5335     memset(&e->editInsertionTable, 0, sizeof(e->editInsertionTable)); // XXX do we really need this?
5336     for(int i = 0 ; i < 8 ; i += 1)
5337     {
5338         if (e->mopTally == 0)
5339         {
5340             e->_faults |= FAULT_IPR;
5341             break;
5342         }
5343 #ifdef EIS_PTR2
5344         word9 entry = EISget49(&e->ADDR2, &e->mopPos, CTN9);  // get mop table entries
5345 #else
5346         word9 entry = EISget49(e->mopAddress, &e->mopPos, CTN9);  // get mop table entries
5347 #endif
5348         e->editInsertionTable[i] = entry & 0777;            // keep to 9-bits
5349         e->mopTally -= 1;
5350     }
5351     return 0;
5352 }
5353 
5354 /*!
5355  * ENF Micro Operation - End Floating Suppression
5356  * EXPLANATION:
5357  *  Bit 0 of IF, IF(0), specifies the nature of the floating suppression. Bit 1
5358  *  of IF, IF(1), specifies if blank when zero option is used.
5359  * For IF(0) = 0 (end floating-sign operation),
5360  * − If ES is OFF and SN is OFF, then edit insertion table entry 3 is moved to
5361  * the receiving field and ES is set ON.
5362  * − If ES is OFF and SN is ON, then edit insertion table entry 4 is moved to
5363  * the receiving field and ES is set ON.
5364  * − If ES is ON, no action is taken.
5365  * For IF(0) = 1 (end floating currency symbol operation),
5366  * − If ES is OFF, then edit insertion table entry 5 is moved to the receiving
5367  * field and ES is set ON.
5368  * − If ES is ON, no action is taken.
5369  * For IF(1) = 1 (blank when zero): the BZ flag is set ON. For IF(1) = 0 (no
5370  * blank when zero): no action is taken.
5371  * FLAGS: (Flags not listed are not affected)
5372  *      ES - If OFF, then set ON
5373  *      BZ - If bit 1 of C(IF) = 1, then set ON; otherwise, unchanged
5374  */
5375 
5376 static int mopENF (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5377 {
5378     EISstruct * e = & cpu.currentEISinstruction;
5379     // For IF(0) = 0 (end floating-sign operation),
5380     if (!(e->mopIF & 010))
5381     {
5382         // If ES is OFF and SN is OFF, then edit insertion table entry 3 is moved to the receiving field and ES is set ON.
5383         if (!e->mopES && !e->mopSN)
5384         {
5385             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[2]);
5386             e->mopES = true;
5387         }
5388         // If ES is OFF and SN is ON, then edit insertion table entry 4 is moved to the receiving field and ES is set ON.
5389         if (!e->mopES && e->mopSN)
5390         {
5391             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[3]);
5392             e->mopES = true;
5393         }
5394         // If ES is ON, no action is taken.
5395     } else { // IF(0) = 1 (end floating currency symbol operation),
5396         if (!e->mopES)
5397         {
5398             // If ES is OFF, then edit insertion table entry 5 is moved to the receiving field and ES is set ON.
5399             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5400             e->mopES = true;
5401         }
5402         // If ES is ON, no action is taken.
5403     }
5404 
5405     // For IF(1) = 1 (blank when zero): the BZ flag is set ON. For IF(1) = 0 (no blank when zero): no action is taken.
5406     if (e->mopIF & 04)
5407         e->mopBZ = true;
5408 
5409     return 0;
5410 }
5411 
5412 /*!
5413  * IGN Micro Operation - Ignore Source Characters
5414  * EXPLANATION:
5415  * IF specifies the number of characters to be ignored, where IF = 0 specifies
5416  * 16 characters.
5417  * The next IF characters in the source data field are ignored and the sending
5418  * tally is reduced accordingly.
5419  * FLAGS: None affected
5420  */
5421 
5422 static int mopIGN (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5423 {
5424     EISstruct * e = & cpu.currentEISinstruction;
5425 // AL-39 doesn't specify the == 0 test, but NovaScale does;
5426 // also ISOLTS ps830 test-04a seems to rely on it.
5427     if (e->mopIF == 0)
5428         e->mopIF = 16;
5429 
5430     for(int n = 0 ; n < e->mopIF ; n += 1)
5431     {
5432         if (e->dstTally == 0)
5433             break;
5434         if (e->srcTally == 0)
5435         {
5436             // IGN doesn't allow BZ, raise IPR straight away
5437             e->_faults |= FAULT_IPR;
5438             break;
5439         }
5440 
5441         e->srcTally -= 1;
5442         e->in += 1;
5443     }
5444     return 0;
5445 }
5446 
5447 /*!
5448  * INSA Micro Operation - Insert Asterisk on Suppression
5449  * EXPLANATION:
5450  * This MOP is the same as INSB except that if ES is OFF, then edit insertion
5451  * table entry 2 is moved to the receiving field.
5452  * FLAGS: None affected
5453  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5454  */
5455 
5456 static int mopINSA (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5457 {
5458     EISstruct * e = & cpu.currentEISinstruction;
5459     // If C(IF) = 9-15, an IPR fault occurs.
5460     if (e->mopIF >= 9 && e->mopIF <= 15)
5461     {
5462         e->_faults |= FAULT_IPR;
5463         return 0;
5464     }
5465 
5466 
5467     // If ES is OFF, then edit insertion table entry 1 is moved to the
5468     // receiving field. If IF = 0, then the next 9 bits are also skipped. If IF
5469     // is not 0, the next 9 bits are treated as a MOP.
5470 
5471     if (!e->mopES)
5472       {
5473         writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[1]);
5474 
5475         if (e->mopIF == 0)
5476           {
5477             if (e->mopTally == 0)
5478               {
5479                 e->_faults |= FAULT_IPR;
5480                 return 0;
5481               }
5482 # ifdef EIS_PTR2
5483             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5484 # else
5485             EISget49(e->mopAddress, &e->mopPos, CTN9);
5486 # endif
5487             e->mopTally -= 1;
5488           }
5489       }
5490 
5491     // If ES is ON and IF = 0, then the 9-bit character immediately following
5492     // the INSB micro-instruction is moved to the receiving field
5493     else
5494       {
5495         if (e->mopIF == 0)
5496           {
5497             if (e->mopTally == 0)
5498               {
5499                 e->_faults |= FAULT_IPR;
5500                 return 0;
5501               }
5502 # ifdef EIS_PTR2
5503             word9 c = EISget49(&e->ADDR2, &e->mopPos, CTN9);
5504 # else
5505             word9 c = EISget49(e->mopAddress, &e->mopPos, CTN9);
5506 # endif
5507             writeToOutputBuffer(&e->out, 9, e->dstSZ, c);
5508             e->mopTally -= 1;
5509           }
5510     // If ES is ON and IF<>0, then IF specifies which edit insertion table
5511     // entry (1-8) is to be moved to the receiving field.
5512         else
5513           {
5514             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF-1]);
5515           }
5516       }
5517 
5518 
5519 
5520 
5521 
5522 
5523 
5524 
5525 
5526 
5527 
5528 
5529 
5530 
5531 
5532 
5533 
5534 
5535 
5536 
5537 
5538 
5539 
5540 
5541 
5542 
5543 
5544 
5545 
5546 
5547 
5548 
5549 
5550 
5551 
5552 
5553 
5554 
5555 
5556 
5557 
5558 
5559 
5560 
5561 
5562 
5563 
5564 
5565 
5566     return 0;
5567 }
5568 
5569 /*!
5570  * INSB Micro Operation - Insert Blank on Suppression
5571  * EXPLANATION:
5572  * IF specifies which edit insertion table entry is inserted.
5573  * If IF = 0, the 9 bits immediately following the INSB micro operation are
5574  * treated as a 9-bit character (not a MOP) and are moved or skipped according
5575  * to ES.
5576  * − If ES is OFF, then edit insertion table entry 1 is moved to the receiving
5577  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5578  * next 9 bits are treated as a MOP.
5579  * − If ES is ON and IF = 0, then the 9-bit character immediately following the
5580  * INSB micro-instruction is moved to the receiving field.
5581  * − If ES is ON and IF<>0, then IF specifies which edit insertion table entry
5582  * (1-8) is to be moved to the receiving field.
5583  * FLAGS: None affected
5584  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5585  */
5586 
5587 static int mopINSB (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5588 {
5589     EISstruct * e = & cpu.currentEISinstruction;
5590     // If C(IF) = 9-15, an IPR fault occurs.
5591     if (e->mopIF >= 9 && e->mopIF <= 15)
5592     {
5593         e->_faults |= FAULT_IPR;
5594         return 0;
5595     }
5596 
5597     if (!e->mopES)
5598     {
5599         // If ES is OFF, then edit insertion table entry 1 is moved to the
5600         // receiving field. If IF = 0, then the next 9 bits are also skipped.
5601         // If IF is not 0, the next 9 bits are treated as a MOP.
5602         writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5603 
5604         if (e->mopIF == 0)
5605         {
5606             if (e->mopTally == 0)
5607             {
5608                 e->_faults |= FAULT_IPR;
5609                 return 0;
5610             }
5611 #ifdef EIS_PTR2
5612             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5613 #else
5614             EISget49(e->mopAddress, &e->mopPos, CTN9);
5615 #endif
5616             e->mopTally -= 1;
5617         }
5618 
5619     } else {
5620 
5621         // ES is ON
5622 
5623         // If C(IF) != 0
5624         if (e->mopIF)
5625         {
5626             // If ES is ON and IF<>0, then IF specifies which edit
5627             // insertion table entry (1-8) is to be moved to the receiving
5628             // field.
5629             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5630         } else {
5631             // If ES is ON and IF = 0, then the 9-bit character immediately
5632             // following the INSB micro-instruction is moved to the
5633             // receiving field.
5634             if (e->mopTally == 0)
5635             {
5636                 e->_faults |= FAULT_IPR;
5637                 return 0;
5638             }
5639 #ifdef EIS_PTR2
5640             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(&e->ADDR2, &e->mopPos, CTN9));
5641             //EISget49(&e->ADDR2, &e->mopPos, CTN9);
5642 #else
5643             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(e->mopAddress, &e->mopPos, CTN9));
5644             //EISget49(e->mopAddress, &e->mopPos, CTN9);
5645 #endif
5646             e->mopTally -= 1;
5647 
5648         }
5649     }
5650     return 0;
5651 }
5652 
5653 /*!
5654  * INSM Micro Operation - Insert Table Entry One Multiple
5655  * EXPLANATION:
5656  * IF specifies the number of receiving characters affected, where IF = 0
5657  * specifies 16 characters.
5658  * Edit insertion table entry 1 is moved to the next IF (1-16) receiving field
5659  * characters.
5660  * FLAGS: None affected
5661  */
5662 
5663 static int mopINSM (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5664 {
5665     EISstruct * e = & cpu.currentEISinstruction;
5666     if (e->mopIF == 0)
5667         e->mopIF = 16;
5668     for(int n = 0 ; n < e->mopIF ; n += 1)
5669     {
5670         if (e->dstTally == 0)
5671           break;
5672         writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5673     }
5674     return 0;
5675 }
5676 
5677 /*!
5678  * INSN Micro Operation - Insert on Negative
5679  * EXPLANATION:
5680  * IF specifies which edit insertion table entry is inserted. If IF = 0, the 9
5681  * bits immediately following the INSN micro operation are treated as a 9-bit
5682  * character (not a MOP) and are moved or skipped according to SN.
5683  * − If SN is OFF, then edit insertion table entry 1 is moved to the receiving
5684  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5685  * next 9 bits are treated as a MOP.
5686  * − If SN is ON and IF = 0, then the 9-bit character immediately following the
5687  * INSN micro-instruction is moved to the receiving field.
5688  * − If SN is ON and IF <> 0, then IF specifies which edit insertion table
5689  * entry (1-8) is to be moved to the receiving field.
5690  * FLAGS: None affected
5691  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5692  */
5693 
5694 static int mopINSN (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5695 {
5696     EISstruct * e = & cpu.currentEISinstruction;
5697     // If C(IF) = 9-15, an IPR fault occurs.
5698     if (e->mopIF >= 9 && e->mopIF <= 15)
5699     {
5700         e->_faults |= FAULT_IPR;
5701         return 0;
5702     }
5703 
5704     // If IF = 0, the 9 bits immediately following the INSN micro operation are
5705     // treated as a 9-bit character (not a MOP) and are moved or skipped
5706     // according to SN.
5707 
5708     if (e->mopIF == 0)
5709     {
5710         if (e->mopTally == 0)
5711         {
5712             e->_faults |= FAULT_IPR;
5713             return 0;
5714         }
5715       if (!e->mopSN)
5716         {
5717             //If SN is OFF, then edit insertion table entry 1 is moved to the
5718             //receiving field. If IF = 0, then the next 9 bits are also
5719             //skipped. If IF is not 0, the next 9 bits are treated as a MOP.
5720 #ifdef EIS_PTR2
5721             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5722 #else
5723             EISget49(e->mopAddress, &e->mopPos, CTN9);
5724 #endif
5725             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5726             e->mopTally -= 1;
5727         } else {
5728             // If SN is ON and IF = 0, then the 9-bit character immediately
5729             // following the INSN micro-instruction is moved to the receiving
5730             // field.
5731 #ifdef EIS_PTR2
5732             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(&e->ADDR2, &e->mopPos, CTN9));
5733 #else
5734             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(e->mopAddress, &e->mopPos, CTN9));
5735 #endif
5736 
5737             e->mopTally -= 1;
5738         }
5739     }
5740     else
5741     {
5742         if (e->mopSN)
5743         {
5744             //If SN is ON and IF <> 0, then IF specifies which edit insertion
5745             //table entry (1-8) is to be moved to the receiving field.
5746             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5747         } else {
5748             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5749         }
5750     }
5751     return 0;
5752 }
5753 
5754 /*!
5755  * INSP Micro Operation - Insert on Positive
5756  * EXPLANATION:
5757  * INSP is the same as INSN except that the responses for the SN values are
5758  * reversed.
5759  * FLAGS: None affected
5760  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5761  */
5762 
5763 static int mopINSP (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5764 {
5765     EISstruct * e = & cpu.currentEISinstruction;
5766     // If C(IF) = 9-15, an IPR fault occurs.
5767     if (e->mopIF >= 9 && e->mopIF <= 15)
5768     {
5769         e->_faults |= FAULT_IPR;
5770         return 0;
5771     }
5772 
5773     if (e->mopIF == 0)
5774     {
5775         if (e->mopTally == 0)
5776         {
5777             e->_faults |= FAULT_IPR;
5778             return 0;
5779         }
5780         if (e->mopSN)
5781         {
5782 #ifdef EIS_PTR2
5783             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5784 #else
5785             EISget49(e->mopAddress, &e->mopPos, CTN9);
5786 #endif
5787             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5788             e->mopTally -= 1;
5789         } else {
5790 #ifdef EIS_PTR2
5791             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(&e->ADDR2, &e->mopPos, CTN9));
5792 #else
5793             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(e->mopAddress, &e->mopPos, CTN9));
5794 #endif
5795             e->mopTally -= 1;
5796         }
5797     }
5798     else
5799     {
5800         if (!e->mopSN)
5801         {
5802             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5803         } else {
5804             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5805         }
5806     }
5807 
5808     return 0;
5809 }
5810 
5811 /*!
5812  * LTE Micro Operation - Load Table Entry
5813  * EXPLANATION:
5814  * IF specifies the edit insertion table entry to be replaced.
5815  * The edit insertion table entry specified by IF is replaced by the 9-bit
5816  * character immediately following the LTE microinstruction.
5817  * FLAGS: None affected
5818  * NOTE: If C(IF) = 0 or C(IF) = 9-15, an Illegal Procedure fault occurs.
5819  */
5820 
5821 static int mopLTE (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5822 {
5823     EISstruct * e = & cpu.currentEISinstruction;
5824     if (e->mopIF == 0 || (e->mopIF >= 9 && e->mopIF <= 15))
5825     {
5826         e->_faults |= FAULT_IPR;
5827         return 0;
5828     }
5829     if (e->mopTally == 0)
5830     {
5831         e->_faults |= FAULT_IPR;
5832         return 0;
5833     }
5834 #ifdef EIS_PTR2
5835     word9 next = EISget49(&e->ADDR2, &e->mopPos, CTN9);
5836 #else
5837     word9 next = EISget49(e->mopAddress, &e->mopPos, CTN9);
5838 #endif
5839     e->mopTally -= 1;
5840 
5841     e->editInsertionTable[e->mopIF - 1] = next;
5842     sim_debug (DBG_TRACEEXT, & cpu_dev, "LTE IT[%d]<=%d\n", e -> mopIF - 1, next);
5843     return 0;
5844 }
5845 
5846 /*!
5847  * MFLC Micro Operation - Move with Floating Currency Symbol Insertion
5848  * EXPLANATION:
5849  * IF specifies the number of characters of the sending field upon which the
5850  * operation is performed, where IF = 0 specifies 16 characters.
5851  * Starting with the next available sending field character, the next IF
5852  * characters are individually fetched and the following conditional actions
5853  * occur.
5854  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
5855  * moved to the receiving field in place of the character.
5856  * − If ES is OFF and the character is not zero, then edit insertion table
5857  * entry 5 is moved to the receiving field, the character is also moved to the
5858  * receiving field, and ES is set ON.
5859  * − If ES is ON, the character is moved to the receiving field.
5860  * The number of characters placed in the receiving field is data-dependent. If
5861  * the entire sending field is zero, IF characters are placed in the receiving
5862  * field. However, if the sending field contains a nonzero character, IF+1
5863  * characters (the insertion character plus the characters from the sending
5864  * field) are placed in the receiving field.
5865  * An IPR fault occurs when the sending field is exhausted before the receiving
5866  * field is filled. In order to provide space in the receiving field for an
5867  * inserted currency symbol, the receiving field must have a string length one
5868  * character longer than the sending field. When the sending field is all
5869  * zeros, no currency symbol is inserted by the MFLC micro operation and the
5870  * receiving field is not filled when the sending field is exhausted. The user
5871  * should provide an ENF (ENF,12) micro operation after a MFLC micro operation
5872  * that has as its character count the number of characters in the sending
5873  * field. The ENF micro operation is engaged only when the MFLC micro operation
5874  * fails to fill the receiving field. Then it supplies a currency symbol to
5875  * fill the receiving field and blanks out the entire field.
5876  * FLAGS: (Flags not listed are not affected.)
5877  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
5878  * is unchanged.
5879  * NOTE: Since the number of characters moved to the receiving string is
5880  * data-dependent, a possible IPR fault may be avoided by ensuring that the Z
5881  * and BZ flags are ON.
5882  */
5883 
5884 static int mopMFLC (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5885 {
5886     EISstruct * e = & cpu.currentEISinstruction;
5887     if (e->mopIF == 0)
5888         e->mopIF = 16;
5889 
5890     //  Starting with the next available sending field character, the next IF
5891     //  characters are individually fetched and the following conditional
5892     //  actions occur.
5893     sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC IF %d, srcTally %d, dstTally %d\n", e->mopIF, e->srcTally, e->dstTally);
5894     for(int n = 0 ; n < e->mopIF ; n += 1)
5895     {
5896         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC n %d, srcTally %d, dstTally %d\n", n, e->srcTally, e->dstTally);
5897         if (e->dstTally == 0)
5898             break;
5899         if (e->srcTally == 0)
5900             return -1;
5901         // If ES is OFF and the character is zero, edit insertion table entry 1
5902         // is moved to the receiving field in place of the character.
5903         // If ES is OFF and the character is not zero, then edit insertion
5904         // table entry 5 is moved to the receiving field, the character is also
5905         // moved to the receiving field, and ES is set ON.
5906 
5907         word9 c = *(e->in);
5908         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC c %d (0%o)\n", c, c);
5909         if (!e->mopES) { // e->mopES is OFF
5910 
5911             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES off\n");
5912             if (isDecimalZero (c)) {
5913                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is zero\n");
5914                 // edit insertion table entry 1 is moved to the receiving field
5915                 // in place of the character.
5916                 writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5917                 e->in += 1;
5918                 e->srcTally -= 1;
5919             } else {
5920                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is not zero\n");
5921                 // then edit insertion table entry 5 is moved to the receiving
5922                 // field, the character is also moved to the receiving field,
5923                 // and ES is set ON.
5924                 writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5925 
5926                 writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
5927                 e->mopZ = false; // iszero() tested above.
5928                 e->in += 1;
5929                 e->srcTally -= 1;
5930 
5931                 e->mopES = true;
5932             }
5933         } else {
5934             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES on\n");
5935             // If ES is ON, the character is moved to the receiving field.
5936             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
5937 
5938             if (! isDecimalZero (c))
5939                 e->mopZ = false;
5940             e->in += 1;
5941             e->srcTally -= 1;
5942         }
5943     }
5944 
5945     return 0;
5946 }
5947 
5948 /*!
5949  * MFLS Micro Operation - Move with Floating Sign Insertion
5950  * EXPLANATION:
5951  * IF specifies the number of characters of the sending field upon which the
5952  * operation is performed, where IF = 0 specifies 16 characters.
5953  * Starting with the next available sending field character, the next IF
5954  * characters are individually fetched and the following conditional actions
5955  * occur.
5956  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
5957  * moved to the receiving field in place of the character.
5958  * − If ES is OFF, the character is not zero, and SN is OFF; then edit
5959  * insertion table entry 3 is moved to the receiving field; the character is
5960  * also moved to the receiving field, and ES is set ON.
5961  * − If ES is OFF, the character is nonzero, and SN is ON; edit insertion table
5962  * entry 4 is moved to the receiving field; the character is also moved to the
5963  * receiving field, and ES is set ON.
5964  * − If ES is ON, the character is moved to the receiving field.
5965  * The number of characters placed in the receiving field is data-dependent. If
5966  * the entire sending field is zero, IF characters are placed in the receiving
5967  * field. However, if the sending field contains a nonzero character, IF+1
5968  * characters (the insertion character plus the characters from the sending
5969  * field) are placed in the receiving field.
5970  * An IPR fault occurs when the sending field is exhausted before the receiving
5971  * field is filled. In order to provide space in the receiving field for an
5972  * inserted sign, the receiving field must have a string length one character
5973  * longer than the sending field. When the sending field is all zeros, no sign
5974  * is inserted by the MFLS micro operation and the receiving field is not
5975  * filled when the sending field is exhausted. The user should provide an ENF
5976  * (ENF,4) micro operation after a MFLS micro operation that has as its
5977  * character count the number of characters in the sending field. The ENF micro
5978  * operation is engaged only when the MFLS micro operation fails to fill the
5979  * receiving field; then, it supplies a sign character to fill the receiving
5980  * field and blanks out the entire field.
5981  *
5982  * FLAGS: (Flags not listed are not affected.)
5983  *     ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
5984  *     it is unchanged.
5985  * NOTE: Since the number of characters moved to the receiving string is
5986  * data-dependent, a possible Illegal Procedure fault may be avoided by
5987  * ensuring that the Z and BZ flags are ON.
5988  */
5989 
5990 static int mopMFLS (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5991 {
5992     EISstruct * e = & cpu.currentEISinstruction;
5993     if (e->mopIF == 0)
5994         e->mopIF = 16;
5995 
5996     for(int n = 0 ; n < e->mopIF; n += 1)
5997     {
5998         if (e->dstTally == 0)
5999             break;
6000         if (e->srcTally == 0)
6001             return -1;
6002 
6003         word9 c = *(e->in);
6004         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLS n %d c %o\n", n, c);
6005         if (!e->mopES) { // e->mopES is OFF
6006             if (isDecimalZero (c))
6007             {
6008                 // edit insertion table entry 1 is moved to the receiving field
6009                 // in place of the character.
6010                 sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is off, c is zero; edit insertion table entry 1 is moved to the receiving field in place of the character.\n");
6011                 writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6012                 e->in += 1;
6013                 e->srcTally -= 1;
6014             } else {
6015                 // c is non-zero
6016                 if (!e->mopSN)
6017                 {
6018                     // then edit insertion table entry 3 is moved to the
6019                     // receiving field; the character is also moved to the
6020                     // receiving field, and ES is set ON.
6021                     sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is off, c is non-zero, SN is off; edit insertion table entry 3 is moved to the receiving field; the character is also moved to the receiving field, and ES is set ON.\n");
6022                     writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[2]);
6023 
6024                     e->in += 1;
6025                     e->srcTally -= 1;
6026                     e->mopZ = false; // iszero tested above
6027 
6028 
6029 
6030 
6031 
6032 
6033 
6034 
6035                     writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6036 
6037                     e->mopES = true;
6038                 } else {
6039                     //  SN is ON; edit insertion table entry 4 is moved to the
6040                     //  receiving field; the character is also moved to the
6041                     //  receiving field, and ES is set ON.
6042                     sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is off, c is non-zero, SN is OFF; edit insertion table entry 4 is moved to the receiving field; the character is also moved to the receiving field, and ES is set ON.\n");
6043                     writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[3]);
6044 
6045                     e->in += 1;
6046                     e->srcTally -= 1;
6047                     e->mopZ = false; // iszero tested above
6048 
6049                     writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6050 
6051                     e->mopES = true;
6052                 }
6053             }
6054         } else {
6055             // If ES is ON, the character is moved to the receiving field.
6056             sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is ON, the character is moved to the receiving field.\n");
6057             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6058 
6059             if (! isDecimalZero (c))
6060                 e->mopZ = false;
6061             e->in += 1;
6062             e->srcTally -= 1;
6063         }
6064     }
6065 
6066     // NOTE: Since the number of characters moved to the receiving string is
6067     // data-dependent, a possible Illegal Procedure fault may be avoided by
6068     // ensuring that the Z and BZ flags are ON.
6069 
6070     return 0;
6071 }
6072 
6073 /*!
6074  * MORS Micro Operation - Move and OR Sign
6075  * EXPLANATION:
6076  * IF specifies the number of characters of the sending field upon which the
6077  * operation is performed, where IF = 0 specifies 16 characters.
6078  * Starting with the next available sending field character, the next IF
6079  * characters are individually fetched and the following conditional actions
6080  * occur.
6081  * − If SN is OFF, the next IF characters in the source data field are moved to
6082  * the receiving data field and, during the move, edit insertion table entry 3
6083  * is ORed to each character.
6084  * − If SN is ON, the next IF characters in the source data field are moved to
6085  * the receiving data field and, during the move, edit insertion table entry 4
6086  * is ORed to each character.
6087  * MORS can be used to generate a negative overpunch for a receiving field to
6088  * be used later as a sending field.
6089  * FLAGS: None affected
6090  */
6091 
6092 static int mopMORS (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6093 {
6094     EISstruct * e = & cpu.currentEISinstruction;
6095     if (e->mopIF == 0)
6096         e->mopIF = 16;
6097 
6098     sim_debug (DBG_TRACEEXT, & cpu_dev, "MORS mopIF %d src %d dst %d\n", e->mopIF, e->srcTally, e->dstTally);
6099     for(int n = 0 ; n < e->mopIF ; n += 1)
6100     {
6101 // The micro operation sequence is terminated normally when the receiving
6102 // string length becomes exhausted. The micro operation sequence is terminated
6103 // abnormally (with an illegal procedure fault) if a move from an exhausted
6104 // sending string or the use of an exhausted MOP string is attempted.
6105 
6106         if (e->dstTally == 0)
6107             break;
6108         if (e->srcTally == 0)
6109             return -1;
6110 
6111         // XXX this is probably wrong regarding the ORing, but it's a start ....
6112         word9 c = (*e->in | (!e->mopSN ? e->editInsertionTable[2] : e->editInsertionTable[3]));
6113         if (! isDecimalZero (*e->in))
6114             e->mopZ = false;
6115         e->in += 1;
6116         e->srcTally -= 1;
6117 
6118         writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6119     }
6120 
6121     return 0;
6122 }
6123 
6124 /*!
6125  * MVC Micro Operation - Move Source Characters
6126  * EXPLANATION:
6127  * IF specifies the number of characters to be moved, where IF = 0 specifies 16
6128  * characters.
6129  * The next IF characters in the source data field are moved to the receiving
6130  * data field.
6131  * FLAGS: None affected
6132  */
6133 
6134 static int mopMVC (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6135 {
6136     EISstruct * e = & cpu.currentEISinstruction;
6137     if (e->mopIF == 0)
6138         e->mopIF = 16;
6139 
6140     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC mopIF %d\n", e->mopIF);
6141 
6142     for(int n = 0 ; n < e->mopIF ; n += 1)
6143     {
6144         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC n %d srcTally %d dstTally %d\n", n, e->srcTally, e->dstTally);
6145 // GD's test_float shows that data exhaustion is not a fault.
6146 //#if 0
6147         if (e->dstTally == 0)
6148             break;
6149         if (e->srcTally == 0)
6150             return -1;
6151 
6152         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC write to output buffer %o\n", *e->in);
6153         writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, *e->in);
6154         if (! isDecimalZero (*e->in))
6155             e->mopZ = false;
6156         e->in += 1;
6157 
6158         e->srcTally -= 1;
6159     }
6160 
6161     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC done\n");
6162     return 0;
6163 }
6164 
6165 /*!
6166  * MSES Micro Operation - Move and Set Sign
6167  * EXPLANATION:
6168  * IF specifies the number of characters of the sending field upon which the
6169  * operation is performed, where IF = 0 specifies 16 characters. For MVE,
6170  * starting with the next available sending field character, the next IF
6171  * characters are individually fetched and the following conditional actions
6172  * occur.
6173  * Starting with the first character during the move, a comparative AND is made
6174  * first with edit insertion table entry 3. If the result is nonzero, the first
6175  * character and the rest of the characters are moved without further
6176  * comparative ANDs. If the result is zero, a comparative AND is made between
6177  * the character being moved and edit insertion table entry 4 If that result is
6178  * nonzero, the SN indicator is set ON (indicating negative) and the first
6179  * character and the rest of the characters are moved without further
6180  * comparative ANDs. If the result is zero, the second character is treated
6181  * like the first. This process continues until one of the comparative AND
6182  * results is nonzero or until all characters are moved.
6183  * For MVNE instruction, the sign (SN) flag is already set and IF characters
6184  * are moved to the destination field (MSES is equivalent to the MVC
6185  * instruction).
6186  * FLAGS: (Flags not listed are not affected.)
6187  * SN If edit insertion table entry 4 is found in C(Y-1), then ON; otherwise,
6188  * it is unchanged.
6189  */
6190 
6191 static int mopMSES (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6192 {
6193     EISstruct * e = & cpu.currentEISinstruction;
6194     if (e->mvne == true)
6195         return mopMVC ();   // XXX I think!
6196 
6197     if (e->mopIF == 0)
6198         e->mopIF = 16;
6199 
6200     int overpunch = false;
6201 
6202     for(int n = 0 ; n < e->mopIF ; n += 1)
6203     {
6204         if (e->dstTally == 0)
6205             break;
6206         if (e->srcTally == 0)
6207             return -1;
6208 
6209         //Starting with the first character during the move, a comparative AND
6210         //is made first with edit insertion table entry 3. If the result is
6211         //nonzero, the first character and the rest of the characters are moved
6212         //without further comparative ANDs. If the result is zero, a
6213         //comparative AND is made between the character being moved and edit
6214         //insertion table entry 4 If that result is nonzero, the SN indicator
6215         //is set ON (indicating negative) and the first character and the rest
6216         //of the characters are moved without further comparative ANDs. If the
6217         //result is zero, the second character is treated like the first. This
6218         //process continues until one of the comparative AND results is nonzero
6219         //or until all characters are moved.
6220 
6221         word9 c = *(e->in);
6222 
6223         if (!overpunch) {
6224             if (c & e->editInsertionTable[2])  // XXX only lower 4-bits are considered
6225                 overpunch = true;
6226 
6227             else if (c & e->editInsertionTable[3])  // XXX only lower 4-bits are considered
6228             {
6229                 e->mopSN = true;
6230                 overpunch = true;
6231             }
6232         }
6233 
6234         e->in += 1;
6235         e->srcTally -= 1;   // XXX is this correct? No chars have been consumed, but ......
6236         if (! isDecimalZero (c))
6237             e->mopZ = false;
6238         writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6239     }
6240 
6241     return 0;
6242 }
6243 
6244 /*!
6245  * MVZA Micro Operation - Move with Zero Suppression and Asterisk Replacement
6246  * EXPLANATION:
6247  * MVZA is the same as MVZB except that if ES is OFF and the character is zero,
6248  * then edit insertion table entry 2 is moved to the receiving field.
6249  * FLAGS: (Flags not listed are not affected.)
6250  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
6251  * is unchanged.
6252  */
6253 
6254 static int mopMVZA (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6255 {
6256     EISstruct * e = & cpu.currentEISinstruction;
6257     if (e->mopIF == 0)
6258         e->mopIF = 16;
6259 
6260     for(int n = 0 ; n < e->mopIF ; n += 1)
6261     {
6262         if (e->dstTally == 0)
6263             break;
6264         if (e->srcTally == 0)
6265             return -1;
6266 
6267         word9 c = *e->in;
6268         e->in += 1;
6269         e->srcTally -= 1;
6270 
6271         //if (!e->mopES && c == 0)
6272         // XXX See srcTA comment in MVNE
6273         if (!e->mopES && isDecimalZero (c))
6274         {
6275             //If ES is OFF and the character is zero, then edit insertion table
6276             //entry 2 is moved to the receiving field in place of the
6277             //character.
6278             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[1]);
6279         //} else if (!e->mopES && c != 0)
6280         // XXX See srcTA comment in MVNE
6281         }
6282         else if ((! e->mopES) && (! isDecimalZero (c)))
6283         {
6284             //If ES is OFF and the character is not zero, then the character is
6285             //moved to the receiving field and ES is set ON.
6286             e->mopZ = false;
6287             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6288 
6289             e->mopES = true;
6290         } else if (e->mopES)
6291         {
6292             //If ES is ON, the character is moved to the receiving field.
6293             if (! isDecimalZero (c))
6294                 e->mopZ = false;
6295             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6296         }
6297     }
6298 
6299     return 0;
6300 }
6301 
6302 /*!
6303  * MVZB Micro Operation - Move with Zero Suppression and Blank Replacement
6304  * EXPLANATION:
6305  * IF specifies the number of characters of the sending field upon which the
6306  * operation is performed, where IF = 0 specifies 16 characters.
6307  * Starting with the next available sending field character, the next IF
6308  * characters are individually fetched and the following conditional actions
6309  * occur.
6310  * − If ES is OFF and the character is zero, then edit insertion table entry 1
6311  * is moved to the receiving field in place of the character.
6312  * − If ES is OFF and the character is not zero, then the character is moved to
6313  * the receiving field and ES is set ON.
6314  * − If ES is ON, the character is moved to the receiving field.
6315  * FLAGS: (Flags not listed are not affected.)
6316  *   ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6317  *   it is unchanged.
6318  */
6319 
6320 static int mopMVZB (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6321 {
6322     EISstruct * e = & cpu.currentEISinstruction;
6323     if (e->mopIF == 0)
6324         e->mopIF = 16;
6325 
6326     for(int n = 0 ; n < e->mopIF ; n += 1)
6327     {
6328         if (e->dstTally == 0)
6329             break;
6330         if (e->srcTally == 0)
6331           return -1;
6332 
6333         word9 c = *e->in;
6334         e->srcTally -= 1;
6335         e->in += 1;
6336 
6337         //if (!e->mopES && c == 0)
6338         // XXX See srcTA comment in MVNE
6339         if ((!e->mopES) && isDecimalZero (c))
6340         {
6341             //If ES is OFF and the character is zero, then edit insertion table
6342             //entry 1 is moved to the receiving field in place of the
6343             //character.
6344             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6345         //} else if (!e->mopES && c != 0)
6346         // XXX See srcTA comment in MVNE
6347         }
6348         if ((! e->mopES) && (! isDecimalZero (c)))
6349         {
6350             //If ES is OFF and the character is not zero, then the character is
6351             //moved to the receiving field and ES is set ON.
6352             e->mopZ = false;
6353             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6354 
6355             e->mopES = true;
6356         } else if (e->mopES)
6357         {
6358             //If ES is ON, the character is moved to the receiving field.
6359             if (! isDecimalZero (c))
6360                 e->mopZ = false;
6361             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6362         }
6363     }
6364 
6365     return 0;
6366 }
6367 
6368 /*!
6369  * SES Micro Operation - Set End Suppression
6370  * EXPLANATION:
6371  * Bit 0 of IF (IF(0)) specifies the setting of the ES switch.
6372  * If IF(0) = 0, the ES flag is set OFF. If IF(0) = 1, the ES flag is set ON.
6373  * Bit 1 of IF (IF(1)) specifies the setting of the blank-when-zero option.
6374  * If IF(1) = 0, no action is taken.
6375  * If IF(1) = 1, the BZ flag is set ON.
6376  * FLAGS: (Flags not listed are not affected.)
6377  * ES set by this micro operation
6378  * BZ If bit 1 of C(IF) = 1, then ON; otherwise, it is unchanged.
6379  */
6380 
6381 static int mopSES (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6382 {
6383     EISstruct * e = & cpu.currentEISinstruction;
6384     if (e->mopIF & 010)
6385         e->mopES = true;
6386     else
6387         e->mopES = false;
6388 
6389     if (e->mopIF & 04)
6390         e->mopBZ = true;
6391 
6392     return 0;
6393 }
6394 
6395 // Table 4-9. Micro Operation Code Assignment Map
6396 #ifndef QUIET_UNUSED
6397 static char * mopCodes [040] =
6398   {
6399     //            0       1       2       3       4       5       6       7
6400     /* 00 */      0, "insm",  "enf",  "ses", "mvzb", "mvza", "mfls", "mflc",
6401     /* 10 */ "insb", "insa", "insn", "insp",  "ign",  "mvc", "mses", "mors",
6402     /* 20 */  "lte",  "cht",      0,      0,      0,      0,      0,      0,
6403     /* 30 */      0,      0,      0,      0,      0,      0,      0,      0
6404   };
6405 #endif
6406 
6407 static MOP_struct mopTab[040] = {
6408     {NULL, 0},
6409     {"insm", mopINSM },
6410     {"enf",  mopENF  },
6411     {"ses",  mopSES  },
6412     {"mvzb", mopMVZB },
6413     {"mvza", mopMVZA },
6414     {"mfls", mopMFLS },
6415     {"mflc", mopMFLC },
6416     {"insb", mopINSB },
6417     {"insa", mopINSA },
6418     {"insn", mopINSN },
6419     {"insp", mopINSP },
6420     {"ign",  mopIGN  },
6421     {"mvc",  mopMVC  },
6422     {"mses", mopMSES },
6423     {"mors", mopMORS },
6424     {"lte",  mopLTE  },
6425     {"cht",  mopCHT  },
6426     {NULL, 0},
6427     {NULL, 0},
6428     {NULL, 0},
6429     {NULL, 0},
6430     {NULL, 0},
6431     {NULL, 0},
6432     {NULL, 0},
6433     {NULL, 0},
6434     {NULL, 0},
6435     {NULL, 0},
6436     {NULL, 0},
6437     {NULL, 0},
6438     {NULL, 0},
6439     {NULL, 0}
6440 };
6441 
6442 /*!
6443  * fetch MOP from e->mopAddr/e->mopPos ...
6444  */
6445 
6446 static MOP_struct* EISgetMop (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6447 {
6448     EISstruct * e = & cpu.currentEISinstruction;
6449     //static word18 lastAddress;  // try to keep memory access' down
6450     //static word36 data;
6451 
6452     if (e == NULL) //-V547
6453     //{
6454     //    p->lastAddress = -1;
6455     //    p->data = 0;
6456         return NULL;
6457     //}
6458 
6459 #ifdef EIS_PTR2
6460     EISaddr *p = &e->ADDR2;
6461 #else
6462     EISaddr *p = e->mopAddress;
6463 #endif
6464 
6465     //if (p->lastAddress != p->address)                 // read from memory if different address
6466         p->data = EISRead(p);   // read data word from memory
6467 
6468     if (e->mopPos > 3)   // overflows to next word?
6469     {   // yep....
6470         e->mopPos = 0;   // reset to 1st byte
6471 #ifdef EIS_PTR2
6472         cpu.du.Dk_PTR_W[KMOP] = (cpu.du.Dk_PTR_W[KMOP] + 1) & AMASK;     // bump source to next address
6473         p->data = EISRead(&e->ADDR2);   // read it from memory
6474 #else
6475         PNL (cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK);     // bump source to next address
6476         PNL (p->data = EISRead(e->mopAddress));   // read it from memory
6477 # ifdef EIS_PTR
6478         cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK;     // bump source to next address
6479         p->data = EISRead(e->mopAddress);   // read it from memory
6480 # else
6481         e->mopAddress->address = (e->mopAddress->address + 1) & AMASK;     // bump source to next address
6482         p->data = EISRead(e->mopAddress);   // read it from memory
6483 # endif
6484 #endif
6485     }
6486 
6487     word9 mop9  = (word9) get9 (p -> data, e -> mopPos); // get 9-bit mop
6488     word5 mop   = (mop9 >> 4) & 037;
6489     e->mopIF = mop9 & 0xf;
6490 
6491     MOP_struct *m = &mopTab[mop];
6492     sim_debug (DBG_TRACEEXT, & cpu_dev, "MOP %s(%o) %o\n", m -> mopName, mop, e->mopIF);
6493     e->m = m;
6494     if (e->m == NULL || e->m->f == NULL)
6495     {
6496         sim_debug (DBG_TRACEEXT, & cpu_dev, "getMop(e->m == NULL || e->m->f == NULL): mop:%d IF:%d\n", mop, e->mopIF);
6497         return NULL;
6498     }
6499 
6500     e->mopPos += 1;
6501     e->mopTally -= 1;
6502 
6503     //p->lastAddress = p->address;
6504 
6505     return m;
6506 }
6507 
6508 #ifdef EIS_PTR2
6509 static void mopExecutor (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6510 #else
6511 static void mopExecutor (int kMop)
6512 #endif
6513   {
6514     EISstruct * e = & cpu.currentEISinstruction;
6515     PNL (L68_ (DU_CYCLE_FEXOP;))
6516 #ifdef EIS_PTR2
6517     e->mopTally = (int) e->N[KMOP];        // number of micro-ops
6518     e->mopPos   = (int) e->CN[KMOP];        // starting at char pos CN
6519 #else
6520     e->mopAddress = &e->addr[kMop-1];
6521     e->mopTally = (int) e->N[kMop-1];        // number of micro-ops
6522     e->mopPos   = (int) e->CN[kMop-1];        // starting at char pos CN
6523 #endif
6524 
6525     word9 *p9 = e->editInsertionTable; // re-initialize edit insertion table
6526     char *q = defaultEditInsertionTable;
6527     while((*p9++ = (word9) (*q++)))
6528         ;
6529 
6530     e->in = e->inBuffer;    // reset input buffer pointer
6531     e->out = e->outBuffer;  // reset output buffer pointer
6532 
6533     e->_faults = 0; // No faults (yet!)
6534 
6535     // execute dstTally micro operations
6536     // The micro operation sequence is terminated normally when the receiving
6537     // string length becomes exhausted. The micro operation sequence is
6538     // terminated abnormally (with an illegal procedure fault) if a move from
6539     // an exhausted sending string or the use of an exhausted MOP string is
6540     // attempted.
6541 
6542     while (e->dstTally)
6543     {
6544         sim_debug (DBG_TRACEEXT, & cpu_dev, "mopExecutor srcTally %d dstTally %d mopTally %d\n", e->srcTally, e->dstTally, e->mopTally);
6545         MOP_struct *m = EISgetMop();
6546         if (! m)
6547           {
6548             sim_debug (DBG_TRACEEXT, & cpu_dev, "mopExecutor EISgetMop forced break\n");
6549             e->_faults |= FAULT_IPR;   // XXX ill proc fault
6550             break;
6551           }
6552         int mres = m->f();    // execute mop
6553 
6554         // PVS-Studio claims: Expression 'e->_faults & FAULT_IPR' is always false.
6555         if (e->_faults & FAULT_IPR) //-V547
6556             break; // hard IPR raised by a MOP
6557 
6558         // RJ78 specifies "if at completion of a move (L1 exhausted)", AL39
6559         // doesn't define "completion of a move".
6560         // But ISOLTS-845 asserts a case where L1 is NOT exhausted. Therefore I
6561         // assume "L2 exhausted" or "L1 or L2 exhausted" is the correct
6562         // interpretation. Both these options pass ISOLTS-845.
6563         // "L3 exhausted" is also an option but unlikely since that would fire
6564         // the BZ check even upon normal termination.
6565         // XXX DH03 7-295 suggests that there might be a difference between MVE
6566         // and MVNE. It might well be that DPS88/9000 behaves differently than
6567         // DPS8.
6568 
6569 
6570 
6571 
6572 
6573 
6574 
6575         // immediate (L1 or L2) srcTally test
6576         // perhaps more adherent to documentation
6577         if (e->mopTally == 0 || mres)
6578           {
6579             sim_debug (DBG_TRACEEXT, & cpu_dev,
6580                        "mopExecutor N1 or N2 exhausted\n");
6581 
6582             if (e->mopZ && e->mopBZ)
6583               {
6584                 e->out = e->outBuffer; //-V1048  // reset output buffer pointer
6585                 e->dstTally = (int) e->N3;       // number of chars in dst (max 63)
6586                 while (e->dstTally)
6587                   {
6588                     writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6589                   }
6590               }
6591             else if (mres || e->dstTally) //-V560
6592               { // N1 or N2 exhausted and BZ wasn't enabled
6593                 e->_faults |= FAULT_IPR;
6594               } // otherwise normal termination
6595             break;
6596           }
6597     }
6598 
6599     sim_debug (DBG_TRACEEXT, & cpu_dev, "mop faults %o src %d dst %d mop %d\n", e->_faults, e->srcTally, e->dstTally, e->mopTally);
6600 
6601 //"The micro-operation sequence is terminated normally when the receiving string
6602 // length is exhausted. The micro-operation sequence is terminated abnormally (with
6603 // an IPR fault) if an attempt is made to move from an exhausted sending string or to
6604 // use an exhausted MOP string.
6605 
6606 // ISOLTS 845 is happy with no check at all
6607 
6608 
6609 
6610 
6611 
6612 
6613 
6614 
6615 
6616 
6617 
6618 
6619 
6620 
6621 
6622 
6623 
6624 
6625 
6626 
6627 
6628 
6629 
6630 
6631 
6632 
6633 
6634 
6635 
6636 
6637 
6638 
6639 
6640 
6641 
6642 
6643 
6644 
6645     if (e -> _faults)
6646       doFault (FAULT_IPR, fst_ill_proc, "mopExecutor");
6647 }
6648 
6649 void mve (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6650   {
6651     EISstruct * e = & cpu.currentEISinstruction;
6652 
6653     sim_debug(DBG_TRACEEXT, & cpu_dev, "mve\n");
6654 
6655     fault_ipr_subtype_ mod_fault = 0;
6656 
6657 #ifndef EIS_SETUP
6658     setupOperandDescriptor(1, &mod_fault);
6659     setupOperandDescriptor(2, &mod_fault);
6660     setupOperandDescriptor(3, &mod_fault);
6661 #endif
6662 
6663     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
6664     parseAlphanumericOperandDescriptor(2, 2, false, &mod_fault);
6665     parseAlphanumericOperandDescriptor(3, 3, false, &mod_fault);
6666 
6667     L68_ (
6668       // L68 raises it immediately
6669       if (mod_fault)
6670         {
6671           doFault (FAULT_IPR,
6672                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6673                    "Illegal modifier");
6674         }
6675     )
6676 
6677     // Bits 0, 1, 9, and 10 MBZ
6678     // According to RJ78, bit 9 is T, but is not mentioned in the text.
6679     if (IWB_IRODD & 0600600000000)
6680       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mve: 0, 1, 9, 10 MBZ");
6681 
6682     // Bit 23 of OP1 MBZ
6683     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
6684       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op1 23 MBZ");
6685 
6686 
6687 
6688 
6689 
6690 
6691     // only bit 23 according to RH03. this was fixed in DPS9000
6692     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
6693       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op2 23 MBZ");
6694 
6695     // Bit 23 of OP3 MBZ
6696     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6697       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op3 23 MBZ");
6698 
6699     DPS8M_ (
6700       // DPS8M raises it delayed
6701       if (mod_fault)
6702         {
6703           doFault (FAULT_IPR,
6704                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6705                    "Illegal modifier");
6706         }
6707     )
6708 
6709     // initialize mop flags. Probably best done elsewhere.
6710     e->mopES = false; // End Suppression flag
6711     e->mopSN = false; // Sign flag
6712     e->mopBZ = false; // Blank-when-zero flag
6713     e->mopZ  = true;  // Zero flag
6714 
6715     e->srcTally = (int) e->N1;  // number of chars in src (max 63)
6716     e->dstTally = (int) e->N3;  // number of chars in dst (max 63)
6717 
6718 #ifdef EIS_PTR3
6719     e->srcTA = (int) TA1;    // type of chars in src
6720 #else
6721     e->srcTA = (int) e->TA1;    // type of chars in src
6722 #endif
6723 
6724     switch (e -> srcTA)
6725       {
6726         case CTA4:
6727           e -> srcSZ = 4;
6728           break;
6729         case CTA6:
6730           e -> srcSZ = 6;
6731           break;
6732         case CTA9:
6733           e -> srcSZ = 9;
6734           break;
6735       }
6736 
6737 #ifdef EIS_PTR3
6738     uint dstTA = TA3;    // type of chars in dst
6739 #else
6740     uint dstTA = e -> TA3;    // type of chars in dst
6741 #endif
6742 
6743     switch (dstTA)
6744       {
6745         case CTA4:
6746           e -> dstSZ = 4;
6747           break;
6748         case CTA6:
6749           e -> dstSZ = 6;
6750           break;
6751         case CTA9:
6752           e -> dstSZ = 9;
6753           break;
6754       }
6755 
6756     // 1. load sending string into inputBuffer
6757     EISloadInputBufferAlphnumeric (1);   // according to MF1
6758 
6759     // 2. Execute micro operation string, starting with first (4-bit) digit.
6760     e -> mvne = false;
6761 
6762 #ifdef EIS_PTR2
6763     mopExecutor ();
6764 #else
6765     mopExecutor (2);
6766 #endif
6767 
6768     e -> dstTally = (int) e -> N3;  // restore dstTally for output
6769 
6770     EISwriteOutputBufferToMemory (3);
6771     cleanupOperandDescriptor (1);
6772     cleanupOperandDescriptor (2);
6773     cleanupOperandDescriptor (3);
6774   }
6775 
6776 void mvne (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6777   {
6778     EISstruct * e = & cpu.currentEISinstruction;
6779 
6780     fault_ipr_subtype_ mod_fault = 0;
6781 
6782 #ifndef EIS_SETUP
6783     setupOperandDescriptor (1, &mod_fault);
6784     setupOperandDescriptor (2, &mod_fault);
6785     setupOperandDescriptor (3, &mod_fault);
6786 #endif
6787 
6788     parseNumericOperandDescriptor (1, &mod_fault);
6789     parseAlphanumericOperandDescriptor (2, 2, false, &mod_fault);
6790     parseAlphanumericOperandDescriptor (3, 3, false, &mod_fault);
6791 
6792     L68_ (
6793       // L68 raises it immediately
6794       if (mod_fault)
6795         {
6796           doFault (FAULT_IPR,
6797                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6798                    "Illegal modifier");
6799         }
6800     )
6801 
6802     // Bits 0, 1, 9, and 10 MBZ
6803     if (IWB_IRODD & 0600600000000)
6804       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvne: 0, 1, 9, 10 MBZ");
6805 
6806     // Bit 24-29 of OP1 MBZ
6807     // Multics has been observed to use 600162017511, cf RJ78
6808     //if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
6809       //doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op1 24-29 MBZ");
6810 
6811 
6812 
6813 
6814 
6815 
6816     // only bits 21-23 according to RJ78, maybe even less on DPS8
6817     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000070000)
6818       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op2 21-23 MBZ");
6819 
6820 
6821 
6822 
6823 
6824 
6825     // only bit 23 according to RJ78
6826     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6827       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op3 23 MBZ");
6828 
6829     DPS8M_ (
6830       // DPS8M raises it delayed
6831       if (mod_fault)
6832         {
6833           doFault (FAULT_IPR,
6834                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6835                    "Illegal modifier");
6836         }
6837     )
6838 
6839     uint srcTN = e -> TN1;    // type of chars in src
6840 
6841     int n1 = 0;
6842 
6843     /*
6844      * Here we need to distinguish between 4 type of numbers.
6845      *
6846      * CSFL - Floating-point, leading sign
6847      * CSLS - Scaled fixed-point, leading sign
6848      * CSTS - Scaled fixed-point, trailing sign
6849      * CSNS - Scaled fixed-point, unsigned
6850      */
6851 
6852     // determine precision
6853     switch(e->S1)
6854     {
6855         case CSFL:
6856             n1 = (int) e->N1 - 1; // need to account for the - sign
6857             if (srcTN == CTN4)
6858                 n1 -= 2;    // 2 4-bit digits exponent
6859             else
6860                 n1 -= 1;    // 1 9-bit digit exponent
6861             break;
6862 
6863         case CSLS:
6864         case CSTS:
6865             n1 = (int) e->N1 - 1; // only 1 sign
6866             break;
6867 
6868         case CSNS:
6869             n1 = (int) e->N1;     // no sign
6870             break;  // no sign wysiwyg
6871     }
6872 
6873     if (n1 < 1)
6874         doFault (FAULT_IPR, fst_ill_proc, "mvne adjusted n1<1");
6875 
6876     // Putting this check in pAOD breaks Multics boot
6877     // From DH03 it seems that DPS8 does not check this explicitly, but L2 exhaust occurs which raises IPR anyway
6878     // So we may as well keep it here.
6879     if (e->N[1] == 0)
6880       doFault (FAULT_IPR, fst_ill_proc, "mvne N2 0");
6881 
6882     // this is a flaw in DPS8/70 which was corrected in DPS88 and later
6883     // ISOLTS-841 07h, RH03 p.7-295
6884     if (e->N[2] == 0)
6885       doFault (FAULT_IPR, fst_ill_proc, "mvne N3 0");
6886 
6887 //if ((e -> op [0]  & 0000000007700) ||
6888 //    (e -> op [1]  & 0000000077700) ||
6889 //    (e -> op [2]  & 0000000017700))
6890 //sim_printf ("%012"PRIo64"\n%012"PRIo64"\n%012"PRIo64"\n%012"PRIo64"\n", cpu.cu.IWB, e->op[0], e->op[1], e-> op[2]);
6891 //if (e -> op [0]  & 0000000007700) sim_printf ("op1\n");
6892 //if (e -> op [1]  & 0000000077700) sim_printf ("op2\n");
6893 //if (e -> op [2]  & 0000000017700) sim_printf ("op3\n");
6894 //000140  aa  100 004 024 500   mvne      (pr),(ic),(pr)
6895 //000141  aa  6 00162 01 7511   desc9ls   pr6|114,9,-3
6896 //000142  aa   000236 00 0007   desc9a    158,7               000376 = 403040144040
6897 //000143  aa  6 00134 00 0012   desc9a    pr6|92,10           vcpu
6898 //
6899 // The desc8ls is sign-extending the -3.
6900 
6901     // initialize mop flags. Probably best done elsewhere.
6902     e->mopES = false; // End Suppression flag
6903     e->mopSN = false; // Sign flag
6904     e->mopBZ = false; // Blank-when-zero flag
6905     e->mopZ  = true;  // Zero flag
6906 
6907     e -> srcTally = (int) e -> N1;  // number of chars in src (max 63)
6908     e -> dstTally = (int) e -> N3;  // number of chars in dst (max 63)
6909 
6910 // XXX Temp hack to get MOP to work. Merge TA/TN?
6911 // The MOP operators look at srcTA to make 9bit/not 9-bit decisions about
6912 // the contents of inBuffer; parseNumericOperandDescriptor() always puts
6913 // 4 bit data in inBuffer, so signal the MOPS code of that.
6914     e->srcTA = CTA4;    // type of chars in src
6915 
6916     switch(srcTN)
6917     {
6918         case CTN4:
6919             //e->srcAddr = e->YChar41;
6920             e->srcSZ = 4; //-V1037  // stored as 4-bit decimals
6921             break;
6922         case CTN9:
6923             //e->srcAddr = e->YChar91;
6924             e->srcSZ = 4; //-V1037  // 'cause everything is stored as 4-bit decimals
6925             break;
6926     }
6927 
6928 #ifdef EIS_PTR3
6929     uint dstTA = TA3;     // type of chars in dst
6930 #else
6931     uint dstTA = e->TA3;  // type of chars in dst
6932 #endif
6933     switch(dstTA)
6934     {
6935         case CTA4:
6936             //e->dstAddr = e->YChar43;
6937             e->dstSZ = 4;
6938             break;
6939         case CTA6:
6940             //e->dstAddr = e->YChar63;
6941             e->dstSZ = 6;
6942             break;
6943         case CTA9:
6944             //e->dstAddr = e->YChar93;
6945             e->dstSZ = 9;
6946             break;
6947     }
6948 
6949 #ifdef EIS_PTR3
6950     sim_debug (DBG_TRACEEXT, & cpu_dev,
6951       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
6952       e->N1, e->N2, e->N3, e->TN1, e->CN1, TA3, e->CN3);
6953 #else
6954     sim_debug (DBG_TRACEEXT, & cpu_dev,
6955       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
6956       e->N1, e->N2, e->N3, e->TN1, e->CN1, e->TA3, e->CN3);
6957 #endif
6958 
6959     // 1. load sending string into inputBuffer
6960     EISloadInputBufferNumeric (1);   // according to MF1
6961 
6962     // 2. Test sign and, if required, set the SN flag. (Sign flag; initially
6963     // set OFF if the sending string has an alphanumeric descriptor or an
6964     // unsigned numeric descriptor. If the sending string has a signed numeric
6965     // descriptor, the sign is initially read from the sending string from the
6966     // digit position defined by the sign and the decimal type field (S); SN is
6967     // set OFF if positive, ON if negative. If all digits are zero, the data is
6968     // assumed positive and the SN flag is set OFF, even when the sign is
6969     // negative.)
6970 
6971     int sum = 0;
6972     for(int n = 0 ; n < e -> srcTally ; n ++)
6973         sum += e -> inBuffer [n];
6974     if ((e -> sign == -1) && sum)
6975         e -> mopSN = true;
6976 
6977     // 3. Execute micro operation string, starting with first (4-bit) digit.
6978     e -> mvne = true;
6979 
6980 #ifdef EIS_PTR2
6981     mopExecutor ();
6982 #else
6983     mopExecutor (2);
6984 #endif
6985 
6986     e -> dstTally = (int) e -> N3;  // restore dstTally for output
6987 
6988     EISwriteOutputBufferToMemory (3);
6989     cleanupOperandDescriptor (1);
6990     cleanupOperandDescriptor (2);
6991     cleanupOperandDescriptor (3);
6992   }
6993 
6994 /*
6995  * MVT - Move Alphanumeric with Translation
6996  */
6997 
6998 void mvt (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6999   {
7000     EISstruct * e = & cpu.currentEISinstruction;
7001 
7002     // For i = 1, 2, ..., minimum (N1,N2)
7003     //    m = C(Y-charn1)i-1
7004     //    C(Y-char93)m → C(Y-charn2)i-1
7005     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7006     //    m = C(FILL)
7007     //    C(Y-char93)m → C(Y-charn2)i-1
7008 
7009     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
7010 
7011     fault_ipr_subtype_ mod_fault = 0;
7012 
7013 #ifndef EIS_SETUP
7014     setupOperandDescriptor (1, &mod_fault);
7015     setupOperandDescriptor (2, &mod_fault);
7016     setupOperandDescriptorCache (3);
7017 #endif
7018 
7019     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
7020     parseAlphanumericOperandDescriptor (2, 2, false, &mod_fault);
7021     parseArgOperandDescriptor (3, &mod_fault);
7022 
7023     L68_ (
7024       // L68 raises it immediately
7025       if (mod_fault)
7026         {
7027           doFault (FAULT_IPR,
7028                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7029                    "Illegal modifier");
7030         }
7031     )
7032 
7033 // ISOLTS 808 test-03b sets bit 0, 1
7034 // ISOLTS 808 test-03b sets bit 0, 1, 9
7035 
7036     // Bits 10 MBZ
7037     if (IWB_IRODD & 0000200000000)
7038       {
7039         //sim_printf ("mvt %012"PRIo64"\n", IWB_IRODD);
7040         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvt 10 MBZ");
7041       }
7042 
7043 
7044 
7045 
7046 
7047 
7048 
7049 
7050 
7051     // Bit 23 of OP1 MBZ
7052     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
7053       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op1 23 MBZ");
7054 
7055 // This breaks eis_tester mvt 110
7056 
7057 
7058 
7059 
7060 
7061 
7062     // Bits 18-28 of OP3 MBZ
7063     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777600)
7064       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op3 18-28 MBZ");
7065 
7066     DPS8M_ (
7067       // DPS8M raises it delayed
7068       if (mod_fault)
7069         {
7070           doFault (FAULT_IPR,
7071                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7072                    "Illegal modifier");
7073         }
7074     )
7075 
7076 #ifdef EIS_PTR3
7077     e->srcTA = (int) TA1;
7078     uint dstTA = TA2;
7079 
7080     switch (TA1)
7081 #else
7082     e->srcTA = (int) e->TA1;
7083     uint dstTA = e->TA2;
7084 
7085     switch (e -> TA1)
7086 #endif
7087       {
7088         case CTA4:
7089           e -> srcSZ = 4;
7090           break;
7091         case CTA6:
7092           e -> srcSZ = 6;
7093           break;
7094         case CTA9:
7095           e -> srcSZ = 9;
7096          break;
7097       }
7098 
7099 #ifdef EIS_PTR3
7100     switch (TA2)
7101 #else
7102     switch (e -> TA2)
7103 #endif
7104       {
7105         case CTA4:
7106           e -> dstSZ = 4;
7107           break;
7108         case CTA6:
7109           e -> dstSZ = 6;
7110           break;
7111         case CTA9:
7112           e -> dstSZ = 9;
7113           break;
7114       }
7115 
7116     //  Prepage Check in a Multiword Instruction
7117     //  The MVT, TCT, TCTR, and CMPCT instruction have a prepage check. The
7118     //  size of the translate table is determined by the TA1 data type as shown
7119     //  in the table below. Before the instruction is executed, a check is made
7120     //  for allocation in memory for the page for the translate table. If the
7121     //  page is not in memory, a Missing Page fault occurs before execution of
7122     //  the instruction. (Bull RJ78 p.7-75)
7123 
7124     // TA1              TRANSLATE TABLE SIZE
7125     // 4-BIT CHARACTER      4 WORDS
7126     // 6-BIT CHARACTER     16 WORDS
7127     // 9-BIT CHARACTER    128 WORDS
7128 
7129     uint xlatSize = 0;   // size of xlation table in words .....
7130 #ifdef EIS_PTR3
7131     switch(TA1)
7132 #else
7133     switch(e->TA1)
7134 #endif
7135     {
7136         case CTA4:
7137             xlatSize = 4;
7138             break;
7139         case CTA6:
7140             xlatSize = 16;
7141             break;
7142         case CTA9:
7143             xlatSize = 128;
7144             break;
7145     }
7146 
7147 
7148 
7149 
7150 
7151 
7152 
7153 
7154 
7155     // ISOLTS 878 01c - op1 and xlate table are prepaged, in that order
7156     // prepage op1
7157     int lastpageidx = ((int)e->N1 + (int)e->CN1 -1) / e->srcSZ;
7158     if (lastpageidx>0)
7159         EISReadIdx(&e->ADDR1, (uint)lastpageidx);
7160     // prepage xlate table
7161     EISReadIdx(&e->ADDR3, 0);
7162     EISReadIdx(&e->ADDR3, xlatSize-1);
7163 
7164     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7165 
7166     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
7167     word9 fillT = fill;  // possibly truncated fill pattern
7168     // play with fill if we need to use it
7169     switch(e->srcSZ)
7170     {
7171         case 4:
7172             fillT = fill & 017;    // truncate upper 5-bits
7173             break;
7174         case 6:
7175             fillT = fill & 077;    // truncate upper 3-bits
7176             break;
7177     }
7178 
7179     sim_debug (DBG_TRACEEXT, & cpu_dev,
7180       "%s srcCN:%d dstCN:%d srcSZ:%d dstSZ:%d T:%d fill:%03o/%03o N1:%d N2:%d\n",
7181       __func__, e -> CN1, e -> CN2, e -> srcSZ, e -> dstSZ, T,
7182       fill, fillT, e -> N1, e -> N2);
7183 
7184     PNL (L68_ (if (max (e->N1, e->N2) < 128)
7185       DU_CYCLE_FLEN_128;))
7186 
7187     for ( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY ++)
7188     {
7189         word9 c = EISget469(1, cpu.du.CHTALLY); // get src char
7190         int cidx = 0;
7191 
7192 #ifdef EIS_PTR3
7193         if (TA1 == TA2)
7194 #else
7195         if (e->TA1 == e->TA2)
7196 #endif
7197             EISput469(2, cpu.du.CHTALLY, xlate (&e->ADDR3, dstTA, c));
7198         else
7199         {
7200             // If data types are dissimilar (TA1 ≠ TA2), each character is high-order truncated or zero filled, as appropriate, as it is moved. No character conversion takes place.
7201             cidx = c;
7202 
7203             word9 cout = xlate(&e->ADDR3, dstTA, (uint) cidx);
7204 
7205 //            switch(e->dstSZ)
7206 //            {
7207 //                case 4:
7208 //                    cout &= 017;    // truncate upper 5-bits
7209 //                    break;
7210 //                case 6:
7211 //                    cout &= 077;    // truncate upper 3-bits
7212 //                    break;
7213 //            }
7214 
7215             switch (e->srcSZ)
7216             {
7217                 case 6:
7218                     switch(e->dstSZ)
7219                     {
7220                         case 4:
7221                             cout &= 017;    // truncate upper 2-bits
7222                             break;
7223                         case 9:
7224                             break;              // should already be 0-filled
7225                     }
7226                     break;
7227                 case 9:
7228                     switch(e->dstSZ)
7229                     {
7230                         case 4:
7231                             cout &= 017;    // truncate upper 5-bits
7232                             break;
7233                         case 6:
7234                             cout &= 077;    // truncate upper 3-bits
7235                             break;
7236                     }
7237                     break;
7238             }
7239 
7240             EISput469 (2, cpu.du.CHTALLY, cout);
7241         }
7242     }
7243 
7244     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7245     //    m = C(FILL)
7246     //    C(Y-char93)m → C(Y-charn2)N2-i
7247 
7248     if (e->N1 < e->N2)
7249     {
7250         word9 cfill = xlate(&e->ADDR3, dstTA, fillT);
7251         switch (e->srcSZ)
7252         {
7253             case 6:
7254                 switch(e->dstSZ)
7255                 {
7256                     case 4:
7257                         cfill &= 017;    // truncate upper 2-bits
7258                         break;
7259                     case 9:
7260                         break;              // should already be 0-filled
7261                 }
7262                 break;
7263             case 9:
7264                 switch(e->dstSZ)
7265                 {
7266                     case 4:
7267                         cfill &= 017;    // truncate upper 5-bits
7268                         break;
7269                     case 6:
7270                         cfill &= 077;    // truncate upper 3-bits
7271                         break;
7272                 }
7273                 break;
7274         }
7275 
7276         for( ; cpu.du.CHTALLY < e->N2 ; cpu.du.CHTALLY ++)
7277             EISput469 (2, cpu.du.CHTALLY, cfill);
7278     }
7279 
7280     cleanupOperandDescriptor (1);
7281     cleanupOperandDescriptor (2);
7282     cleanupOperandDescriptor (3);
7283 
7284     if (e->N1 > e->N2)
7285       {
7286         SET_I_TRUNC;
7287         if (T && ! TST_I_OMASK)
7288           doFault(FAULT_OFL, fst_zero, "mvt truncation fault");
7289       }
7290     else
7291       CLR_I_TRUNC;
7292   }
7293 
7294 /*
7295  * cmpn - Compare Numeric
7296  */
7297 
7298 void cmpn (void)
     /* [previous][next][first][last][top][bottom][index][help] */
7299 {
7300     EISstruct * e = & cpu.currentEISinstruction;
7301 
7302     // C(Y-charn1) :: C(Y-charn2) as numeric values
7303 
7304     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7305     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7306     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7307 
7308     fault_ipr_subtype_ mod_fault = 0;
7309 
7310 #ifndef EIS_SETUP
7311     setupOperandDescriptor(1, &mod_fault);
7312     setupOperandDescriptor(2, &mod_fault);
7313 #endif
7314 
7315     parseNumericOperandDescriptor(1, &mod_fault);
7316     parseNumericOperandDescriptor(2, &mod_fault);
7317 
7318     L68_ (
7319       // L68 raises it immediately
7320       if (mod_fault)
7321         {
7322           doFault (FAULT_IPR,
7323                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7324                    "Illegal modifier");
7325         }
7326     )
7327 
7328     // Bits 0-10 MBZ
7329     if (IWB_IRODD & 0777600000000)
7330       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpn 0-10 MBZ");
7331 
7332     DPS8M_ (
7333       // DPS8M raises it delayed
7334       if (mod_fault)
7335         {
7336           doFault (FAULT_IPR,
7337                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7338                    "Illegal modifier");
7339         }
7340     )
7341 
7342     uint srcTN = e->TN1;    // type of chars in src
7343 
7344     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
7345 
7346     /*
7347      * Here we need to distinguish between 4 type of numbers.
7348      *
7349      * CSFL - Floating-point, leading sign
7350      * CSLS - Scaled fixed-point, leading sign
7351      * CSTS - Scaled fixed-point, trailing sign
7352      * CSNS - Scaled fixed-point, unsigned
7353      */
7354 
7355     // determine precision
7356     switch(e->S1)
7357     {
7358         case CSFL:
7359             n1 = (int) e->N1 - 1; // need to account for the - sign
7360             if (srcTN == CTN4)
7361                 n1 -= 2;    // 2 4-bit digits exponent
7362             else
7363                 n1 -= 1;    // 1 9-bit digit exponent
7364             sc1 = 0;        // no scaling factor
7365             break;
7366 
7367         case CSLS:
7368         case CSTS:
7369             n1 = (int) e->N1 - 1; // only 1 sign
7370             sc1 = -e->SF1;
7371             break;
7372 
7373         case CSNS:
7374             n1 = (int) e->N1;     // no sign
7375             sc1 = -e->SF1;
7376             break;  // no sign wysiwyg
7377     }
7378 
7379     if (n1 < 1)
7380         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n1<1");
7381 
7382     switch(e->S2)
7383     {
7384         case CSFL:
7385             n2 = (int) e->N2 - 1; // need to account for the sign
7386             if (e->TN2 == CTN4)
7387                 n2 -= 2;    // 2 4-bit digit exponent
7388             else
7389                 n2 -= 1;    // 1 9-bit digit exponent
7390             sc2 = 0;        // no scaling factor
7391             break;
7392 
7393         case CSLS:
7394         case CSTS:
7395             n2 = (int) e->N2 - 1; // 1 sign
7396             sc2 = -e->SF2;
7397             break;
7398 
7399         case CSNS:
7400             n2 = (int) e->N2;     // no sign
7401             sc2 = -e->SF2;
7402             break;  // no sign wysiwyg
7403     }
7404 
7405     if (n2 < 1)
7406         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n2<1");
7407 
7408     decContext set;
7409     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
7410     decContextDefaultDPS8(&set);
7411 
7412     set.traps=0;
7413 
7414     decNumber _1, _2, _3;
7415 
7416     EISloadInputBufferNumeric (1);   // according to MF1
7417 
7418     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
7419     if (e->sign == -1)
7420         op1->bits |= DECNEG;
7421     if (e->S1 == CSFL)
7422         op1->exponent = e->exponent;
7423 
7424     EISloadInputBufferNumeric (2);   // according to MF2
7425 
7426     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
7427     if (e->sign == -1)
7428         op2->bits |= DECNEG;
7429     if (e->S2 == CSFL)
7430         op2->exponent = e->exponent;
7431 
7432     // signed-compare
7433     decNumber *cmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7434     int cSigned = decNumberToInt32(cmp, &set);
7435 
7436     // take absolute value of operands
7437     op1 = decNumberAbs(op1, op1, &set);
7438     op2 = decNumberAbs(op2, op2, &set);
7439 
7440     // magnitude-compare
7441     decNumber *mcmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7442     int cMag = decNumberToInt32(mcmp, &set);
7443 
7444     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7445     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7446     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7447 
7448     SC_I_ZERO (cSigned == 0);
7449     SC_I_NEG (cSigned == 1);
7450     SC_I_CARRY (cMag != 1);
7451 
7452     cleanupOperandDescriptor (1);
7453     cleanupOperandDescriptor (2);
7454 
7455 }
7456 
7457 /*
7458  * mvn - move numeric (initial version was deleted by house gnomes)
7459  */
7460 
7461 /*
7462  * write 4-bit chars to memory @ pos ...
7463  */
7464 
7465 static void EISwrite4(EISaddr *p, int *pos, word4 char4)
     /* [previous][next][first][last][top][bottom][index][help] */
7466 {
7467     word36 w;
7468     if (*pos > 7)    // out-of-range?
7469     {
7470         *pos = 0;    // reset to 1st byte
7471 #ifdef EIS_PTR
7472         long eisaddr_idx = EISADDR_IDX (p);
7473 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7474         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7475 #else
7476         p->address = (p->address + 1) & AMASK;        // goto next dstAddr in memory
7477 #endif
7478     }
7479 
7480     w = EISRead(p);      // read dst memory into w
7481 
7482 // AL39, Figure 2-3
7483     switch (*pos)
7484     {
7485         case 0:
7486             //w = bitfieldInsert36(w, char4, 31, 5);
7487             w = setbits36_4 (w, 1, char4);
7488             break;
7489         case 1:
7490             //w = bitfieldInsert36(w, char4, 27, 4);
7491             w = setbits36_4 (w, 5, char4);
7492             break;
7493         case 2:
7494             //w = bitfieldInsert36(w, char4, 22, 5);
7495             w = setbits36_4 (w, 10, char4);
7496             break;
7497         case 3:
7498             //w = bitfieldInsert36(w, char4, 18, 4);
7499             w = setbits36_4 (w, 14, char4);
7500             break;
7501         case 4:
7502             //w = bitfieldInsert36(w, char4, 13, 5);
7503             w = setbits36_4 (w, 19, char4);
7504             break;
7505         case 5:
7506             //w = bitfieldInsert36(w, char4, 9, 4);
7507             w = setbits36_4 (w, 23, char4);
7508             break;
7509         case 6:
7510             //w = bitfieldInsert36(w, char4, 4, 5);
7511             w = setbits36_4 (w, 28, char4);
7512             break;
7513         case 7:
7514             //w = bitfieldInsert36(w, char4, 0, 4);
7515             w = setbits36_4 (w, 32, char4);
7516             break;
7517     }
7518 
7519     EISWriteIdx(p, 0, w, true); // XXX this is the inefficient part!
7520 
7521     *pos += 1;       // to next char.
7522 }
7523 
7524 /*
7525  * write 9-bit bytes to memory @ pos ...
7526  */
7527 
7528 static void EISwrite9(EISaddr *p, int *pos, word9 char9)
     /* [previous][next][first][last][top][bottom][index][help] */
7529 {
7530     word36 w;
7531     if (*pos > 3)    // out-of-range?
7532     {
7533         *pos = 0;    // reset to 1st byte
7534 #ifdef EIS_PTR
7535         long eisaddr_idx = EISADDR_IDX (p);
7536 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7537         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7538 #else
7539         p->address = (p->address + 1) & AMASK;       // goto next dstAddr in memory
7540 #endif
7541     }
7542 
7543     w = EISRead(p);      // read dst memory into w
7544 
7545 // AL39, Figure 2-5
7546     switch (*pos)
7547     {
7548         case 0:
7549             //w = bitfieldInsert36(w, char9, 27, 9);
7550             w = setbits36_9 (w, 0, char9);
7551             break;
7552         case 1:
7553             //w = bitfieldInsert36(w, char9, 18, 9);
7554             w = setbits36_9 (w, 9, char9);
7555             break;
7556         case 2:
7557             //w = bitfieldInsert36(w, char9, 9, 9);
7558             w = setbits36_9 (w, 18, char9);
7559             break;
7560         case 3:
7561             //w = bitfieldInsert36(w, char9, 0, 9);
7562             w = setbits36_9 (w, 27, char9);
7563             break;
7564     }
7565 
7566     EISWriteIdx (p, 0, w, true); // XXX this is the inefficient part!
7567 
7568     *pos += 1;       // to next byte.
7569 }
7570 
7571 /*
7572  * write a 4-, or 9-bit numeric char to dstAddr ....
7573  */
7574 
7575 static void EISwrite49(EISaddr *p, int *pos, int tn, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
7576 {
7577     switch(tn)
7578     {
7579         case CTN4:
7580             EISwrite4(p, pos, (word4) c49);
7581             return;
7582         case CTN9:
7583             EISwrite9(p, pos, c49);
7584             return;
7585     }
7586 }
7587 
7588 void mvn (void)
     /* [previous][next][first][last][top][bottom][index][help] */
7589 {
7590     /*
7591      * EXPLANATION:
7592      * Starting at location YC1, the decimal number of data type TN1 and sign
7593      * and decimal type S1 is moved, properly scaled, to the decimal number of
7594      * data type TN2 and sign and decimal type S2 that starts at location YC2.
7595      * If S2 indicates a fixed-point format, the results are stored as L2
7596      * digits using scale factor SF2, and thereby may cause
7597      * most-significant-digit overflow and/or least- significant-digit
7598      * truncation.
7599      * If P = 1, positive signed 4-bit results are stored using octal 13 as the
7600      * plus sign. Rounding is legal for both fixed-point and floating-point
7601      * formats. If P = 0, positive signed 4-bit results are stored using octal
7602      * 14 as the plus sign.
7603      * Provided that string 1 and string 2 are not overlapped, the contents of
7604      * the decimal number that starts in location YC1 remain unchanged.
7605      */
7606 
7607     EISstruct * e = & cpu.currentEISinstruction;
7608 
7609     fault_ipr_subtype_ mod_fault = 0;
7610 
7611 #ifndef EIS_SETUP
7612     setupOperandDescriptor(1, &mod_fault);
7613     setupOperandDescriptor(2, &mod_fault);
7614 #endif
7615 
7616     parseNumericOperandDescriptor(1, &mod_fault);
7617     parseNumericOperandDescriptor(2, &mod_fault);
7618 
7619     L68_ (
7620       // L68 raises it immediately
7621       if (mod_fault)
7622         {
7623           doFault (FAULT_IPR,
7624                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7625                    "Illegal modifier");
7626         }
7627     )
7628 
7629     // Bits 2-8 MBZ
7630     if (IWB_IRODD & 0377000000000)
7631      doFault (FAULT_IPR,
7632               (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault},
7633               "mvn 2-8 MBZ");
7634 
7635     DPS8M_ (
7636       // DPS8M raises it delayed
7637       if (mod_fault)
7638         {
7639           doFault (FAULT_IPR,
7640                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7641                    "Illegal modifier");
7642         }
7643     )
7644 
7645     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character
7646                                               //  control
7647     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7648     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
7649     PNL (L68_ (if (R)
7650       DU_CYCLE_FRND;))
7651 
7652     uint srcTN = e->TN1;    // type of chars in src
7653 
7654     uint dstTN = e->TN2;    // type of chars in dst
7655     uint dstCN = e->CN2;    // starting at char pos CN
7656 
7657     sim_debug (DBG_CAC, & cpu_dev,
7658                "mvn(1): TN1 %d CN1 %d N1 %d TN2 %d CN2 %d N2 %d\n",
7659                e->TN1, e->CN1, e->N1, e->TN2, e->CN2, e->N2);
7660     sim_debug (DBG_CAC, & cpu_dev,
7661                "mvn(2): SF1 %d              SF2 %d\n",
7662                e->SF1, e->SF2);
7663     sim_debug (DBG_CAC, & cpu_dev,
7664                "mvn(3): OP1 %012"PRIo64" OP2 %012"PRIo64"\n",
7665                e->OP1, e->OP2);
7666 
7667     int n1 = 0, n2 = 0, sc1 = 0;
7668 
7669     /*
7670      * Here we need to distinguish between 4 type of numbers.
7671      *
7672      * CSFL - Floating-point, leading sign
7673      * CSLS - Scaled fixed-point, leading sign
7674      * CSTS - Scaled fixed-point, trailing sign
7675      * CSNS - Scaled fixed-point, unsigned
7676      */
7677 
7678     // determine precision
7679     switch(e->S1)
7680     {
7681         case CSFL:
7682             n1 = (int) e->N1 - 1; // need to account for the - sign
7683             if (srcTN == CTN4)
7684                 n1 -= 2;    // 2 4-bit digits exponent
7685             else
7686                 n1 -= 1;    // 1 9-bit digit exponent
7687             sc1 = 0;        // no scaling factor
7688             break;
7689 
7690         case CSLS:
7691         case CSTS:
7692             n1 = (int) e->N1 - 1; // only 1 sign
7693             sc1 = -e->SF1;
7694             break;
7695 
7696         case CSNS:
7697             n1 = (int) e->N1;     // no sign
7698             sc1 = -e->SF1;
7699             break;  // no sign wysiwyg
7700     }
7701 
7702     sim_debug (DBG_CAC, & cpu_dev, "n1 %d sc1 %d\n", n1, sc1);
7703 
7704     // RJ78: An Illegal Procedure fault occurs if:
7705     // The values for the number of characters (N1 or N2) of the data
7706     // descriptors are not large enough to hold the number of characters
7707     // required for the specified sign and/or exponent, plus at least one
7708     // digit.
7709 
7710     if (n1 < 1)
7711         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n1<1");
7712 
7713     switch(e->S2)
7714     {
7715         case CSFL:
7716             n2 = (int) e->N2 - 1; // need to account for the sign
7717             if (dstTN == CTN4)
7718                 n2 -= 2;    // 2 4-bit digit exponent
7719             else
7720                 n2 -= 1;    // 1 9-bit digit exponent
7721             break;
7722 
7723         case CSLS:
7724         case CSTS:
7725             n2 = (int) e->N2 - 1; // 1 sign
7726             break;
7727 
7728         case CSNS:
7729             n2 = (int) e->N2;     // no sign
7730             break;          // no sign wysiwyg
7731     }
7732 
7733     sim_debug (DBG_CAC, & cpu_dev, "n2 %d\n", n2);
7734 
7735     if (n2 < 1)
7736         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n2<1");
7737 
7738     decContext set;
7739     decContextDefaultDPS8(&set);
7740     set.traps=0;
7741 
7742     decNumber _1;
7743 
7744     EISloadInputBufferNumeric (1);   // according to MF1
7745 
7746     decNumber *op1 = decBCD9ToNumber (e->inBuffer, n1, sc1, &_1);
7747 
7748     if (e->sign == -1)
7749         op1->bits |= DECNEG;
7750     if (e->S1 == CSFL)
7751         op1->exponent = e->exponent;
7752     if (decNumberIsZero (op1))
7753         op1->exponent = 127;
7754 
7755     if_sim_debug (DBG_CAC, & cpu_dev)
7756     {
7757         PRINTDEC ("mvn input (op1)", op1);
7758     }
7759 
7760     bool Ovr = false, EOvr = false, Trunc = false;
7761 
7762     uint8_t out [256];
7763     char * res = formatDecimal (out, & set, op1, n2, (int) e->S2, e->SF2, R,
7764                                 & Ovr, & Trunc);
7765 
7766     sim_debug (DBG_CAC, & cpu_dev, "mvn res: '%s'\n", res);
7767 
7768     // now write to memory in proper format.....
7769 
7770     //word18 dstAddr = e->dstAddr;
7771     int pos = (int) dstCN;
7772 
7773     // 1st, take care of any leading sign .......
7774     switch(e->S2)
7775     {
7776         case CSFL:  // floating-point, leading sign.
7777         case CSLS:  // fixed-point, leading sign
7778             switch(dstTN)
7779             {
7780                 case CTN4:
7781  // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7782  // sign character is placed appropriately if the result of the operation is
7783  // positive.
7784                     if (e->P)
7785                         // special +
7786                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7787                                    (decNumberIsNegative (op1) &&
7788                                     ! decNumberIsZero(op1)) ? 015 : 013);
7789                     else
7790                         // default +
7791                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7792                                     (decNumberIsNegative (op1) &&
7793                                      ! decNumberIsZero (op1)) ? 015 : 014);
7794                     break;
7795                 case CTN9:
7796                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7797                                 (decNumberIsNegative (op1) &&
7798                                  ! decNumberIsZero (op1)) ? '-' : '+');
7799                     break;
7800             }
7801             break;
7802 
7803         case CSTS:  // nuttin' to do here .....
7804         case CSNS:
7805             break;  // no sign wysiwyg
7806     }
7807 
7808     // 2nd, write the digits .....
7809     for (int i = 0 ; i < n2 ; i ++)
7810         switch (dstTN)
7811         {
7812             case CTN4:
7813                 EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7814                             (word9) (res[i] - '0'));
7815                 break;
7816             case CTN9:
7817                 EISwrite49 (& e->ADDR2, & pos, (int) dstTN, (word9) res[i]);
7818                 break;
7819         }
7820 
7821     // 3rd, take care of any trailing sign or exponent ...
7822     switch(e->S2)
7823     {
7824         case CSTS:  // write trailing sign ....
7825             switch(dstTN)
7826             {
7827                 case CTN4:
7828 // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7829 // sign character is placed appropriately if the result of the operation is
7830 // positive.
7831                     if (e->P)
7832                         // special +
7833                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7834                                     (decNumberIsNegative (op1) &&
7835                                      ! decNumberIsZero(op1)) ? 015 :  013);
7836                     else
7837                         // default +
7838                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7839                                     (decNumberIsNegative (op1) &&
7840                                      ! decNumberIsZero (op1)) ? 015 :  014);
7841                     break;
7842 
7843                 case CTN9:
7844                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7845                                 (decNumberIsNegative (op1) &&
7846                                  ! decNumberIsZero(op1)) ? '-' : '+');
7847                     break;
7848             }
7849             break;
7850 
7851         case CSFL:  // floating-point, leading sign.
7852             // write the exponent
7853             switch(dstTN)
7854             {
7855                 case CTN4:
7856                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7857                                 (op1->exponent >> 4) & 0xf); // upper 4-bits
7858                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7859                                 op1->exponent       & 0xf); // lower 4-bits
7860                     break;
7861                 case CTN9:
7862                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7863                                  op1->exponent & 0xff); // write 8-bit exponent
7864                 break;
7865             }
7866             break;
7867 
7868         case CSLS:  // fixed point, leading sign - already done
7869         case CSNS:  // fixed point, unsigned - nuttin' needed to do
7870             break;
7871     }
7872 
7873     // set flags, etc ...
7874     if (e->S2 == CSFL)
7875     {
7876         if (op1->exponent > 127)
7877         {
7878             SET_I_EOFL;
7879             EOvr = true;
7880         }
7881         if (op1->exponent < -128)
7882         {
7883             SET_I_EUFL;
7884             EOvr = true;
7885         }
7886     }
7887 
7888 sim_debug (DBG_CAC, & cpu_dev, "is neg %o\n", decNumberIsNegative(op1));
7889 sim_debug (DBG_CAC, & cpu_dev, "is zero %o\n", decNumberIsZero(op1));
7890 sim_debug (DBG_CAC, & cpu_dev, "R %o\n", R);
7891 sim_debug (DBG_CAC, & cpu_dev, "Trunc %o\n", Trunc);
7892 sim_debug (DBG_CAC, & cpu_dev, "TRUNC %o\n", TST_I_TRUNC);
7893 sim_debug (DBG_CAC, & cpu_dev, "OMASK %o\n", TST_I_OMASK);
7894 sim_debug (DBG_CAC, & cpu_dev, "tstOVFfault %o\n", tstOVFfault ());
7895 sim_debug (DBG_CAC, & cpu_dev, "T %o\n", T);
7896 sim_debug (DBG_CAC, & cpu_dev, "EOvr %o\n", EOvr);
7897 sim_debug (DBG_CAC, & cpu_dev, "Ovr %o\n", Ovr);
7898     // set negative indicator if op3 < 0
7899     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));
7900 
7901     // set zero indicator if op3 == 0
7902     SC_I_ZERO (decNumberIsZero(op1));
7903 
7904     // If the truncation condition exists without rounding, then ON;
7905     // otherwise OFF
7906     SC_I_TRUNC (!R && Trunc);
7907 
7908     cleanupOperandDescriptor (1);
7909     cleanupOperandDescriptor (2);
7910 
7911     if (TST_I_TRUNC && T && tstOVFfault ())
7912         doFault (FAULT_OFL, fst_zero, "mvn truncation(overflow) fault");
7913     if (EOvr && tstOVFfault ())
7914         doFault (FAULT_OFL, fst_zero, "mvn over/underflow fault");
7915     if (Ovr)
7916     {
7917         SET_I_OFLOW;
7918         if (tstOVFfault ())
7919           doFault (FAULT_OFL, fst_zero, "mvn overflow fault");
7920     }
7921 }
7922 
7923 void csl (void)
     /* [previous][next][first][last][top][bottom][index][help] */
7924   {
7925     EISstruct * e = & cpu.currentEISinstruction;
7926 
7927     // For i = bits 1, 2, ..., minimum (N1,N2)
7928     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
7929     //   C(BOLR)m → C(Y-bit2)i-1
7930     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
7931     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
7932     //   C(BOLR)m → C(Y-bit2)i-1
7933     //
7934     // INDICATORS: (Indicators not listed are not affected)
7935     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
7936     //     Truncation If N1 > N2, then ON; otherwise OFF
7937     //
7938     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
7939     // processed and the truncation indicator is set ON.
7940     //
7941     // If T = 1 and the truncation indicator is set ON by execution of the
7942     // instruction, then a truncation (overflow) fault occurs.
7943     //
7944     // BOLR
7945     // If first operand    and    second operand    then result
7946     // bit is:                    bit is:           is from bit:
7947     //        0                          0                      5
7948     //        0                          1                      6
7949     //        1                          0                      7
7950     //        1                          1                      8
7951     //
7952     // The Boolean operations most commonly used are
7953     //                  BOLR Field Bits
7954     // Operation        5      6      7      8
7955     //
7956     // MOVE             0      0      1      1
7957     // AND              0      0      0      1
7958     // OR               0      1      1      1
7959     // NAND             1      1      1      0
7960     // EXCLUSIVE OR     0      1      1      0
7961     // Clear            0      0      0      0
7962     // Invert           1      1      0      0
7963     //
7964 
7965 // 0 0 0 0  Clear
7966 // 0 0 0 1  a AND b
7967 // 0 0 1 0  a AND !b
7968 // 0 0 1 1  a
7969 // 0 1 0 0  !a AND b
7970 // 0 1 0 1  b
7971 // 0 1 1 0  a XOR b
7972 // 0 1 1 1  a OR b
7973 // 1 0 0 0  !a AND !b     !(a OR b)
7974 // 1 0 0 1  a == b        !(a XOR b)
7975 // 1 0 1 0  !b
7976 // 1 0 1 1  !b OR A
7977 // 1 1 0 0  !a
7978 // 1 1 0 1  !b AND a
7979 // 1 1 1 0  a NAND b
7980 // 1 1 1 1  Set
7981 
7982     fault_ipr_subtype_ mod_fault = 0;
7983 
7984 #ifndef EIS_SETUP
7985     setupOperandDescriptor (1, & mod_fault);
7986     setupOperandDescriptor (2, & mod_fault);
7987 #endif
7988 
7989     parseBitstringOperandDescriptor (1, & mod_fault);
7990     parseBitstringOperandDescriptor (2, & mod_fault);
7991 
7992     L68_ (
7993       // L68 raises it immediately
7994       if (mod_fault)
7995           doFault (FAULT_IPR,
7996                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7997                    "Illegal modifier");
7998     )
7999 
8000     // Bits 1-4 and 10 MBZ
8001     if (IWB_IRODD & 0360200000000)
8002       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8003 
8004     DPS8M_ (
8005       // DPS8M raises it delayed
8006       if (mod_fault)
8007           doFault (FAULT_IPR,
8008                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8009                    "Illegal modifier");
8010     )
8011 
8012     e->ADDR1.cPos = (int) e->C1;
8013     e->ADDR2.cPos = (int) e->C2;
8014 
8015     e->ADDR1.bPos = (int) e->B1;
8016     e->ADDR2.bPos = (int) e->B2;
8017 
8018     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8019     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8020 
8021     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8022     bool B5 = !! (BOLR & 8);
8023     bool B6 = !! (BOLR & 4);
8024     bool B7 = !! (BOLR & 2);
8025     bool B8 = !! (BOLR & 1);
8026 
8027     e->ADDR1.mode = eRWreadBit;
8028 
8029 #ifndef EIS_PTR
8030     sim_debug (DBG_TRACEEXT, & cpu_dev,
8031                "CSL N1 %d N2 %d\n"
8032                "CSL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8033                "CSL BOLR %u%u%u%u\n"
8034                "CSL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8035                "CSL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8036                e -> N1, e -> N2,
8037                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8038                B5, B6, B7, B8,
8039                e -> addr [0].SNR, e -> addr [0].address,
8040                e -> addr [0].cPos, e -> addr [0].bPos,
8041                e -> addr [1].SNR, e -> addr [1].address,
8042                e -> addr [1].cPos, e -> addr [1].bPos);
8043 #endif
8044 
8045     bool bR = false; // result bit
8046 
8047     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8048                  DU_CYCLE_FLEN_128;))
8049 
8050     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8051       {
8052         bool b1 = EISgetBitRWN(&e->ADDR1, true);
8053         e->ADDR2.mode = eRWreadBit;
8054         bool b2 = EISgetBitRWN(&e->ADDR2, true);
8055 
8056         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8057 
8058         if (bR)
8059           {
8060             //CLR_I_ZERO);
8061             cpu.du.Z = 0;
8062           }
8063 
8064         // write out modified bit
8065         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8066         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8067         // if ADDR1 is on a word boundary, it might fault on the next loop,
8068         // so we flush the write in case.
8069         EISgetBitRWN(&e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8070     }
8071 
8072     if (e->N1 < e->N2)
8073       {
8074         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8075           {
8076             bool b1 = F;
8077 
8078             e->ADDR2.mode = eRWreadBit;
8079             bool b2 = EISgetBitRWN(&e->ADDR2, true);
8080 
8081             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8082 
8083             if (bR)
8084               {
8085                 //CLR_I_ZERO;
8086                 cpu.du.Z = 0;
8087               }
8088 
8089             // write out modified bit
8090             e->ADDR2.bit = bR ? 1 : 0;
8091             e->ADDR2.mode = eRWwriteBit;
8092             // if ADDR1 is on a word boundary, it might fault on the next loop,
8093             // so we flush the write in case.
8094             EISgetBitRWN(&e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8095           }
8096       }
8097 
8098     EISWriteCache (&e->ADDR2);
8099 
8100     cleanupOperandDescriptor (1);
8101     cleanupOperandDescriptor (2);
8102 
8103     SC_I_ZERO (cpu.du.Z);
8104     if (e->N1 > e->N2)
8105       {
8106         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8107         // processed and the truncation indicator is set ON.
8108         //
8109         // If T = 1 and the truncation indicator is set ON by execution of the
8110         // instruction, then a truncation (overflow) fault occurs.
8111 
8112         SET_I_TRUNC;
8113         if (T && tstOVFfault ())
8114           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8115       }
8116     else
8117       {
8118         CLR_I_TRUNC;
8119       }
8120   }
8121 
8122 /*
8123  * return B (bit position), C (char position) and word offset given:
8124  *  'length' # of bits, etc ....
8125  *  'initC' initial char position (C)
8126  *  'initB' initial bit position
8127  */
8128 
8129 static void getBitOffsets(int length, int initC, int initB, int *nWords, int *newC, int *newB)
     /* [previous][next][first][last][top][bottom][index][help] */
8130 {
8131     if (length == 0)
8132         return;
8133 
8134     int endBit = (length + 9 * initC + initB - 1) % 36;
8135 
8136     //int numWords = (length + 35) / 36;  // how many additional words will the bits take up?
8137     int numWords = (length + 9 * initC + initB + 35) / 36;  // how many additional words will the bits take up?
8138     int lastWordOffset = numWords - 1;
8139 
8140     if (lastWordOffset > 0)          // more that the 1 word needed?
8141         *nWords = lastWordOffset;  // # of additional words
8142     else
8143         *nWords = 0;    // no additional words needed
8144 
8145     *newC = endBit / 9; // last character number
8146     *newB = endBit % 9; // last bit number
8147 }
8148 
8149 static bool EISgetBitRWNR (EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
8150   {
8151     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
8152     int baseBitPosn = baseCharPosn + p -> bPos;
8153     baseBitPosn -= (int) cpu.du.CHTALLY;
8154 
8155     int bitPosn = baseBitPosn % 36;
8156     int woff = baseBitPosn / 36;
8157     while (bitPosn < 0)
8158       {
8159         bitPosn += 36;
8160         woff -= 1;
8161       }
8162 
8163 /* if (bitPosn < 0) { */
8164 /* sim_printf ("cPos %d bPos %d\n", p->cPos, p->bPos); */
8165 /* sim_printf ("baseCharPosn %d baseBitPosn %d\n", baseCharPosn, baseBitPosn); */
8166 /* sim_printf ("CHTALLY %d baseBitPosn %d\n", cpu.du.CHTALLY, baseBitPosn); */
8167 /* sim_printf ("bitPosn %d woff %d\n", bitPosn, woff); */
8168 /* sim_warn ("EISgetBitRWNR oops\n"); */
8169 /* return false; */
8170 /* } */
8171 
8172 #ifdef EIS_PTR
8173     long eisaddr_idx = EISADDR_IDX (p);
8174 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8175     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
8176     cpu.du.Dk_PTR_W[eisaddr_idx] += (word18) woff;
8177     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8178 #else
8179     word18 saveAddr = p -> address;
8180     //p -> address += (word18) woff;
8181     //ubsan
8182     p->address = (word18) (((word18s) p->address) + (word18s) woff);
8183 #endif
8184 
8185     p -> data = EISRead (p); // read data word from memory
8186 
8187     if (p -> mode == eRWreadBit)
8188       {
8189         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
8190       }
8191     else if (p -> mode == eRWwriteBit)
8192       {
8193         //p -> data = bitfieldInsert36 (p -> data, p -> bit, bitPosn, 1);
8194         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
8195 
8196         EISWriteIdx (p, 0, p -> data, flush); // write data word to memory
8197       }
8198 
8199     p->last_bit_posn = bitPosn;
8200 
8201 #ifdef EIS_PTR
8202     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
8203 #else
8204     p -> address = saveAddr;
8205 #endif
8206     return p -> bit;
8207   }
8208 
8209 void csr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8210   {
8211     EISstruct * e = & cpu.currentEISinstruction;
8212 
8213     // For i = bits 1, 2, ..., minimum (N1,N2)
8214     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8215     //   C(BOLR)m → C( Y-bit2)N2-i
8216     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8217     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8218     //    C(BOLR)m → C( Y-bit2)N2-i
8219     // INDICATORS: (Indicators not listed are not affected)
8220     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8221     //     Truncation If N1 > N2, then ON; otherwise OFF
8222     //
8223     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8224     // processed and the truncation indicator is set ON.
8225     //
8226     // If T = 1 and the truncation indicator is set ON by execution of the
8227     // instruction, then a truncation (overflow) fault occurs.
8228     //
8229     // BOLR
8230     // If first operand    and    second operand    then result
8231     // bit is:                    bit is:           is from bit:
8232     //        0                          0                      5
8233     //        0                          1                      6
8234     //        1                          0                      7
8235     //        1                          1                      8
8236     //
8237     // The Boolean operations most commonly used are
8238     //                  BOLR Field Bits
8239     // Operation        5      6      7      8
8240     //
8241     // MOVE             0      0      1      1
8242     // AND              0      0      0      1
8243     // OR               0      1      1      1
8244     // NAND             1      1      1      0
8245     // EXCLUSIVE OR     0      1      1      0
8246     // Clear            0      0      0      0
8247     // Invert           1      1      0      0
8248     //
8249 
8250     fault_ipr_subtype_ mod_fault = 0;
8251 
8252 #ifndef EIS_SETUP
8253     setupOperandDescriptor(1, &mod_fault);
8254     setupOperandDescriptor(2, &mod_fault);
8255 #endif
8256 
8257     parseBitstringOperandDescriptor(1, &mod_fault);
8258     parseBitstringOperandDescriptor(2, &mod_fault);
8259 
8260     L68_ (
8261       // L68 raises it immediately
8262       if (mod_fault)
8263           doFault (FAULT_IPR,
8264                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8265                    "Illegal modifier");
8266     )
8267 
8268     // Bits 1-4 and 10 MBZ
8269     if (IWB_IRODD & 0360200000000)
8270       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8271 
8272     DPS8M_ (
8273       // DPS8M raises it delayed
8274       if (mod_fault)
8275           doFault (FAULT_IPR,
8276                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8277                    "Illegal modifier");
8278     )
8279 
8280     e->ADDR1.cPos = (int) e->C1;
8281     e->ADDR2.cPos = (int) e->C2;
8282 
8283     e->ADDR1.bPos = (int) e->B1;
8284     e->ADDR2.bPos = (int) e->B2;
8285 
8286     // get new char/bit offsets
8287     int numWords1=0, numWords2=0;
8288 
8289     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8290     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8291     PNL (cpu.du.D1_PTR_W &= AMASK);
8292 #ifdef EIS_PTR
8293     cpu.du.D1_PTR_W += (word18) numWords1;
8294     cpu.du.D1_PTR_W &= AMASK;
8295 #else
8296     e->ADDR1.address += (word18) numWords1;
8297 #endif
8298 
8299     sim_debug (DBG_TRACEEXT, & cpu_dev,
8300                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8301                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8302     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8303     sim_debug (DBG_TRACEEXT, & cpu_dev,
8304                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8305                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8306     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8307     PNL (cpu.du.D2_PTR_W &= AMASK);
8308 #ifdef EIS_PTR
8309     cpu.du.D2_PTR_W += (word18) numWords1;
8310     cpu.du.D2_PTR_W &= AMASK;
8311 #else
8312     e->ADDR2.address += (word18) numWords2;
8313 #endif
8314 
8315     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8316     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8317 
8318     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8319     bool B5 = !! (BOLR & 8);
8320     bool B6 = !! (BOLR & 4);
8321     bool B7 = !! (BOLR & 2);
8322     bool B8 = !! (BOLR & 1);
8323 
8324     e->ADDR1.mode = eRWreadBit;
8325 
8326     CLR_I_TRUNC;     // assume N1 <= N2
8327 
8328     bool bR = false; // result bit
8329 
8330     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8331                  DU_CYCLE_FLEN_128;))
8332 
8333     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8334       {
8335         bool b1 = EISgetBitRWNR(&e->ADDR1, true);
8336 
8337         e->ADDR2.mode = eRWreadBit;
8338         bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8339 
8340         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8341 
8342         if (bR)
8343           cpu.du.Z = 0;
8344 
8345         // write out modified bit
8346         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8347         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8348         // if ADDR1 is on a word boundary, it might fault on the next loop,
8349         // so we flush the write in case.
8350         EISgetBitRWNR(&e->ADDR2, e->ADDR1.last_bit_posn == 0);
8351       }
8352 
8353     if (e->N1 < e->N2)
8354       {
8355         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8356           {
8357             bool b1 = F;
8358 
8359             e->ADDR2.mode = eRWreadBit;
8360             bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8361 
8362             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8363 
8364             if (bR)
8365               {
8366                 //CLR_I_ZERO;
8367                 cpu.du.Z = 0;
8368               }
8369 
8370             // write out modified bit
8371             e->ADDR2.bit = bR ? 1 : 0;
8372             e->ADDR2.mode = eRWwriteBit;
8373             // if ADDR1 is on a word boundary, it might fault on the next loop,
8374             // so we flush the write in case.
8375             EISgetBitRWNR(&e->ADDR2, e->ADDR1.last_bit_posn == 0);
8376           }
8377       }
8378 
8379     EISWriteCache (&e->ADDR2);
8380 
8381     cleanupOperandDescriptor (1);
8382     cleanupOperandDescriptor (2);
8383 
8384     SC_I_ZERO (cpu.du.Z);
8385     if (e->N1 > e->N2)
8386       {
8387         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8388         // processed and the truncation indicator is set ON.
8389         //
8390         // If T = 1 and the truncation indicator is set ON by execution of the
8391         // instruction, then a truncation (overflow) fault occurs.
8392 
8393         SET_I_TRUNC;
8394         if (T && tstOVFfault ())
8395           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8396       }
8397     else
8398       {
8399         CLR_I_TRUNC;
8400       }
8401   }
8402 
8403 void sztl (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8404   {
8405 
8406     // The execution of this instruction is identical to the Combine
8407     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8408     // not placed into C(Y-bit2)i-1.
8409 
8410     EISstruct * e = & cpu.currentEISinstruction;
8411 
8412     // For i = bits 1, 2, ..., minimum (N1,N2)
8413     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
8414     //   C(BOLR)m → C(Y-bit2)i-1
8415     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
8416     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
8417     //   C(BOLR)m → C(Y-bit2)i-1
8418     //
8419     // INDICATORS: (Indicators not listed are not affected)
8420     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8421     //     Truncation If N1 > N2, then ON; otherwise OFF
8422     //
8423     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8424     // processed and the truncation indicator is set ON.
8425     //
8426     // If T = 1 and the truncation indicator is set ON by execution of the
8427     // instruction, then a truncation (overflow) fault occurs.
8428     //
8429     // BOLR
8430     // If first operand    and    second operand    then result
8431     // bit is:                    bit is:           is from bit:
8432     //        0                          0                      5
8433     //        0                          1                      6
8434     //        1                          0                      7
8435     //        1                          1                      8
8436     //
8437     // The Boolean operations most commonly used are
8438     //                  BOLR Field Bits
8439     // Operation        5      6      7      8
8440     //
8441     // MOVE             0      0      1      1
8442     // AND              0      0      0      1
8443     // OR               0      1      1      1
8444     // NAND             1      1      1      0
8445     // EXCLUSIVE OR     0      1      1      0
8446     // Clear            0      0      0      0
8447     // Invert           1      1      0      0
8448     //
8449 
8450 // 0 0 0 0  Clear
8451 // 0 0 0 1  a AND b
8452 // 0 0 1 0  a AND !b
8453 // 0 0 1 1  a
8454 // 0 1 0 0  !a AND b
8455 // 0 1 0 1  b
8456 // 0 1 1 0  a XOR b
8457 // 0 1 1 1  a OR b
8458 // 1 0 0 0  !a AND !b     !(a OR b)
8459 // 1 0 0 1  a == b        !(a XOR b)
8460 // 1 0 1 0  !b
8461 // 1 0 1 1  !b OR A
8462 // 1 1 0 0  !a
8463 // 1 1 0 1  !b AND a
8464 // 1 1 1 0  a NAND b
8465 // 1 1 1 1  Set
8466 
8467     fault_ipr_subtype_ mod_fault = 0;
8468 
8469 #ifndef EIS_SETUP
8470     setupOperandDescriptor (1, &mod_fault);
8471     setupOperandDescriptor (2, &mod_fault);
8472 #endif
8473 
8474     parseBitstringOperandDescriptor (1, &mod_fault);
8475     parseBitstringOperandDescriptor (2, &mod_fault);
8476 
8477     L68_ (
8478       // L68 raises it immediately
8479       if (mod_fault)
8480           doFault (FAULT_IPR,
8481                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8482                    "Illegal modifier");
8483     )
8484 
8485     // Bits 1-4 and 10 MBZ
8486     if (IWB_IRODD & 0360200000000)
8487       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8488 
8489     DPS8M_ (
8490       // DPS8M raises it delayed
8491       if (mod_fault)
8492           doFault (FAULT_IPR,
8493                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8494                    "Illegal modifier");
8495     )
8496 
8497     e->ADDR1.cPos = (int) e->C1;
8498     e->ADDR2.cPos = (int) e->C2;
8499 
8500     e->ADDR1.bPos = (int) e->B1;
8501     e->ADDR2.bPos = (int) e->B2;
8502 
8503     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8504     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8505 
8506     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8507     bool B5 = !! (BOLR & 8);
8508     bool B6 = !! (BOLR & 4);
8509     bool B7 = !! (BOLR & 2);
8510     bool B8 = !! (BOLR & 1);
8511 
8512     e->ADDR1.mode = eRWreadBit;
8513     e->ADDR2.mode = eRWreadBit;
8514 
8515 #ifndef EIS_PTR
8516     sim_debug (DBG_TRACEEXT, & cpu_dev,
8517                "SZTL N1 %d N2 %d\n"
8518                "SZTL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8519                "SZTL BOLR %u%u%u%u\n"
8520                "SZTL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8521                "SZTL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8522                e -> N1, e -> N2,
8523                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8524                B5, B6, B7, B8,
8525                e -> addr [0].SNR, e -> addr [0].address,
8526                e -> addr [0].cPos, e -> addr [0].bPos,
8527                e -> addr [1].SNR, e -> addr [1].address,
8528                e -> addr [1].cPos, e -> addr [1].bPos);
8529 #endif
8530 
8531     bool bR = false; // result bit
8532 
8533     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8534                  DU_CYCLE_FLEN_128;))
8535 
8536     for( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY += 1)
8537     {
8538         bool b1 = EISgetBitRWN (& e->ADDR1, true);
8539         bool b2 = EISgetBitRWN (& e->ADDR2, true);
8540 
8541         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8542 
8543         if (bR)
8544           {
8545             //CLR_I_ZERO);
8546             cpu.du.Z = 0;
8547             break;
8548           }
8549       }
8550 
8551     if (e->N1 < e->N2)
8552       {
8553         for (; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8554           {
8555             bool b1 = F;
8556             bool b2 = EISgetBitRWN (& e->ADDR2, true);
8557 
8558             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8559 
8560             if (bR)
8561               {
8562                 //CLR_I_ZERO;
8563                 cpu.du.Z = 0;
8564                 break;
8565               }
8566           }
8567       }
8568 
8569     cleanupOperandDescriptor (1);
8570     cleanupOperandDescriptor (2);
8571 
8572     SC_I_ZERO (cpu.du.Z);
8573     if (e->N1 > e->N2)
8574       {
8575         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8576         // processed and the truncation indicator is set ON.
8577         //
8578         // If T = 1 and the truncation indicator is set ON by execution of the
8579         // instruction, then a truncation (overflow) fault occurs.
8580 
8581         SET_I_TRUNC;
8582         if (T && tstOVFfault ())
8583           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8584       }
8585     else
8586       {
8587         CLR_I_TRUNC;
8588       }
8589   }
8590 
8591 void sztr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8592   {
8593 
8594     // The execution of this instruction is identical to the Combine
8595     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8596     // not placed into C(Y-bit2)i-1.
8597 
8598     EISstruct * e = & cpu.currentEISinstruction;
8599 
8600     // For i = bits 1, 2, ..., minimum (N1,N2)
8601     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8602     //   C(BOLR)m → C( Y-bit2)N2-i
8603     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8604     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8605     //    C(BOLR)m → C( Y-bit2)N2-i
8606     // INDICATORS: (Indicators not listed are not affected)
8607     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8608     //     Truncation If N1 > N2, then ON; otherwise OFF
8609     //
8610     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8611     // processed and the truncation indicator is set ON.
8612     //
8613     // If T = 1 and the truncation indicator is set ON by execution of the
8614     // instruction, then a truncation (overflow) fault occurs.
8615     //
8616     // BOLR
8617     // If first operand    and    second operand    then result
8618     // bit is:                    bit is:           is from bit:
8619     //        0                          0                      5
8620     //        0                          1                      6
8621     //        1                          0                      7
8622     //        1                          1                      8
8623     //
8624     // The Boolean operations most commonly used are
8625     //                  BOLR Field Bits
8626     // Operation        5      6      7      8
8627     //
8628     // MOVE             0      0      1      1
8629     // AND              0      0      0      1
8630     // OR               0      1      1      1
8631     // NAND             1      1      1      0
8632     // EXCLUSIVE OR     0      1      1      0
8633     // Clear            0      0      0      0
8634     // Invert           1      1      0      0
8635     //
8636 
8637     fault_ipr_subtype_ mod_fault = 0;
8638 
8639 #ifndef EIS_SETUP
8640     setupOperandDescriptor(1, &mod_fault);
8641     setupOperandDescriptor(2, &mod_fault);
8642 #endif
8643 
8644     parseBitstringOperandDescriptor(1, &mod_fault);
8645     parseBitstringOperandDescriptor(2, &mod_fault);
8646 
8647     L68_ (
8648       // L68 raises it immediately
8649       if (mod_fault)
8650           doFault (FAULT_IPR,
8651                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8652                    "Illegal modifier");
8653     )
8654 
8655     // Bits 1-4 and 10 MBZ
8656     if (IWB_IRODD & 0360200000000)
8657       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8658 
8659     DPS8M_ (
8660       // DPS8M raises it delayed
8661       if (mod_fault)
8662           doFault (FAULT_IPR,
8663                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8664                    "Illegal modifier");
8665     )
8666 
8667     e->ADDR1.cPos = (int) e->C1;
8668     e->ADDR2.cPos = (int) e->C2;
8669 
8670     e->ADDR1.bPos = (int) e->B1;
8671     e->ADDR2.bPos = (int) e->B2;
8672 
8673     // get new char/bit offsets
8674     int numWords1=0, numWords2=0;
8675 
8676     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8677     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8678     PNL (cpu.du.D1_PTR_W &= AMASK);
8679 #ifdef EIS_PTR
8680     cpu.du.D1_PTR_W += (word18) numWords1;
8681     cpu.du.D1_PTR_W &= AMASK;
8682 #else
8683     e->ADDR1.address += (word18) numWords1;
8684 #endif
8685 
8686     sim_debug (DBG_TRACEEXT, & cpu_dev,
8687                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8688                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8689     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8690     sim_debug (DBG_TRACEEXT, & cpu_dev,
8691                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8692                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8693     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8694     PNL (cpu.du.D2_PTR_W &= AMASK);
8695 #ifdef EIS_PTR
8696     cpu.du.D2_PTR_W += (word18) numWords1;
8697     cpu.du.D2_PTR_W &= AMASK;
8698 #else
8699     e->ADDR2.address += (word18) numWords2;
8700 #endif
8701 
8702     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8703     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8704 
8705     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8706     bool B5 = !! (BOLR & 8);
8707     bool B6 = !! (BOLR & 4);
8708     bool B7 = !! (BOLR & 2);
8709     bool B8 = !! (BOLR & 1);
8710 
8711     e->ADDR1.mode = eRWreadBit;
8712 
8713     CLR_I_TRUNC;     // assume N1 <= N2
8714 
8715     bool bR = false; // result bit
8716 
8717     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8718                  DU_CYCLE_FLEN_128;))
8719 
8720     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8721       {
8722         bool b1 = EISgetBitRWNR(&e->ADDR1, true);
8723 
8724         e->ADDR2.mode = eRWreadBit;
8725         bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8726 
8727         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8728 
8729         if (bR)
8730           {
8731             cpu.du.Z = 0;
8732             break;
8733           }
8734 
8735       }
8736 
8737     if (e->N1 < e->N2)
8738       {
8739         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8740           {
8741             bool b1 = F;
8742 
8743             e->ADDR2.mode = eRWreadBit;
8744             bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8745 
8746             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8747 
8748             if (bR)
8749             {
8750                 //CLR_I_ZERO;
8751                 cpu.du.Z = 0;
8752                 break;
8753             }
8754 
8755           }
8756       }
8757 
8758     cleanupOperandDescriptor (1);
8759     cleanupOperandDescriptor (2);
8760 
8761     SC_I_ZERO (cpu.du.Z);
8762     if (e->N1 > e->N2)
8763       {
8764         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8765         // processed and the truncation indicator is set ON.
8766         //
8767         // If T = 1 and the truncation indicator is set ON by execution of the
8768         // instruction, then a truncation (overflow) fault occurs.
8769 
8770         SET_I_TRUNC;
8771         if (T && tstOVFfault ())
8772           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8773       }
8774     else
8775       {
8776         CLR_I_TRUNC;
8777       }
8778   }
8779 
8780 /*
8781  * CMPB - Compare Bit Strings
8782  */
8783 
8784 /*
8785  * get a bit from memory ....
8786  */
8787 // XXX this is terribly inefficient, but it'll do for now ......
8788 
8789 static bool EISgetBit(EISaddr *p, int *cpos, int *bpos)
     /* [previous][next][first][last][top][bottom][index][help] */
8790 {
8791 #ifdef EIS_PTR
8792     long eisaddr_idx = EISADDR_IDX (p);
8793 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8794 #endif
8795 
8796     if (!p)
8797     {
8798         //lastAddress = -1;
8799         return 0;
8800     }
8801 
8802     if (*bpos > 8)      // bits 0-8
8803     {
8804         *bpos = 0;
8805         *cpos += 1;
8806         if (*cpos > 3)  // chars 0-3
8807         {
8808             *cpos = 0;
8809 #ifdef EIS_PTR
8810             cpu.du.Dk_PTR_W[eisaddr_idx] += 1;
8811             cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8812 #else
8813             p->address += 1;
8814             p->address &= AMASK;
8815 #endif
8816         }
8817     }
8818 
8819     p->data = EISRead(p); // read data word from memory
8820 
8821     int charPosn = *cpos * 9;
8822     int bitPosn = charPosn + *bpos;
8823     bool b = getbits36_1 (p->data, (uint) bitPosn) != 0;
8824 
8825     *bpos += 1;
8826 
8827     return b;
8828 }
8829 
8830 void cmpb (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8831 {
8832     EISstruct * e = & cpu.currentEISinstruction;
8833 
8834     // For i = 1, 2, ..., minimum (N1,N2)
8835     //   C(Y-bit1)i-1 :: C(Y-bit2)i-1
8836     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
8837     //   C(FILL) :: C(Y-bit2)i-1
8838     // If N1 > N2, then for i = N2+l, N2+2, ..., N1
8839     //   C(Y-bit1)i-1 :: C(FILL)
8840     //
8841     // Indicators:
8842     //    Zero:  If C(Y-bit1)i = C(Y-bit2)i for all i, then ON; otherwise, OFF
8843     //    Carry: If C(Y-bit1)i < C(Y-bit2)i for any i, then OFF; otherwise ON
8844 
8845     fault_ipr_subtype_ mod_fault = 0;
8846 
8847 #ifndef EIS_SETUP
8848     setupOperandDescriptor(1, &mod_fault);
8849     setupOperandDescriptor(2, &mod_fault);
8850 #endif
8851 
8852     parseBitstringOperandDescriptor(1, &mod_fault);
8853     parseBitstringOperandDescriptor(2, &mod_fault);
8854 
8855     L68_ (
8856       // L68 raises it immediately
8857       if (mod_fault)
8858         {
8859           doFault (FAULT_IPR,
8860                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8861                    "Illegal modifier");
8862         }
8863     )
8864 
8865     // Bits 1-8 and 10 MBZ
8866     if (IWB_IRODD & 0377200000000)
8867       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpb 1-8,10 MBZ");
8868 
8869     DPS8M_ (
8870       // DPS8M raises it delayed
8871       if (mod_fault)
8872         {
8873           doFault (FAULT_IPR,
8874                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8875                    "Illegal modifier");
8876         }
8877     )
8878 
8879     int charPosn1 = (int) e->C1;
8880     int charPosn2 = (int) e->C2;
8881 
8882     int bitPosn1 = (int) e->B1;
8883     int bitPosn2 = (int) e->B2;
8884 
8885     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8886 
8887     SET_I_ZERO;  // assume all =
8888     SET_I_CARRY; // assume all >=
8889 
8890 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb N1 %d N2 %d\n", e -> N1, e -> N2);
8891 
8892 
8893 
8894 
8895 
8896 
8897 
8898 
8899 
8900 
8901 
8902 
8903 
8904 
8905 
8906 
8907 
8908     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8909       DU_CYCLE_FLEN_128;))
8910 
8911     uint i;
8912     for(i = 0 ; i < min(e->N1, e->N2) ; i += 1)
8913     {
8914         bool b1 = EISgetBit (&e->ADDR1, &charPosn1, &bitPosn1);
8915         bool b2 = EISgetBit (&e->ADDR2, &charPosn2, &bitPosn2);
8916 
8917 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(min(e->N1, e->N2)) i %d b1 %d b2 %d\n", i, b1, b2);
8918         if (b1 != b2)
8919         {
8920             CLR_I_ZERO;
8921             if (!b1 && b2)  // 0 < 1
8922                 CLR_I_CARRY;
8923 
8924             cleanupOperandDescriptor (1);
8925             cleanupOperandDescriptor (2);
8926 
8927             return;
8928         }
8929 
8930     }
8931     if (e->N1 < e->N2)
8932     {
8933         for(; i < e->N2 ; i += 1)
8934         {
8935             bool b1 = F;
8936             bool b2 = EISgetBit(&e->ADDR2, &charPosn2, &bitPosn2);
8937 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 < e->N2) i %d b1fill %d b2 %d\n", i, b1, b2);
8938 
8939             if (b1 != b2)
8940             {
8941                 CLR_I_ZERO;
8942                 if (!b1 && b2)  // 0 < 1
8943                     CLR_I_CARRY;
8944 
8945                 cleanupOperandDescriptor (1);
8946                 cleanupOperandDescriptor (2);
8947 
8948                 return;
8949             }
8950         }
8951     } else if (e->N1 > e->N2)
8952     {
8953         for(; i < e->N1 ; i += 1)
8954         {
8955             bool b1 = EISgetBit(&e->ADDR1, &charPosn1, &bitPosn1);
8956             bool b2 = F;
8957 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 > e->N2) i %d b1 %d b2fill %d\n", i, b1, b2);
8958 
8959             if (b1 != b2)
8960             {
8961                 CLR_I_ZERO;
8962                 if (!b1 && b2)  // 0 < 1
8963                     CLR_I_CARRY;
8964 
8965                 cleanupOperandDescriptor (1);
8966                 cleanupOperandDescriptor (2);
8967 
8968                 return;
8969             }
8970         }
8971     }
8972     cleanupOperandDescriptor (1);
8973     cleanupOperandDescriptor (2);
8974 }
8975 
8976 
8977 
8978 
8979 
8980 
8981 
8982 
8983 
8984 
8985 
8986 
8987 
8988 
8989 
8990 
8991 
8992 
8993 
8994 
8995 
8996 
8997 
8998 
8999 
9000 
9001 
9002 
9003 
9004 
9005 
9006 
9007 
9008 
9009 
9010 
9011 
9012 
9013 
9014 
9015 
9016 
9017 
9018 
9019 
9020 
9021 
9022 
9023 
9024 
9025 
9026 
9027 
9028 
9029 
9030 
9031 
9032 
9033 
9034 
9035 
9036 
9037 
9038 
9039 
9040 
9041 
9042 
9043 
9044 
9045 
9046 
9047 
9048 
9049 
9050 
9051 
9052 
9053 
9054 
9055 
9056 
9057 
9058 
9059 
9060 
9061 
9062 
9063 
9064 
9065 
9066 
9067 
9068 
9069 
9070 
9071 
9072 
9073 
9074 
9075 
9076 
9077 
9078 
9079 
9080 
9081 
9082 
9083 
9084 
9085 
9086 
9087 
9088 
9089 
9090 
9091 
9092 
9093 
9094 
9095 
9096 
9097 
9098 
9099 
9100 
9101 
9102 
9103 
9104 
9105 
9106 
9107 
9108 
9109 
9110 
9111 
9112 
9113 
9114 
9115 
9116 
9117 
9118 
9119 
9120 
9121 
9122 
9123 
9124 
9125 
9126 
9127 
9128 
9129 
9130 
9131 
9132 
9133 
9134 
9135 
9136 
9137 
9138 
9139 
9140 
9141 
9142 
9143 
9144 
9145 
9146 
9147 
9148 
9149 
9150 
9151 
9152 
9153 
9154 
9155 
9156 
9157 
9158 
9159 
9160 
9161 
9162 
9163 
9164 
9165 
9166 
9167 
9168 
9169 
9170 
9171 
9172 
9173 
9174 
9175 
9176 
9177 
9178 
9179 
9180 
9181 
9182 
9183 
9184 
9185 
9186 
9187 
9188 
9189 
9190 
9191 
9192 
9193 
9194 
9195 
9196 
9197 /*
9198  * determine sign of N*9-bit length word
9199  */
9200 static bool sign9n(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9201 {
9202 
9203     // sign bit of  9-bit is bit 8  (1 << 8)
9204     // sign bit of 18-bit is bit 17 (1 << 17)
9205     // .
9206     // .
9207     // .
9208     // sign bit of 72-bit is bit 71 (1 << 71)
9209 
9210     if (N < 1 || N > 8) // XXX largest int we'll play with is 72-bits? Makes sense
9211         return false;
9212 
9213 #ifdef NEED_128
9214     word72 sgnmask = lshift_128 (construct_128 (0, 1), (uint) (N * 9 - 1));
9215     return isnonzero_128 (and_128 (sgnmask, n128));
9216 #else
9217     word72 sgnmask = (word72)1 << ((N * 9) - 1);
9218 
9219     return (bool)(sgnmask & n128);
9220 #endif
9221 }
9222 
9223 /*
9224  * sign extend a N*9 length word to a (word72) 128-bit word
9225  */
9226 static word72s signExt9(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9227 {
9228     // ext mask for  9-bit = 037777777777777777777777777777777777777400  8 0's
9229     // ext mask for 18-bit = 037777777777777777777777777777777777400000 17 0's
9230     // ext mask for 36-bit = 037777777777777777777777777777400000000000 35 0's
9231     // etc...
9232 
9233     int bits = (N * 9) - 1;
9234     if (sign9n(n128, N))
9235     {
9236 #ifdef NEED_128
9237         uint128 extBits = lshift_128 (construct_128 (MASK64, MASK64), (uint) bits);
9238         uint128 or = or_128 (n128, extBits);
9239         return cast_s128 (or);
9240 #else
9241         uint128 extBits = ((uint128)-1 << bits);
9242         return (word72s) (n128 | extBits);
9243 #endif
9244     }
9245 #ifdef NEED_128
9246     uint128 zeroBits = complement_128 (lshift_128 (construct_128 (MASK64, MASK64), (uint) bits));
9247     uint128 and = and_128 (n128, zeroBits);
9248     return cast_s128 (and);
9249 #else
9250     uint128 zeroBits = ~((uint128)-1 << bits);
9251     return (word72s) (n128 & zeroBits);
9252 #endif
9253 }
9254 
9255 /*
9256  * load a 9*n bit integer into e->x ...
9257  */
9258 
9259 static void load9x(int n, EISaddr *addr, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
9260 {
9261     EISstruct * e = & cpu.currentEISinstruction;
9262 #ifdef NEED_128
9263     word72 x = construct_128 (0, 0);
9264 #else
9265     word72 x = 0;
9266 #endif
9267 #ifdef EIS_PTR
9268     long eisaddr_idx = EISADDR_IDX (addr);
9269 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
9270 #endif
9271 
9272     word36 data = EISRead(addr);
9273 
9274     int m = n;
9275     while (m)
9276     {
9277 #ifdef NEED_128
9278         x = lshift_128 (x, 9);
9279 #else
9280         x <<= 9;         // make room for next 9-bit byte
9281 #endif
9282 
9283         if (pos > 3)        // overflows to next word?
9284         {   // yep....
9285             pos = 0;        // reset to 1st byte
9286 #if EIS_PTR
9287             cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;          // bump source to next address
9288 #else
9289             addr->address = (addr->address + 1) & AMASK;          // bump source to next address
9290 #endif
9291             data = EISRead(addr);    // read it from memory
9292         }
9293 
9294 #ifdef NEED_128
9295         x = or_128 (x, construct_128 (0, GETBYTE (data, pos)));
9296 #else
9297         x |= GETBYTE(data, pos);   // fetch byte at position pos and 'or' it in
9298 #endif
9299 
9300         pos += 1;           // onto next position
9301 
9302         m -= 1;             // decrement byte counter
9303     }
9304     e->x = signExt9(x, n);  // form proper 2's-complement integer
9305 }
9306 
9307 
9308 
9309 
9310 
9311 
9312 
9313 
9314 
9315 
9316 
9317 
9318 
9319 
9320 
9321 
9322 
9323 
9324 
9325 
9326 
9327 
9328 
9329 
9330 
9331 
9332 
9333 
9334 
9335 
9336 
9337 
9338 
9339 
9340 
9341 
9342 
9343 
9344 
9345 
9346 
9347 
9348 
9349 
9350 
9351 
9352 
9353 
9354 
9355 
9356 
9357 
9358 
9359 
9360 
9361 
9362 
9363 
9364 
9365 
9366 
9367 
9368 
9369 
9370 
9371 
9372 
9373 
9374 
9375 
9376 
9377 
9378 
9379 
9380 
9381 
9382 
9383 
9384 
9385 
9386 
9387 
9388 
9389 
9390 
9391 
9392 
9393 
9394 
9395 
9396 
9397 
9398 
9399 
9400 
9401 
9402 
9403 
9404 
9405 
9406 
9407 
9408 
9409 
9410 
9411 
9412 
9413 
9414 
9415 
9416 
9417 
9418 
9419 
9420 
9421 
9422 
9423 
9424 
9425 
9426 
9427 void btd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9428 {
9429     EISstruct * e = & cpu.currentEISinstruction;
9430 
9431     // C(Y-char91) converted to decimal → C(Y-charn2)
9432     /*!
9433      * C(Y-char91) contains a twos complement binary integer aligned on 9-bit
9434      * character boundaries with length 0 < N1 <= 8.
9435      *
9436      * If TN2 and S2 specify a 4-bit signed number and P = 1, then if
9437      * C(Y-char91) is positive (bit 0 of C(Y-char91)0 = 0), then the 13(8) plus
9438      * sign character is moved to C(Y-charn2) as appropriate.
9439      *
9440      *   The scaling factor of C(Y-charn2), SF2, must be 0.
9441      *
9442      *   If N2 is not large enough to hold the digits generated by conversion
9443      *   of C(Y-char91) an overflow condition exists; the overflow indicator is
9444      *   set ON and an overflow fault occurs. This implies that an unsigned
9445      *   fixed-point receiving field has a minimum length of 1 character and a
9446      *   signed fixed- point field, 2 characters.
9447      *
9448      * If MFk.RL = 1, then Nk does not contain the operand length; instead; it
9449      * contains a register code for a register holding the operand length.
9450      *
9451      * If MFk.ID = 1, then the kth word following the instruction word does not
9452      * contain an operand descriptor; instead, it contains an indirect pointer
9453      * to the operand descriptor.
9454      *
9455      * C(Y-char91) and C(Y-charn2) may be overlapping strings; no check is made.
9456      *
9457      * Attempted conversion to a floating-point number (S2 = 0) or attempted
9458      * use of a scaling factor (SF2 ≠ 0) causes an illegal procedure fault.
9459      *
9460      * If N1 = 0 or N1 > 8 an illegal procedure fault occurs.
9461      *
9462      * Attempted execution with the xed instruction causes an illegal procedure fault.
9463      *
9464      * Attempted repetition with the rpt, rpd, or rpl instructions causes an illegal procedure fault.
9465      *
9466      */
9467 
9468     // C(string 1) -> C(string 2) (converted)
9469 
9470     // The two's complement binary integer starting at location YC1 is
9471     // converted into a signed string of decimal characters of data type TN2,
9472     // sign and decimal type S2 (S2 = 00 is illegal) and scale factor 0; and is
9473     // stored, right-justified, as a string of length L2 starting at location
9474     // YC2. If the string generated is longer than L2, the high-order excess is
9475     // truncated and the overflow indicator is set. If strings 1 and 2 are not
9476     // overlapped, the contents of string 1 remain unchanged. The length of
9477     // string 1 (L1) is given as the number of 9-bit segments that make up the
9478     // string. L1 is equal to or is less than 8. Thus, the binary string to be
9479     // converted can be 9, 18, 27, 36, 45, 54, 63, or 72 bits long. CN1
9480     // designates a 9-bit character boundary. If P=1, positive signed 4-bit
9481     // results are stored using octal 13 as the plus sign. If P=0, positive
9482     // signed 4-bit results are stored with octal 14 as the plus sign.
9483 
9484     fault_ipr_subtype_ mod_fault = 0;
9485 
9486 #ifndef EIS_SETUP
9487     setupOperandDescriptor(1, &mod_fault);
9488     setupOperandDescriptor(2, &mod_fault);
9489 #endif
9490 
9491     parseNumericOperandDescriptor(1, &mod_fault);
9492     parseNumericOperandDescriptor(2, &mod_fault);
9493 
9494     L68_ (
9495       // L68 raises it immediately
9496       if (mod_fault)
9497         {
9498           doFault (FAULT_IPR,
9499                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9500                    "Illegal modifier");
9501         }
9502     )
9503 
9504     // Bits 1-10 MBZ
9505     if (IWB_IRODD & 0377600000000)
9506       {
9507         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
9508         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "btd 0-8 MBZ");
9509       }
9510 
9511     // Bits 21-29 of OP1 MBZ
9512     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000077700)
9513       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op1 21-29 MBZ");
9514 
9515     // Bits 24-29 of OP2 MBZ
9516     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000007700)
9517       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 24-29 MBZ");
9518 
9519     if (e->S[1] == 0)
9520       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 S=0");
9521 
9522     DPS8M_ (
9523       // DPS8 raises it delayed
9524       if (mod_fault)
9525         {
9526           doFault (FAULT_IPR,
9527                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9528                    "Illegal modifier");
9529         }
9530     )
9531 
9532     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
9533 
9534     if (e->N1 == 0 || e->N1 > 8)
9535         doFault(FAULT_IPR, fst_ill_proc, "btd(1): N1 == 0 || N1 > 8");
9536 
9537     uint dstTN = e->TN2;    // type of chars in dst
9538     uint dstCN = e->CN2;    // starting at char pos CN
9539 
9540     int n2 = 0;
9541 
9542     switch(e->S2)
9543     {
9544         case CSLS:
9545         case CSTS:
9546             n2 = (int) e->N2 - 1; // 1 sign
9547             break;
9548 
9549         case CSNS:
9550             n2 = (int) e->N2;     // no sign
9551             break;          // no sign wysiwyg
9552     }
9553 
9554     sim_debug (DBG_CAC, & cpu_dev,
9555       "n2 %d\n",
9556       n2);
9557 
9558     if (n2 < 1)
9559         doFault (FAULT_IPR, fst_ill_proc, "btd adjusted n2<1");
9560 
9561     decContext set;
9562     decContextDefaultDPS8(&set);
9563     set.traps=0;
9564 
9565     load9x((int) e->N1, &e->ADDR1, (int) e->CN1);
9566 
9567     // handle sign
9568     e->sign = 1;
9569 #ifdef NEED_128
9570     word72 x = cast_128 (e->x);
9571     if (islt_s128 (e->x, construct_s128 (0, 0)))
9572       {
9573         e->sign = -1;
9574         x = and_128 (negate_128 (x), MASK72);
9575 
9576       }
9577 
9578     // convert to decimal string, workaround missing sprintf uint128
9579     char tmp[32];
9580     tmp[31] = 0;
9581     int i;
9582     for (i=30;i>=0;i--) {
9583         //tmp[i] = x%10 + '0';
9584         //x /= 10;
9585         uint16_t r;
9586         x = divide_128_16 (x, 10, & r);
9587         tmp[i] = (char) r + '0';
9588         if (iszero_128 (x))
9589             break;
9590     }
9591 #else
9592     word72 x = (word72)e->x;
9593     if (e->x < 0) {
9594         e->sign = -1;
9595         //x = (-x) & MASK72;
9596         // ubsan
9597         x = ((word72) (- (word72s) x)) & MASK72;
9598     }
9599 
9600     // convert to decimal string, workaround missing sprintf uint128
9601     char tmp[32];
9602     tmp[31] = 0;
9603     int i;
9604     for (i=30;i>=0;i--) {
9605         tmp[i] = x%10 + '0';
9606         x /= 10;
9607         if (x == 0)
9608             break;
9609     }
9610 #endif
9611 
9612     decNumber _1;
9613     decNumber *op1 = decNumberFromString(&_1, tmp+i, &set);
9614     if (e->sign == -1)
9615         op1->bits |= DECNEG;
9616 
9617     bool Ovr = false, Trunc = false;
9618 
9619     uint8_t out [256];
9620     char * res = formatDecimal (out, &set, op1, n2, (int) e->S2, e->SF2, 0, &Ovr, &Trunc);
9621 
9622     // now write to memory in proper format.....
9623 
9624     //word18 dstAddr = e->dstAddr;
9625     int pos = (int) dstCN;
9626 
9627     // 1st, take care of any leading sign .......
9628     switch(e->S2)
9629     {
9630         case CSLS:  // fixed-point, leading sign
9631             switch(dstTN)
9632             {
9633                 case CTN4:
9634                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
9635                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 013);  // special +
9636                     else
9637                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 014);  // default +
9638                     break;
9639                 case CTN9:
9640                     EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9641                     break;
9642             }
9643             break;
9644 
9645         case CSTS:  // nuttin' to do here .....
9646         case CSNS:
9647             break;  // no sign wysiwyg
9648     }
9649 
9650     // 2nd, write the digits .....
9651     for(int i = 0 ; i < n2 ; i++)
9652         switch(dstTN)
9653         {
9654             case CTN4:
9655                 EISwrite49(&e->ADDR2, &pos, (int) dstTN, (word9) (res[i] - '0'));
9656                 break;
9657             case CTN9:
9658                 EISwrite49(&e->ADDR2, &pos, (int) dstTN, (word9) res[i]);
9659                 break;
9660         }
9661 
9662     // 3rd, take care of any trailing sign or exponent ...
9663     switch(e->S2)
9664     {
9665         case CSTS:  // write trailing sign ....
9666             switch(dstTN)
9667             {
9668                 case CTN4:
9669                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
9670                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  013);  // special +
9671                     else
9672                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  014);  // default +
9673                     break;
9674 
9675                 case CTN9:
9676                     EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9677                     break;
9678             }
9679             break;
9680 
9681         case CSLS:  // fixed point, leading sign - already done
9682         case CSNS:  // fixed point, unsigned - nuttin' needed to do
9683             break;
9684     }
9685 
9686     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));  // set negative indicator if op3 < 0
9687     SC_I_ZERO (decNumberIsZero(op1));     // set zero indicator if op3 == 0
9688 
9689     cleanupOperandDescriptor (1);
9690     cleanupOperandDescriptor (2);
9691 
9692     if (Ovr)
9693     {
9694         SET_I_OFLOW;
9695         if (tstOVFfault ())
9696           doFault(FAULT_OFL, fst_zero, "btd overflow fault");
9697     }
9698 }
9699 
9700 
9701 
9702 
9703 
9704 
9705 
9706 
9707 
9708 
9709 
9710 
9711 
9712 
9713 
9714 
9715 
9716 
9717 
9718 
9719 
9720 
9721 
9722 
9723 
9724 
9725 
9726 
9727 
9728 
9729 
9730 
9731 
9732 
9733 
9734 
9735 
9736 
9737 
9738 
9739 
9740 
9741 
9742 
9743 
9744 
9745 
9746 
9747 
9748 
9749 
9750 
9751 
9752 
9753 
9754 
9755 
9756 
9757 
9758 
9759 
9760 
9761 
9762 
9763 
9764 
9765 
9766 
9767 
9768 
9769 
9770 
9771 
9772 
9773 
9774 
9775 
9776 
9777 
9778 
9779 
9780 
9781 
9782 
9783 
9784 
9785 
9786 
9787 
9788 
9789 
9790 
9791 
9792 
9793 
9794 
9795 
9796 
9797 
9798 
9799 
9800 
9801 
9802 
9803 
9804 
9805 
9806 
9807 
9808 
9809 
9810 
9811 
9812 
9813 
9814 
9815 
9816 
9817 
9818 
9819 
9820 
9821 
9822 
9823 
9824 
9825 
9826 
9827 
9828 
9829 
9830 
9831 
9832 
9833 
9834 
9835 
9836 
9837 
9838 
9839 
9840 
9841 
9842 
9843 
9844 
9845 
9846 
9847 
9848 
9849 
9850 
9851 
9852 
9853 
9854 
9855 
9856 
9857 
9858 
9859 
9860 
9861 
9862 
9863 
9864 
9865 
9866 
9867 
9868 
9869 
9870 
9871 
9872 
9873 
9874 
9875 
9876 
9877 
9878 
9879 
9880 
9881 
9882 
9883 
9884 
9885 
9886 
9887 
9888 
9889 
9890 
9891 
9892 
9893 
9894 
9895 
9896 
9897 
9898 
9899 
9900 
9901 
9902 
9903 
9904 
9905 
9906 void dtb (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9907 {
9908     EISstruct * e = & cpu.currentEISinstruction;
9909 
9910     fault_ipr_subtype_ mod_fault = 0;
9911 
9912 #ifndef EIS_SETUP
9913     setupOperandDescriptor(1, &mod_fault);
9914     setupOperandDescriptor(2, &mod_fault);
9915 #endif
9916 
9917     PNL (L68_ (DU_CYCLE_DGDB;))
9918 
9919     parseNumericOperandDescriptor(1, &mod_fault);
9920     parseNumericOperandDescriptor(2, &mod_fault);
9921 
9922     L68_ (
9923       // L68 raises it immediately
9924       if (mod_fault)
9925         {
9926           doFault (FAULT_IPR,
9927                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9928                    "Illegal modifier");
9929         }
9930     )
9931 
9932     // Bits 0 to 10 of the instruction Must Be Zero. So Say We ISOLTS.
9933     uint mbz = (uint) getbits36 (IWB_IRODD, 0, 11);
9934     if (mbz)
9935       {
9936         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dtb(): 0-10 MBZ");
9937       }
9938 
9939     // Bits 24-29 of OP1 MBZ
9940     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
9941       {
9942         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op1 24-29 MBZ");
9943       }
9944 
9945     // Bits 21-29 of OP2 MBZ
9946     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000077700)
9947       {
9948         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op2 21-29 MBZ");
9949        }
9950 
9951     // Attempted conversion of a floating-point number (S1 = 0) or attempted
9952     // use of a scaling factor (SF1 ≠ 0) causes an illegal procedure fault.
9953     if (e->S1 == 0 || e->SF1 != 0)
9954     {
9955         doFault(FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb():  S1=0 or SF1!=0");
9956     }
9957 
9958     DPS8M_ (
9959       // DPS8M raises it delayed
9960       if (mod_fault)
9961         {
9962           doFault (FAULT_IPR,
9963                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9964                    "Illegal modifier");
9965         }
9966     )
9967 
9968     // If N2 = 0 or N2 > 8 an illegal procedure fault occurs.
9969     if (e->N2 == 0 || e->N2 > 8)
9970     {
9971         doFault(FAULT_IPR, fst_ill_proc, "dtb():  N2 = 0 or N2 > 8 etc.");
9972     }
9973 
9974     int n1 = 0;
9975 
9976     /*
9977      * Here we need to distinguish between 4 type of numbers.
9978      *
9979      * CSFL - Floating-point, leading sign
9980      * CSLS - Scaled fixed-point, leading sign
9981      * CSTS - Scaled fixed-point, trailing sign
9982      * CSNS - Scaled fixed-point, unsigned
9983      */
9984 
9985     // determine precision
9986     switch(e->S1)
9987     {
9988         case CSLS:
9989         case CSTS:
9990             n1 = (int) e->N1 - 1; // only 1 sign
9991             break;
9992 
9993         case CSNS:
9994             n1 = (int) e->N1;     // no sign
9995             break;  // no sign wysiwyg
9996     }
9997     // RJ78: An Illegal Procedure fault occurs if:
9998     // N1 is not large enough to specify the number of characters required for the
9999     // specified sign and/or exponent, plus at least one digit.
10000 
10001     if (n1 < 1)
10002         doFault (FAULT_IPR, fst_ill_proc, "dtb adjusted n1<1");
10003 
10004     EISloadInputBufferNumeric (1);   // according to MF1
10005 
10006     // prepare output mask
10007 #ifdef NEED_128
10008     word72 msk = subtract_128 (lshift_128 (construct_128 (0, 1), (9*e->N2-1)),construct_128 (0, 1));
10009 #else
10010     word72 msk = ((word72)1<<(9*e->N2-1))-1; // excluding sign
10011 #endif
10012 
10013 
10014 
10015 
10016 
10017 
10018 
10019 
10020 
10021 
10022 
10023 
10024 
10025     // input is unscaled fixed point, so just get the digits
10026     bool Ovr = false;
10027 #ifdef NEED_128
10028     word72 x = construct_128 (0, 0);
10029     for (int i = 0; i < n1; i++) {
10030         //x *= 10;
10031         x = multiply_128 (x, construct_128 (0, 10));
10032         //x += e->inBuffer[i];
10033         x = add_128 (x, construct_128 (0, (uint) e->inBuffer[i]));
10034         //Ovr |= x>msk?1:0;
10035         Ovr |= isgt_128 (x, msk) ? 1 : 0;
10036         //x &= msk; // multiplication and addition mod msk+1
10037         x = and_128 (x, msk); // multiplication and addition mod msk+1
10038     }
10039     if (e->sign == -1)
10040         //x = -x; // no need to mask it
10041         x = negate_128 (x); // no need to mask it
10042 
10043 #else
10044     word72 x = 0;
10045     for (int i = 0; i < n1; i++) {
10046         x *= 10;
10047         x += e->inBuffer[i];
10048         //sim_printf("%d %012"PRIo64" %012"PRIo64"\n",e->inBuffer[i],(word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10049         Ovr |= x>msk?1:0;
10050         x &= msk; // multiplication and addition mod msk+1
10051     }
10052     if (e->sign == -1)
10053         //x = -x; // no need to mask it
10054         // ubsan
10055         x = (word72) (- (word72s) x); // no need to mask it
10056 
10057     //sim_printf ("dtb out %012"PRIo64" %012"PRIo64"\n", (word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10058 #endif
10059     int pos = (int)e->CN2;
10060 
10061     // now write to memory in proper format.....
10062 
10063     int shift = 9*((int)e->N2-1);
10064     for(int i = 0; i < (int)e->N2; i++) {
10065 #ifdef NEED_128
10066         EISwrite9(&e->ADDR2, &pos, (word9) rshift_128 (x, (uint) shift).l & 0777);
10067 #else
10068         EISwrite9(&e->ADDR2, &pos, (word9) (x >> shift )& 0777);
10069 #endif
10070         shift -= 9;
10071     }
10072 
10073     SC_I_NEG (e->sign == -1);  // set negative indicator
10074 #ifdef NEED_128
10075     SC_I_ZERO (iszero_128 (x)); // set zero indicator
10076 #else
10077     SC_I_ZERO (x==0);     // set zero indicator
10078 #endif
10079 
10080     cleanupOperandDescriptor (1);
10081     cleanupOperandDescriptor (2);
10082 
10083     if (Ovr)
10084     {
10085         SET_I_OFLOW;
10086         if (tstOVFfault ())
10087           doFault(FAULT_OFL, fst_zero, "dtb overflow fault");
10088     }
10089 }
10090 
10091 /*
10092  * decimal EIS instructions ...
10093  */
10094 
10095 #define ASC(x)  ((x) + '0')
10096 
10097 /*
10098  * ad2d - Add Using Two Decimal Operands
10099  */
10100 
10101 void ad2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
10102 {
10103     EISstruct * e = & cpu.currentEISinstruction;
10104 
10105     fault_ipr_subtype_ mod_fault = 0;
10106 
10107 #ifndef EIS_SETUP
10108     setupOperandDescriptor(1, &mod_fault);
10109     setupOperandDescriptor(2, &mod_fault);
10110     setupOperandDescriptorCache(3);
10111 #endif
10112 
10113     parseNumericOperandDescriptor(1, &mod_fault);
10114     parseNumericOperandDescriptor(2, &mod_fault);
10115 
10116     L68_ (
10117       // L68 raises it immediately
10118       if (mod_fault)
10119         {
10120           doFault (FAULT_IPR,
10121                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10122                    "Illegal modifier");
10123         }
10124     )
10125 
10126     // Bits 1-8 MBZ
10127     if (IWB_IRODD & 0377000000000)
10128       doFault (FAULT_IPR, fst_ill_op, "ad2d 1-8 MBZ");
10129 
10130     DPS8M_ (
10131       // DPS8M raises it delayed
10132       if (mod_fault)
10133         {
10134           doFault (FAULT_IPR,
10135                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10136                    "Illegal modifier");
10137         }
10138     )
10139 
10140     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10141     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10142     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10143 
10144     PNL (L68_ (if (R)
10145       DU_CYCLE_FRND;))
10146 
10147     uint srcTN = e->TN1;    // type of chars in src
10148 
10149     uint dstTN = e->TN2;    // type of chars in dst
10150     uint dstCN = e->CN2;    // starting at char pos CN
10151 
10152     e->ADDR3 = e->ADDR2;
10153 
10154     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10155 
10156     /*
10157      * Here we need to distinguish between 4 type of numbers.
10158      *
10159      * CSFL - Floating-point, leading sign
10160      * CSLS - Scaled fixed-point, leading sign
10161      * CSTS - Scaled fixed-point, trailing sign
10162      * CSNS - Scaled fixed-point, unsigned
10163      */
10164 
10165     // determine precision
10166     switch(e->S1)
10167     {
10168         case CSFL:
10169             n1 = (int) e->N1 - 1; // need to account for the - sign
10170             if (srcTN == CTN4)
10171                 n1 -= 2;    // 2 4-bit digits exponent
10172             else
10173                 n1 -= 1;    // 1 9-bit digit exponent
10174             sc1 = 0;        // no scaling factor
10175             break;
10176 
10177         case CSLS:
10178         case CSTS:
10179             n1 = (int) e->N1 - 1; // only 1 sign
10180             sc1 = -e->SF1;
10181             break;
10182 
10183         case CSNS:
10184             n1 = (int) e->N1;     // no sign
10185             sc1 = -e->SF1;
10186             break;  // no sign wysiwyg
10187     }
10188 
10189     if (n1 < 1)
10190         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n1<1");
10191 
10192     switch(e->S2)
10193     {
10194         case CSFL:
10195             n2 = (int) e->N2 - 1; // need to account for the sign
10196             if (e->TN2 == CTN4)
10197                 n2 -= 2;    // 2 4-bit digit exponent
10198             else
10199                 n2 -= 1;    // 1 9-bit digit exponent
10200             sc2 = 0;        // no scaling factor
10201             break;
10202 
10203         case CSLS:
10204         case CSTS:
10205             n2 = (int) e->N2 - 1; // 1 sign
10206             sc2 = -e->SF2;
10207             break;
10208 
10209         case CSNS:
10210             n2 = (int) e->N2;     // no sign
10211             sc2 = -e->SF2;
10212             break;  // no sign wysiwyg
10213     }
10214 
10215     if (n2 < 1)
10216         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n2<1");
10217 
10218     decContext set;
10219     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10220     decContextDefaultDPS8(&set);
10221 
10222     set.traps=0;
10223 
10224     decNumber _1, _2, _3;
10225 
10226     EISloadInputBufferNumeric (1);   // according to MF1
10227 
10228     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10229     if (e->sign == -1)
10230         op1->bits |= DECNEG;
10231     if (e->S1 == CSFL)
10232         op1->exponent = e->exponent;
10233 
10234     EISloadInputBufferNumeric (2);   // according to MF2
10235 
10236     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10237     if (e->sign == -1)
10238         op2->bits |= DECNEG;
10239     if (e->S2 == CSFL)
10240         op2->exponent = e->exponent;
10241 
10242     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10243 
10244     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
10245     bool iOvr = 0;
10246     if (op3->digits > 63) {
10247         uint8_t pr[256];
10248         // if sf<=0, trailing zeroes can't be shifted out
10249         // if sf> 0, (some of) trailing zeroes can be shifted out
10250         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10251 
10252         int ctz = 0;
10253         if (sf>0) {     // optimize: we don't care when sf>0
10254             decNumberGetBCD(op3,pr);
10255             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10256                  ctz ++;
10257         }
10258 
10259         if (op3->digits - min(max(sf,0),ctz) > 63) {
10260 
10261             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10262             int safe = set.digits;
10263             decNumber tmp;
10264 
10265             // discard MS digits
10266             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10267             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10268             decNumberPlus(&tmp, op3, &set);
10269             set.digits = safe;
10270 
10271             decNumberSubtract(op3, op3, &tmp, &set);
10272 
10273             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10274 
10275             decContextSetRounding(&set, safeR);
10276             iOvr = 1;
10277         }
10278     }
10279 
10280     bool Ovr = false, EOvr = false, Trunc = false;
10281 
10282     uint8_t out [256];
10283     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
10284 
10285     Ovr |= iOvr;
10286 
10287     if (decNumberIsZero(op3))
10288         op3->exponent = 127;
10289 
10290     //printf("%s\r\n", res);
10291 
10292     // now write to memory in proper format.....
10293 
10294     //word18 dstAddr = e->dstAddr;
10295     int pos = (int) dstCN;
10296 
10297     // 1st, take care of any leading sign .......
10298     switch(e->S2)
10299     {
10300         case CSFL:  // floating-point, leading sign.
10301         case CSLS:  // fixed-point, leading sign
10302             switch(dstTN)
10303             {
10304                 case CTN4:
10305                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
10306                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10307                     else
10308                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10309                     break;
10310                 case CTN9:
10311                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10312                     break;
10313             }
10314             break;
10315 
10316         case CSTS:  // nuttin' to do here .....
10317         case CSNS:
10318             break;  // no sign wysiwyg
10319     }
10320 
10321     // 2nd, write the digits .....
10322     for(int j = 0 ; j < n2 ; j++)
10323         switch(dstTN)
10324         {
10325             case CTN4:
10326                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[j] - '0'));
10327                 break;
10328             case CTN9:
10329                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[j]);
10330                 break;
10331         }
10332 
10333     // 3rd, take care of any trailing sign or exponent ...
10334     switch(e->S2)
10335     {
10336         case CSTS:  // write trailing sign ....
10337             switch(dstTN)
10338             {
10339                 case CTN4:
10340                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
10341                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10342                     else
10343                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10344                     break;
10345                 case CTN9:
10346                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10347                     break;
10348             }
10349             break;
10350 
10351         case CSFL:  // floating-point, leading sign.
10352             // write the exponent
10353             switch(dstTN)
10354             {
10355                 case CTN4:
10356                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10357                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10358                     break;
10359                 case CTN9:
10360                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10361                     break;
10362             }
10363             break;
10364 
10365         case CSLS:  // fixed point, leading sign - already done
10366         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10367             break;
10368     }
10369 
10370     // set flags, etc ...
10371     if (e->S2 == CSFL)
10372     {
10373         if (op3->exponent > 127)
10374         {
10375             SET_I_EOFL;
10376             EOvr = true;
10377         }
10378         if (op3->exponent < -128)
10379         {
10380             SET_I_EUFL;
10381             EOvr = true;
10382         }
10383     }
10384 
10385     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10386     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10387 
10388     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10389 
10390     cleanupOperandDescriptor (1);
10391     cleanupOperandDescriptor (2);
10392     cleanupOperandDescriptor (3);
10393 
10394     if (TST_I_TRUNC && T && tstOVFfault ())
10395       doFault(FAULT_OFL, fst_zero, "ad2d truncation(overflow) fault");
10396     if (EOvr && tstOVFfault ())
10397         doFault(FAULT_OFL, fst_zero, "ad2d over/underflow fault");
10398     if (Ovr)
10399     {
10400         SET_I_OFLOW;
10401         if (tstOVFfault ())
10402           doFault(FAULT_OFL, fst_zero, "ad2d overflow fault");
10403     }
10404 }
10405 
10406 
10407 
10408 
10409 
10410 
10411 
10412 
10413 
10414 
10415 
10416 
10417 
10418 
10419 
10420 
10421 
10422 
10423 
10424 
10425 
10426 
10427 
10428 
10429 
10430 
10431 
10432 
10433 
10434 
10435 
10436 
10437 
10438 
10439 
10440 
10441 
10442 
10443 
10444 
10445 
10446 /*
10447  * ad3d - Add Using Three Decimal Operands
10448  */
10449 
10450 void ad3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
10451 {
10452     EISstruct * e = & cpu.currentEISinstruction;
10453 
10454     fault_ipr_subtype_ mod_fault = 0;
10455 
10456 #ifndef EIS_SETUP
10457     setupOperandDescriptor(1, &mod_fault);
10458     setupOperandDescriptor(2, &mod_fault);
10459     setupOperandDescriptor(3, &mod_fault);
10460 #endif
10461 
10462     parseNumericOperandDescriptor(1, &mod_fault);
10463     parseNumericOperandDescriptor(2, &mod_fault);
10464     parseNumericOperandDescriptor(3, &mod_fault);
10465 
10466     L68_ (
10467       // L68 raises it immediately
10468       if (mod_fault)
10469         {
10470           doFault (FAULT_IPR,
10471                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10472                    "Illegal modifier");
10473         }
10474     )
10475 
10476     // Bit 1 MBZ
10477     if (IWB_IRODD & 0200000000000)
10478       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "ad3d(): 1 MBZ");
10479 
10480     DPS8M_ (
10481       // DPS8M raises it delayed
10482       if (mod_fault)
10483         {
10484           doFault (FAULT_IPR,
10485                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10486                    "Illegal modifier");
10487         }
10488     )
10489 
10490     // initialize mop flags. Probably best done elsewhere.
10491     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10492     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10493     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10494 
10495     PNL (L68_ (if (R)
10496       DU_CYCLE_FRND;))
10497 
10498     uint srcTN = e->TN1;    // type of chars in src
10499 
10500     uint dstTN = e->TN3;    // type of chars in dst
10501     uint dstCN = e->CN3;    // starting at char pos CN
10502 
10503     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
10504 
10505     /*
10506      * Here we need to distinguish between 4 type of numbers.
10507      *
10508      * CSFL - Floating-point, leading sign
10509      * CSLS - Scaled fixed-point, leading sign
10510      * CSTS - Scaled fixed-point, trailing sign
10511      * CSNS - Scaled fixed-point, unsigned
10512      */
10513 
10514     // determine precision
10515     switch(e->S1)
10516     {
10517         case CSFL:
10518             n1 = (int) e->N1 - 1; // need to account for the - sign
10519             if (srcTN == CTN4)
10520                 n1 -= 2;    // 2 4-bit digits exponent
10521             else
10522                 n1 -= 1;    // 1 9-bit digit exponent
10523             sc1 = 0;        // no scaling factor
10524             break;
10525 
10526         case CSLS:
10527         case CSTS:
10528             n1 = (int) e->N1 - 1; // only 1 sign
10529             sc1 = -e->SF1;
10530             break;
10531 
10532         case CSNS:
10533             n1 = (int) e->N1;     // no sign
10534             sc1 = -e->SF1;
10535             break;  // no sign wysiwyg
10536     }
10537 
10538     if (n1 < 1)
10539         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n1<1");
10540 
10541     switch(e->S2)
10542     {
10543         case CSFL:
10544             n2 = (int) e->N2 - 1; // need to account for the sign
10545             if (e->TN2 == CTN4)
10546                 n2 -= 2;    // 2 4-bit digit exponent
10547             else
10548                 n2 -= 1;    // 1 9-bit digit exponent
10549             sc2 = 0;        // no scaling factor
10550             break;
10551 
10552         case CSLS:
10553         case CSTS:
10554             n2 = (int) e->N2 - 1; // 1 sign
10555             sc2 = -e->SF2;
10556             break;
10557 
10558         case CSNS:
10559             n2 = (int) e->N2;     // no sign
10560             sc2 = -e->SF2;
10561             break;  // no sign wysiwyg
10562     }
10563 
10564     if (n2 < 1)
10565         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n2<1");
10566 
10567     switch(e->S3)
10568     {
10569         case CSFL:
10570             n3 = (int) e->N3 - 1; // need to account for the sign
10571             if (dstTN == CTN4)
10572                 n3 -= 2;    // 2 4-bit digit exponent
10573             else
10574                 n3 -= 1;    // 1 9-bit digit exponent
10575             break;
10576 
10577         case CSLS:
10578         case CSTS:
10579             n3 = (int) e->N3 - 1; // 1 sign
10580             break;
10581 
10582         case CSNS:
10583             n3 = (int) e->N3;     // no sign
10584             break;  // no sign wysiwyg
10585     }
10586 
10587     if (n3 < 1)
10588         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n3<1");
10589 
10590     decContext set;
10591     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10592     decContextDefaultDPS8(&set);
10593     set.traps=0;
10594 
10595     decNumber _1, _2, _3;
10596 
10597     EISloadInputBufferNumeric (1);   // according to MF1
10598 
10599     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10600     if (e->sign == -1)
10601         op1->bits |= DECNEG;
10602     if (e->S1 == CSFL)
10603         op1->exponent = e->exponent;
10604 
10605     EISloadInputBufferNumeric (2);   // according to MF2
10606 
10607     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10608     if (e->sign == -1)
10609         op2->bits |= DECNEG;
10610     if (e->S2 == CSFL)
10611         op2->exponent = e->exponent;
10612 
10613     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10614 
10615     // RJ78: significant digits in the result may be lost if:
10616     // The difference between the scaling factors (exponents) of the source
10617     // operands is large enough to cause the expected length of the intermediate
10618     // result to exceed 63 digits after decimal point alignment of source operands, followed by addition.
10619     // ISOLTS 846 07c, 10a, 11b internal register overflow
10620     // trailing zeros are not counted towards the limit
10621 
10622     // XXX it is not clear which digits are lost, but I suppose it should be the most significant.
10623     // ISOLTS doesn't check for this.
10624 
10625     // XXX the algorithm should be similar/the same as dv3d NQ? It is to some extent already...
10626     bool iOvr = 0;
10627     if (op3->digits > 63) {
10628         uint8_t pr[256];
10629         // if sf<=0, trailing zeroes can't be shifted out
10630         // if sf> 0, (some of) trailing zeroes can be shifted out
10631         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10632 
10633         int ctz = 0;
10634         if (sf>0) {     // optimize: we don't care when sf>0
10635             decNumberGetBCD(op3,pr);
10636             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10637                  ctz ++;
10638         }
10639 
10640         if (op3->digits - min(max(sf,0),ctz) > 63) {
10641 
10642             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10643             int safe = set.digits;
10644             decNumber tmp;
10645 
10646             // discard MS digits
10647             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10648             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10649             decNumberPlus(&tmp, op3, &set);
10650             set.digits = safe;
10651 
10652             decNumberSubtract(op3, op3, &tmp, &set);
10653 
10654             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10655 
10656             decContextSetRounding(&set, safeR);
10657             iOvr = 1;
10658         }
10659     }
10660 
10661     bool Ovr = false, EOvr = false, Trunc = false;
10662 
10663     uint8_t out [256];
10664     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
10665 
10666     Ovr |= iOvr;
10667 
10668     if (decNumberIsZero(op3))
10669         op3->exponent = 127;
10670 
10671     //printf("%s\r\n", res);
10672 
10673     // now write to memory in proper format.....
10674 
10675     //word18 dstAddr = e->dstAddr;
10676     int pos = (int) dstCN;
10677 
10678     // 1st, take care of any leading sign .......
10679     switch(e->S3)
10680     {
10681         case CSFL:  // floating-point, leading sign.
10682         case CSLS:  // fixed-point, leading sign
10683             switch(dstTN)
10684             {
10685             case CTN4:
10686                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
10687                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10688                 else
10689                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10690                 break;
10691             case CTN9:
10692                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10693                 break;
10694             }
10695             break;
10696 
10697         case CSTS:  // nuttin' to do here .....
10698         case CSNS:
10699             break;  // no sign wysiwyg
10700     }
10701 
10702     // 2nd, write the digits .....
10703     for(int i = 0 ; i < n3 ; i++)
10704         switch(dstTN)
10705         {
10706         case CTN4:
10707             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
10708             break;
10709         case CTN9:
10710             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
10711             break;
10712         }
10713 
10714     // 3rd, take care of any trailing sign or exponent ...
10715     switch(e->S3)
10716     {
10717         case CSTS:  // write trailing sign ....
10718             switch(dstTN)
10719             {
10720             case CTN4:
10721                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
10722                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10723                 else
10724                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10725                 break;
10726             case CTN9:
10727                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10728                 break;
10729             }
10730             break;
10731 
10732         case CSFL:  // floating-point, leading sign.
10733             // write the exponent
10734             switch(dstTN)
10735             {
10736             case CTN4:
10737                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10738                 EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10739 
10740                     break;
10741             case CTN9:
10742                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10743                 break;
10744             }
10745             break;
10746 
10747         case CSLS:  // fixed point, leading sign - already done
10748         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10749             break;
10750     }
10751 
10752     // set flags, etc ...
10753     if (e->S3 == CSFL)
10754     {
10755         if (op3->exponent > 127)
10756         {
10757             SET_I_EOFL;
10758             EOvr = true;
10759         }
10760         if (op3->exponent < -128)
10761         {
10762             SET_I_EUFL;
10763             EOvr = true;
10764         }
10765     }
10766 
10767     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10768     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10769 
10770     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10771 
10772     cleanupOperandDescriptor (1);
10773     cleanupOperandDescriptor (2);
10774     cleanupOperandDescriptor (3);
10775 
10776     if (TST_I_TRUNC && T && tstOVFfault ())
10777       doFault(FAULT_OFL, fst_zero, "ad3d truncation(overflow) fault");
10778     if (EOvr && tstOVFfault ())
10779         doFault(FAULT_OFL, fst_zero, "ad3d over/underflow fault");
10780     if (Ovr)
10781     {
10782         SET_I_OFLOW;
10783         if (tstOVFfault ())
10784           doFault(FAULT_OFL, fst_zero, "ad3d overflow fault");
10785     }
10786 }
10787 
10788 /*
10789  * sb2d - Subtract Using Two Decimal Operands
10790  */
10791 
10792 void sb2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
10793 {
10794     EISstruct * e = & cpu.currentEISinstruction;
10795 
10796     fault_ipr_subtype_ mod_fault = 0;
10797 
10798 #ifndef EIS_SETUP
10799     setupOperandDescriptor(1, &mod_fault);
10800     setupOperandDescriptor(2, &mod_fault);
10801     setupOperandDescriptorCache(3);
10802 #endif
10803 
10804     parseNumericOperandDescriptor(1, &mod_fault);
10805     parseNumericOperandDescriptor(2, &mod_fault);
10806 
10807     L68_ (
10808       // L68 raises it immediately
10809       if (mod_fault)
10810         {
10811           doFault (FAULT_IPR,
10812                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10813                    "Illegal modifier");
10814         }
10815     )
10816 
10817     // Bits 1-8 MBZ
10818     if (IWB_IRODD & 0377000000000)
10819       {
10820         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
10821         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb2d 0-8 MBZ");
10822       }
10823 
10824     DPS8M_ (
10825       // DPS8M raises it delayed
10826       if (mod_fault)
10827         {
10828           doFault (FAULT_IPR,
10829                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10830                    "Illegal modifier");
10831         }
10832     )
10833 
10834     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10835     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10836     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10837 
10838     PNL (L68_ (if (R)
10839       DU_CYCLE_FRND;))
10840 
10841     uint srcTN = e->TN1;    // type of chars in src
10842 
10843     uint dstTN = e->TN2;    // type of chars in dst
10844     uint dstCN = e->CN2;    // starting at char pos CN
10845 
10846     e->ADDR3 = e->ADDR2;
10847 
10848     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10849 
10850     /*
10851      * Here we need to distinguish between 4 type of numbers.
10852      *
10853      * CSFL - Floating-point, leading sign
10854      * CSLS - Scaled fixed-point, leading sign
10855      * CSTS - Scaled fixed-point, trailing sign
10856      * CSNS - Scaled fixed-point, unsigned
10857      */
10858 
10859     // determine precision
10860     switch(e->S1)
10861     {
10862         case CSFL:
10863             n1 = (int) e->N1 - 1; // need to account for the - sign
10864             if (srcTN == CTN4)
10865                 n1 -= 2;    // 2 4-bit digits exponent
10866             else
10867                 n1 -= 1;    // 1 9-bit digit exponent
10868             sc1 = 0;        // no scaling factor
10869             break;
10870 
10871         case CSLS:
10872         case CSTS:
10873             n1 = (int) e->N1 - 1; // only 1 sign
10874             sc1 = -e->SF1;
10875             break;
10876 
10877         case CSNS:
10878             n1 = (int) e->N1;     // no sign
10879             sc1 = -e->SF1;
10880             break;  // no sign wysiwyg
10881     }
10882 
10883     if (n1 < 1)
10884         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n1<1");
10885 
10886     switch(e->S2)
10887     {
10888         case CSFL:
10889             n2 = (int) e->N2 - 1; // need to account for the sign
10890             if (e->TN2 == CTN4)
10891                 n2 -= 2;    // 2 4-bit digit exponent
10892             else
10893                 n2 -= 1;    // 1 9-bit digit exponent
10894             sc2 = 0;        // no scaling factor
10895             break;
10896 
10897         case CSLS:
10898         case CSTS:
10899             n2 = (int) e->N2 - 1; // 1 sign
10900             sc2 = -e->SF2;
10901             break;
10902 
10903         case CSNS:
10904             n2 = (int) e->N2;     // no sign
10905             sc2 = -e->SF2;
10906             break;  // no sign wysiwyg
10907     }
10908 
10909     if (n2 < 1)
10910         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n2<1");
10911 
10912     decContext set;
10913     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10914     decContextDefaultDPS8(&set);
10915     set.traps=0;
10916 
10917     decNumber _1, _2, _3;
10918 
10919     EISloadInputBufferNumeric (1);   // according to MF1
10920 
10921     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10922     if (e->sign == -1)
10923         op1->bits |= DECNEG;
10924     if (e->S1 == CSFL)
10925         op1->exponent = e->exponent;
10926 
10927     EISloadInputBufferNumeric (2);   // according to MF2
10928 
10929     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10930     if (e->sign == -1)
10931         op2->bits |= DECNEG;
10932     if (e->S2 == CSFL)
10933         op2->exponent = e->exponent;
10934 
10935     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
10936 
10937     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
10938     bool iOvr = 0;
10939     if (op3->digits > 63) {
10940         uint8_t pr[256];
10941         // if sf<=0, trailing zeroes can't be shifted out
10942         // if sf> 0, (some of) trailing zeroes can be shifted out
10943         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10944 
10945         int ctz = 0;
10946         if (sf>0) {     // optimize: we don't care when sf>0
10947             decNumberGetBCD(op3,pr);
10948             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10949                  ctz ++;
10950         }
10951 
10952         if (op3->digits - min(max(sf,0),ctz) > 63) {
10953 
10954             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10955             int safe = set.digits;
10956             decNumber tmp;
10957 
10958             // discard MS digits
10959             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10960             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10961             decNumberPlus(&tmp, op3, &set);
10962             set.digits = safe;
10963 
10964             decNumberSubtract(op3, op3, &tmp, &set);
10965 
10966             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10967 
10968             decContextSetRounding(&set, safeR);
10969             iOvr = 1;
10970         }
10971     }
10972 
10973     bool Ovr = false, EOvr = false, Trunc = false;
10974 
10975     uint8_t out [256];
10976     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
10977 
10978     Ovr |= iOvr;
10979 
10980     if (decNumberIsZero(op3))
10981         op3->exponent = 127;
10982 
10983     //printf("%s\r\n", res);
10984 
10985     // now write to memory in proper format.....
10986 
10987     //word18 dstAddr = e->dstAddr;
10988     int pos = (int) dstCN;
10989 
10990     // 1st, take care of any leading sign .......
10991     switch(e->S2)
10992     {
10993         case CSFL:  // floating-point, leading sign.
10994         case CSLS:  // fixed-point, leading sign
10995             switch(dstTN)
10996             {
10997                 case CTN4:
10998                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
10999                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11000                     else
11001                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11002                     break;
11003                 case CTN9:
11004                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11005                     break;
11006             }
11007             break;
11008 
11009         case CSTS:  // nuttin' to do here .....
11010         case CSNS:
11011             break;  // no sign wysiwyg
11012     }
11013 
11014     // 2nd, write the digits .....
11015     for(int i = 0 ; i < n2 ; i++)
11016         switch(dstTN)
11017         {
11018             case CTN4:
11019                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11020                 break;
11021             case CTN9:
11022                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11023                 break;
11024         }
11025 
11026     // 3rd, take care of any trailing sign or exponent ...
11027     switch(e->S2)
11028     {
11029         case CSTS:  // write trailing sign ....
11030             switch(dstTN)
11031             {
11032                 case CTN4:
11033                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
11034                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11035                     else
11036                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11037                     break;
11038                 case CTN9:
11039                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11040                     break;
11041             }
11042             break;
11043 
11044         case CSFL:  // floating-point, leading sign.
11045             // write the exponent
11046             switch(dstTN)
11047             {
11048                 case CTN4:
11049                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11050                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11051 
11052                     break;
11053                 case CTN9:
11054                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11055                     break;
11056             }
11057             break;
11058 
11059         case CSLS:  // fixed point, leading sign - already done
11060         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11061             break;
11062     }
11063 
11064     // set flags, etc ...
11065     if (e->S2 == CSFL)
11066     {
11067         if (op3->exponent > 127)
11068         {
11069             SET_I_EOFL;
11070             EOvr = true;
11071         }
11072         if (op3->exponent < -128)
11073         {
11074             SET_I_EUFL;
11075             EOvr = true;
11076         }
11077     }
11078 
11079     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11080     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11081 
11082     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11083 
11084     cleanupOperandDescriptor (1);
11085     cleanupOperandDescriptor (2);
11086     cleanupOperandDescriptor (3);
11087 
11088     if (TST_I_TRUNC && T && tstOVFfault ())
11089       doFault(FAULT_OFL, fst_zero, "sb2d truncation(overflow) fault");
11090     if (EOvr && tstOVFfault ())
11091         doFault(FAULT_OFL, fst_zero, "sb2d over/underflow fault");
11092     if (Ovr)
11093     {
11094         SET_I_OFLOW;
11095         if (tstOVFfault ())
11096           doFault(FAULT_OFL, fst_zero, "sb2d overflow fault");
11097     }
11098 }
11099 
11100 /*
11101  * sb3d - Subtract Using Three Decimal Operands
11102  */
11103 
11104 void sb3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
11105 {
11106     EISstruct * e = & cpu.currentEISinstruction;
11107 
11108     fault_ipr_subtype_ mod_fault = 0;
11109 
11110 #ifndef EIS_SETUP
11111     setupOperandDescriptor(1, &mod_fault);
11112     setupOperandDescriptor(2, &mod_fault);
11113     setupOperandDescriptor(3, &mod_fault);
11114 #endif
11115 
11116     parseNumericOperandDescriptor(1, &mod_fault);
11117     parseNumericOperandDescriptor(2, &mod_fault);
11118     parseNumericOperandDescriptor(3, &mod_fault);
11119 
11120     L68_ (
11121       // L68 raises it immediately
11122       if (mod_fault)
11123         {
11124           doFault (FAULT_IPR,
11125                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11126                    "Illegal modifier");
11127         }
11128     )
11129 
11130     // Bit 1 MBZ
11131     if (IWB_IRODD & 0200000000000)
11132       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb3d(): 1 MBZ");
11133 
11134     DPS8M_ (
11135       // DPS8M raises it delayed
11136       if (mod_fault)
11137         {
11138           doFault (FAULT_IPR,
11139                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11140                    "Illegal modifier");
11141         }
11142     )
11143 
11144     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11145     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11146     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11147 
11148     PNL (L68_ (if (R)
11149       DU_CYCLE_FRND;))
11150 
11151     uint srcTN = e->TN1;    // type of chars in src
11152 
11153     uint dstTN = e->TN3;    // type of chars in dst
11154     uint dstCN = e->CN3;    // starting at char pos CN
11155 
11156     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11157 
11158     /*
11159      * Here we need to distinguish between 4 type of numbers.
11160      *
11161      * CSFL - Floating-point, leading sign
11162      * CSLS - Scaled fixed-point, leading sign
11163      * CSTS - Scaled fixed-point, trailing sign
11164      * CSNS - Scaled fixed-point, unsigned
11165      */
11166 
11167     // determine precision
11168     switch(e->S1)
11169     {
11170         case CSFL:
11171             n1 = (int) e->N1 - 1; // need to account for the - sign
11172             if (srcTN == CTN4)
11173                 n1 -= 2;    // 2 4-bit digits exponent
11174             else
11175                 n1 -= 1;    // 1 9-bit digit exponent
11176             sc1 = 0;        // no scaling factor
11177             break;
11178 
11179         case CSLS:
11180         case CSTS:
11181             n1 = (int) e->N1 - 1; // only 1 sign
11182             sc1 = -e->SF1;
11183             break;
11184 
11185         case CSNS:
11186             n1 = (int) e->N1;     // no sign
11187             sc1 = -e->SF1;
11188             break;  // no sign wysiwyg
11189     }
11190 
11191     if (n1 < 1)
11192         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n1<1");
11193 
11194     switch(e->S2)
11195     {
11196         case CSFL:
11197             n2 = (int) e->N2 - 1; // need to account for the sign
11198             if (e->TN2 == CTN4)
11199                 n2 -= 2;    // 2 4-bit digit exponent
11200             else
11201                 n2 -= 1;    // 1 9-bit digit exponent
11202             sc2 = 0;        // no scaling factor
11203             break;
11204 
11205         case CSLS:
11206         case CSTS:
11207             n2 = (int) e->N2 - 1; // 1 sign
11208             sc2 = -e->SF2;
11209             break;
11210 
11211         case CSNS:
11212             n2 = (int) e->N2;     // no sign
11213             sc2 = -e->SF2;
11214             break;  // no sign wysiwyg
11215     }
11216 
11217     if (n2 < 1)
11218         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n2<1");
11219 
11220     switch(e->S3)
11221     {
11222         case CSFL:
11223             n3 = (int) e->N3 - 1; // need to account for the sign
11224             if (dstTN == CTN4)
11225                 n3 -= 2;    // 2 4-bit digit exponent
11226             else
11227                 n3 -= 1;    // 1 9-bit digit exponent
11228             break;
11229 
11230         case CSLS:
11231         case CSTS:
11232             n3 = (int) e->N3 - 1; // 1 sign
11233             break;
11234 
11235         case CSNS:
11236             n3 = (int) e->N3;     // no sign
11237             break;  // no sign wysiwyg
11238     }
11239 
11240     if (n3 < 1)
11241         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n3<1");
11242 
11243     decContext set;
11244     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11245     decContextDefaultDPS8(&set);
11246 
11247     set.traps=0;
11248 
11249     decNumber _1, _2, _3;
11250 
11251     EISloadInputBufferNumeric (1);   // according to MF1
11252 
11253     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11254     if (e->sign == -1)
11255         op1->bits |= DECNEG;
11256     if (e->S1 == CSFL)
11257         op1->exponent = e->exponent;
11258 
11259     EISloadInputBufferNumeric (2);   // according to MF2
11260 
11261     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11262     if (e->sign == -1)
11263         op2->bits |= DECNEG;
11264     if (e->S2 == CSFL)
11265         op2->exponent = e->exponent;
11266 
11267     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11268 
11269     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11270     bool iOvr = 0;
11271     if (op3->digits > 63) {
11272         uint8_t pr[256];
11273         // if sf<=0, trailing zeroes can't be shifted out
11274         // if sf> 0, (some of) trailing zeroes can be shifted out
11275         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11276 
11277         int ctz = 0;
11278         if (sf>0) {     // optimize: we don't care when sf>0
11279             decNumberGetBCD(op3,pr);
11280             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11281                  ctz ++;
11282         }
11283 
11284         if (op3->digits - min(max(sf,0),ctz) > 63) {
11285 
11286             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11287             int safe = set.digits;
11288             decNumber tmp;
11289 
11290             // discard MS digits
11291             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11292             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11293             decNumberPlus(&tmp, op3, &set);
11294             set.digits = safe;
11295 
11296             decNumberSubtract(op3, op3, &tmp, &set);
11297 
11298             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
11299 
11300             decContextSetRounding(&set, safeR);
11301             iOvr = 1;
11302         }
11303     }
11304 
11305     bool Ovr = false, EOvr = false, Trunc = false;
11306 
11307     uint8_t out [256];
11308     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11309 
11310     Ovr |= iOvr;
11311 
11312     if (decNumberIsZero(op3))
11313         op3->exponent = 127;
11314 
11315     // now write to memory in proper format.....
11316 
11317     //word18 dstAddr = e->dstAddr;
11318     int pos = (int) dstCN;
11319 
11320     // 1st, take care of any leading sign .......
11321     switch(e->S3)
11322     {
11323         case CSFL:  // floating-point, leading sign.
11324         case CSLS:  // fixed-point, leading sign
11325             switch(dstTN)
11326         {
11327             case CTN4:
11328                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
11329                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11330                 else
11331                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11332                 break;
11333             case CTN9:
11334                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11335                 break;
11336         }
11337             break;
11338 
11339         case CSTS:  // nuttin' to do here .....
11340         case CSNS:
11341             break;  // no sign wysiwyg
11342     }
11343 
11344     // 2nd, write the digits .....
11345     for(int i = 0 ; i < n3 ; i++)
11346         switch(dstTN)
11347     {
11348         case CTN4:
11349             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11350             break;
11351         case CTN9:
11352             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11353             break;
11354     }
11355 
11356     // 3rd, take care of any trailing sign or exponent ...
11357     switch(e->S3)
11358     {
11359         case CSTS:  // write trailing sign ....
11360             switch(dstTN)
11361             {
11362                 case CTN4:
11363                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
11364                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11365                     else
11366                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11367                     break;
11368                 case CTN9:
11369                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11370                     break;
11371             }
11372             break;
11373 
11374         case CSFL:  // floating-point, leading sign.
11375             // write the exponent
11376             switch(dstTN)
11377             {
11378                 case CTN4:
11379                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11380                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11381 
11382                     break;
11383                 case CTN9:
11384                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11385                     break;
11386             }
11387             break;
11388 
11389         case CSLS:  // fixed point, leading sign - already done
11390         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11391             break;
11392     }
11393 
11394     // set flags, etc ...
11395     if (e->S3 == CSFL)
11396     {
11397         if (op3->exponent > 127)
11398         {
11399             SET_I_EOFL;
11400             EOvr = true;
11401         }
11402         if (op3->exponent < -128)
11403         {
11404             SET_I_EUFL;
11405             EOvr = true;
11406         }
11407     }
11408 
11409     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11410     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11411 
11412     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11413 
11414     cleanupOperandDescriptor (1);
11415     cleanupOperandDescriptor (2);
11416     cleanupOperandDescriptor (3);
11417 
11418     if (TST_I_TRUNC && T && tstOVFfault ())
11419       doFault(FAULT_OFL, fst_zero, "sb3d truncation(overflow) fault");
11420     if (EOvr && tstOVFfault ())
11421         doFault(FAULT_OFL, fst_zero, "sb3d over/underflow fault");
11422     if (Ovr)
11423     {
11424         SET_I_OFLOW;
11425         if (tstOVFfault ())
11426           doFault(FAULT_OFL, fst_zero, "sb3d overflow fault");
11427     }
11428 }
11429 
11430 /*
11431  * mp2d - Multiply Using Two Decimal Operands
11432  */
11433 
11434 void mp2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
11435 {
11436     EISstruct * e = & cpu.currentEISinstruction;
11437 
11438     fault_ipr_subtype_ mod_fault = 0;
11439 
11440 #ifndef EIS_SETUP
11441     setupOperandDescriptor(1, &mod_fault);
11442     setupOperandDescriptor(2, &mod_fault);
11443     setupOperandDescriptorCache(3);
11444 #endif
11445 
11446     parseNumericOperandDescriptor(1, &mod_fault);
11447     parseNumericOperandDescriptor(2, &mod_fault);
11448 
11449     L68_ (
11450       // L68 raises it immediately
11451       if (mod_fault)
11452         {
11453           doFault (FAULT_IPR,
11454                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11455                    "Illegal modifier");
11456         }
11457     )
11458 
11459     // Bits 1-8 MBZ
11460     if (IWB_IRODD & 0377000000000)
11461       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp2d 1-8 MBZ");
11462 
11463     DPS8M_ (
11464       // DPS8M raises it delayed
11465       if (mod_fault)
11466         {
11467           doFault (FAULT_IPR,
11468                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11469                    "Illegal modifier");
11470         }
11471     )
11472 
11473     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11474     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11475     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11476 
11477     PNL (L68_ (if (R)
11478       DU_CYCLE_FRND;))
11479 
11480     uint srcTN = e->TN1;    // type of chars in src
11481 
11482     uint dstTN = e->TN2;    // type of chars in dst
11483     uint dstCN = e->CN2;    // starting at char pos CN
11484 
11485     e->ADDR3 = e->ADDR2;
11486 
11487     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
11488 
11489     /*
11490      * Here we need to distinguish between 4 type of numbers.
11491      *
11492      * CSFL - Floating-point, leading sign
11493      * CSLS - Scaled fixed-point, leading sign
11494      * CSTS - Scaled fixed-point, trailing sign
11495      * CSNS - Scaled fixed-point, unsigned
11496      */
11497 
11498     // determine precision
11499     switch(e->S1)
11500     {
11501         case CSFL:
11502             n1 = (int) e->N1 - 1; // need to account for the - sign
11503             if (srcTN == CTN4)
11504                 n1 -= 2;    // 2 4-bit digits exponent
11505             else
11506                 n1 -= 1;    // 1 9-bit digit exponent
11507             sc1 = 0;        // no scaling factor
11508             break;
11509 
11510         case CSLS:
11511         case CSTS:
11512             n1 = (int) e->N1 - 1; // only 1 sign
11513             sc1 = -e->SF1;
11514             break;
11515 
11516         case CSNS:
11517             n1 = (int) e->N1;     // no sign
11518             sc1 = -e->SF1;
11519             break;  // no sign wysiwyg
11520     }
11521 
11522     if (n1 < 1)
11523         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n1<1");
11524 
11525     switch(e->S2)
11526     {
11527         case CSFL:
11528             n2 = (int) e->N2 - 1; // need to account for the sign
11529             if (e->TN2 == CTN4)
11530                 n2 -= 2;    // 2 4-bit digit exponent
11531             else
11532                 n2 -= 1;    // 1 9-bit digit exponent
11533             sc2 = 0;        // no scaling factor
11534             break;
11535 
11536         case CSLS:
11537         case CSTS:
11538             n2 = (int) e->N2 - 1; // 1 sign
11539             sc2 = -e->SF2;
11540             break;
11541 
11542         case CSNS:
11543             n2 = (int) e->N2;     // no sign
11544             sc2 = -e->SF2;
11545             break;  // no sign wysiwyg
11546     }
11547 
11548     if (n2 < 1)
11549         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n2<1");
11550 
11551     decContext set;
11552     decContextDefaultDPS8Mul(&set); // 126 digits for multiply
11553 
11554     set.traps=0;
11555 
11556     decNumber _1, _2, _3;
11557 
11558     EISloadInputBufferNumeric (1);   // according to MF1
11559 
11560     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11561     if (e->sign == -1)
11562         op1->bits |= DECNEG;
11563     if (e->S1 == CSFL)
11564         op1->exponent = e->exponent;
11565 
11566     EISloadInputBufferNumeric (2);   // according to MF2
11567 
11568     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11569     if (e->sign == -1)
11570         op2->bits |= DECNEG;
11571     if (e->S2 == CSFL)
11572         op2->exponent = e->exponent;
11573 
11574     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11575 
11576     bool Ovr = false, EOvr = false, Trunc = false;
11577 
11578     uint8_t out [256];
11579     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11580 
11581     if (decNumberIsZero(op3))
11582         op3->exponent = 127;
11583 
11584     // now write to memory in proper format.....
11585 
11586     //word18 dstAddr = e->dstAddr;
11587     int pos = (int) dstCN;
11588 
11589     // 1st, take care of any leading sign .......
11590     switch(e->S2)
11591     {
11592         case CSFL:  // floating-point, leading sign.
11593         case CSLS:  // fixed-point, leading sign
11594             switch(dstTN)
11595         {
11596             case CTN4:
11597                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
11598                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11599                 else
11600                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11601                 break;
11602             case CTN9:
11603                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11604                 break;
11605         }
11606             break;
11607 
11608         case CSTS:  // nuttin' to do here .....
11609         case CSNS:
11610             break;  // no sign wysiwyg
11611     }
11612 
11613     // 2nd, write the digits .....
11614     for(int i = 0 ; i < n2 ; i++)
11615         switch(dstTN)
11616     {
11617         case CTN4:
11618             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11619             break;
11620         case CTN9:
11621             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11622             break;
11623     }
11624 
11625     // 3rd, take care of any trailing sign or exponent ...
11626     switch(e->S2)
11627     {
11628         case CSTS:  // write trailing sign ....
11629             switch(dstTN)
11630         {
11631             case CTN4:
11632                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
11633                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11634                 else
11635                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11636                 break;
11637             case CTN9:
11638                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11639                 break;
11640         }
11641             break;
11642 
11643         case CSFL:  // floating-point, leading sign.
11644             // write the exponent
11645             switch(dstTN)
11646             {
11647                 case CTN4:
11648                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11649                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11650 
11651                     break;
11652                 case CTN9:
11653                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11654                     break;
11655             }
11656             break;
11657 
11658         case CSLS:  // fixed point, leading sign - already done
11659         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11660             break;
11661     }
11662 
11663     // set flags, etc ...
11664     if (e->S2 == CSFL)
11665     {
11666         if (op3->exponent > 127)
11667         {
11668             SET_I_EOFL;
11669             EOvr = true;
11670         }
11671         if (op3->exponent < -128)
11672         {
11673             SET_I_EUFL;
11674             EOvr = true;
11675         }
11676     }
11677 
11678     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11679     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11680 
11681     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11682 
11683     cleanupOperandDescriptor (1);
11684     cleanupOperandDescriptor (2);
11685     cleanupOperandDescriptor (3);
11686 
11687     if (TST_I_TRUNC && T && tstOVFfault ())
11688       doFault(FAULT_OFL, fst_zero, "mp2d truncation(overflow) fault");
11689     if (EOvr && tstOVFfault ())
11690         doFault(FAULT_OFL, fst_zero, "mp2d over/underflow fault");
11691     if (Ovr)
11692     {
11693         SET_I_OFLOW;
11694         if (tstOVFfault ())
11695           doFault(FAULT_OFL, fst_zero, "mp2d overflow fault");
11696     }
11697 }
11698 
11699 /*
11700  * mp3d - Multiply Using Three Decimal Operands
11701  */
11702 
11703 void mp3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
11704 {
11705     EISstruct * e = & cpu.currentEISinstruction;
11706 
11707     fault_ipr_subtype_ mod_fault = 0;
11708 
11709 #ifndef EIS_SETUP
11710     setupOperandDescriptor(1, &mod_fault);
11711     setupOperandDescriptor(2, &mod_fault);
11712     setupOperandDescriptor(3, &mod_fault);
11713 #endif
11714 
11715     parseNumericOperandDescriptor(1, &mod_fault);
11716     parseNumericOperandDescriptor(2, &mod_fault);
11717     parseNumericOperandDescriptor(3, &mod_fault);
11718 
11719     L68_ (
11720       // L68 raises it immediately
11721       if (mod_fault)
11722         {
11723           doFault (FAULT_IPR,
11724                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11725                    "Illegal modifier");
11726         }
11727     )
11728 
11729     // Bit 1 MBZ
11730     if (IWB_IRODD & 0200000000000)
11731       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp3d(): 1 MBZ");
11732 
11733     DPS8M_ (
11734       // DPS8M raises it delayed
11735       if (mod_fault)
11736         {
11737           doFault (FAULT_IPR,
11738                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11739                    "Illegal modifier");
11740         }
11741     )
11742 
11743     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11744     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11745     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11746 
11747     PNL (L68_ (if (R)
11748       DU_CYCLE_FRND;))
11749 
11750     uint srcTN = e->TN1;    // type of chars in src
11751 
11752     uint dstTN = e->TN3;    // type of chars in dst
11753     uint dstCN = e->CN3;    // starting at char pos CN
11754 
11755     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11756 
11757     /*
11758      * Here we need to distinguish between 4 type of numbers.
11759      *
11760      * CSFL - Floating-point, leading sign
11761      * CSLS - Scaled fixed-point, leading sign
11762      * CSTS - Scaled fixed-point, trailing sign
11763      * CSNS - Scaled fixed-point, unsigned
11764      */
11765 
11766     // determine precision
11767     switch(e->S1)
11768     {
11769         case CSFL:
11770             n1 = (int) e->N1 - 1; // need to account for the - sign
11771             if (srcTN == CTN4)
11772                 n1 -= 2;    // 2 4-bit digits exponent
11773             else
11774                 n1 -= 1;    // 1 9-bit digit exponent
11775             sc1 = 0;        // no scaling factor
11776             break;
11777 
11778         case CSLS:
11779         case CSTS:
11780             n1 = (int) e->N1 - 1; // only 1 sign
11781             sc1 = -e->SF1;
11782             break;
11783 
11784         case CSNS:
11785             n1 = (int) e->N1;     // no sign
11786             sc1 = -e->SF1;
11787             break;  // no sign wysiwyg
11788     }
11789 
11790     if (n1 < 1)
11791         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n1<1");
11792 
11793     switch(e->S2)
11794     {
11795         case CSFL:
11796             n2 = (int) e->N2 - 1; // need to account for the sign
11797             if (e->TN2 == CTN4)
11798                 n2 -= 2;    // 2 4-bit digit exponent
11799             else
11800                 n2 -= 1;    // 1 9-bit digit exponent
11801             sc2 = 0;        // no scaling factor
11802             break;
11803 
11804         case CSLS:
11805         case CSTS:
11806             n2 = (int) e->N2 - 1; // 1 sign
11807             sc2 = -e->SF2;
11808             break;
11809 
11810         case CSNS:
11811             n2 = (int) e->N2;     // no sign
11812             sc2 = -e->SF2;
11813             break;  // no sign wysiwyg
11814     }
11815 
11816     if (n2 < 1)
11817         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n2<1");
11818 
11819     switch(e->S3)
11820     {
11821         case CSFL:
11822             n3 = (int) e->N3 - 1; // need to account for the sign
11823             if (dstTN == CTN4)
11824                 n3 -= 2;    // 2 4-bit digit exponent
11825             else
11826                 n3 -= 1;    // 1 9-bit digit exponent
11827             break;
11828 
11829         case CSLS:
11830         case CSTS:
11831             n3 = (int) e->N3 - 1; // 1 sign
11832             break;
11833 
11834         case CSNS:
11835             n3 = (int) e->N3;     // no sign
11836             break;  // no sign wysiwyg
11837     }
11838 
11839     if (n3 < 1)
11840         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n3<1");
11841 
11842     decContext set;
11843     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11844     decContextDefaultDPS8Mul(&set);     // 126 digits for multiply
11845 
11846     set.traps=0;
11847 
11848     decNumber _1, _2, _3;
11849 
11850     EISloadInputBufferNumeric (1);   // according to MF1
11851 
11852     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11853     if (e->sign == -1)
11854         op1->bits |= DECNEG;
11855     if (e->S1 == CSFL)
11856         op1->exponent = e->exponent;
11857 
11858     EISloadInputBufferNumeric (2);   // according to MF2
11859 
11860     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11861     if (e->sign == -1)
11862         op2->bits |= DECNEG;
11863     if (e->S2 == CSFL)
11864         op2->exponent = e->exponent;
11865 
11866     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11867 
11868 //    char c1[1024];
11869 //    char c2[1024];
11870 //    char c3[1024];
11871 //
11872 //    decNumberToString(op1, c1);
11873 //    sim_printf("c1:%s\n", c1);
11874 //    decNumberToString(op2, c2);
11875 //    sim_printf("c2:%s\n", c2);
11876 //    decNumberToString(op3, c3);
11877 //    sim_printf("c3:%s\n", c3);
11878 
11879     bool Ovr = false, EOvr = false, Trunc = false;
11880 
11881     uint8_t out [256];
11882     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11883 
11884     if (decNumberIsZero(op3))
11885         op3->exponent = 127;
11886 
11887     // now write to memory in proper format.....
11888 
11889     //word18 dstAddr = e->dstAddr;
11890     int pos = (int) dstCN;
11891 
11892     // 1st, take care of any leading sign .......
11893     switch(e->S3)
11894     {
11895         case CSFL:  // floating-point, leading sign.
11896         case CSLS:  // fixed-point, leading sign
11897             switch(dstTN)
11898             {
11899             case CTN4:
11900               if (e->P) // If TN2 and S2 specify a 4-bit signed number and P
11901                           // = 1, then the 13(8) plus sign character is placed
11902                           // appropriately if the result of the operation is
11903                           // positive.
11904                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11905                 else
11906                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11907                 break;
11908             case CTN9:
11909                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11910                 break;
11911             }
11912             break;
11913 
11914         case CSTS:  // nuttin' to do here .....
11915         case CSNS:
11916             break;  // no sign wysiwyg
11917     }
11918 
11919     // 2nd, write the digits .....
11920     for(int i = 0 ; i < n3 ; i++)
11921         switch(dstTN)
11922         {
11923             case CTN4:
11924                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11925                 break;
11926             case CTN9:
11927                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11928                 break;
11929         }
11930 
11931         // 3rd, take care of any trailing sign or exponent ...
11932     switch(e->S3)
11933     {
11934         case CSTS:  // write trailing sign ....
11935             switch(dstTN)
11936             {
11937                 case CTN4:
11938                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
11939                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11940                     else
11941                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11942                     break;
11943                 case CTN9:
11944                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11945                     break;
11946             }
11947             break;
11948 
11949         case CSFL:  // floating-point, leading sign.
11950             // write the exponent
11951             switch(dstTN)
11952             {
11953                 case CTN4:
11954                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11955                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11956                     break;
11957                 case CTN9:
11958                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11959                     break;
11960             }
11961             break;
11962 
11963         case CSLS:  // fixed point, leading sign - already done
11964         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11965             break;
11966     }
11967 
11968     // set flags, etc ...
11969     if (e->S3 == CSFL)
11970     {
11971         if (op3->exponent > 127)
11972         {
11973             SET_I_EOFL;
11974             EOvr = true;
11975         }
11976         if (op3->exponent < -128)
11977         {
11978             SET_I_EUFL;
11979             EOvr = true;
11980         }
11981     }
11982 
11983     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11984     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11985 
11986     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11987 
11988     cleanupOperandDescriptor (1);
11989     cleanupOperandDescriptor (2);
11990     cleanupOperandDescriptor (3);
11991 
11992     if (TST_I_TRUNC && T && tstOVFfault ())
11993       doFault(FAULT_OFL, fst_zero, "mp3d truncation(overflow) fault");
11994     if (EOvr && tstOVFfault ())
11995         doFault(FAULT_OFL, fst_zero, "mp3d over/underflow fault");
11996     if (Ovr)
11997     {
11998         SET_I_OFLOW;
11999         if (tstOVFfault ())
12000           doFault(FAULT_OFL, fst_zero, "mp3d overflow fault");
12001     }
12002 }
12003 
12004 
12005 
12006 
12007 
12008 
12009 
12010 
12011 
12012 
12013 
12014 
12015 
12016 
12017 
12018 
12019 
12020 
12021 
12022 
12023 
12024 
12025 
12026 
12027 
12028 
12029 
12030 
12031 
12032 
12033 
12034 
12035 
12036 
12037 
12038 
12039 
12040 
12041 
12042 
12043 
12044 
12045 
12046 
12047 
12048 
12049 
12050 
12051 
12052 
12053 
12054 
12055 
12056 
12057 
12058 
12059 
12060 
12061 
12062 
12063 
12064 
12065 
12066 
12067 
12068 
12069 
12070 
12071 
12072 
12073 
12074 
12075 
12076 
12077 
12078 
12079 
12080 
12081 
12082 
12083 
12084 
12085 
12086 
12087 
12088 
12089 
12090 
12091 
12092 
12093 
12094 
12095 
12096 
12097 
12098 
12099 
12100 
12101 
12102 
12103 
12104 
12105 
12106 
12107 
12108 
12109 
12110 
12111 
12112 
12113 
12114 
12115 
12116 
12117 
12118 
12119 
12120 
12121 
12122 
12123 
12124 
12125 
12126 
12127 
12128 
12129 
12130 
12131 
12132 
12133 
12134 
12135 
12136 
12137 
12138 
12139 
12140 
12141 
12142 
12143 
12144 
12145 
12146 
12147 
12148 
12149 
12150 
12151 
12152 
12153 
12154 
12155 
12156 
12157 
12158 
12159 
12160 
12161 
12162 
12163 
12164 
12165 
12166 
12167 
12168 
12169 
12170 
12171 
12172 
12173 
12174 
12175 
12176 
12177 
12178 
12179 
12180 
12181 
12182 
12183 
12184 
12185 
12186 
12187 
12188 
12189 
12190 
12191 
12192 
12193 
12194 
12195 
12196 
12197 
12198 
12199 
12200 
12201 
12202 
12203 
12204 
12205 
12206 
12207 
12208 
12209 
12210 
12211 
12212 
12213 
12214 
12215 
12216 
12217 
12218 
12219 
12220 
12221 
12222 
12223 
12224 
12225 
12226 
12227 
12228 
12229 
12230 
12231 
12232 
12233 
12234 
12235 
12236 
12237 
12238 
12239 
12240 
12241 
12242 
12243 
12244 
12245 
12246 
12247 
12248 
12249 
12250 
12251 
12252 
12253 
12254 
12255 
12256 
12257 
12258 
12259 
12260 
12261 
12262 
12263 
12264 
12265 
12266 
12267 
12268 
12269 
12270 
12271 
12272 
12273 
12274 
12275 
12276 
12277 
12278 
12279 
12280 
12281 
12282 
12283 
12284 
12285 
12286 
12287 
12288 
12289 
12290 
12291 
12292 
12293 
12294 
12295 
12296 
12297 
12298 
12299 
12300 
12301 
12302 
12303 
12304 
12305 
12306 
12307 
12308 
12309 
12310 
12311 
12312 
12313 
12314 
12315 
12316 
12317 
12318 
12319 
12320 
12321 
12322 
12323 
12324 
12325 
12326 
12327 
12328 
12329 
12330 
12331 
12332 
12333 
12334 
12335 
12336 
12337 
12338 
12339 
12340 
12341 
12342 
12343 
12344 
12345 
12346 
12347 
12348 
12349 
12350 
12351 
12352 
12353 
12354 
12355 
12356 
12357 
12358 
12359 
12360 
12361 
12362 
12363 
12364 
12365 
12366 
12367 
12368 
12369 
12370 
12371 
12372 
12373 
12374 
12375 
12376 
12377 
12378 
12379 
12380 
12381 
12382 
12383 
12384 
12385 
12386 
12387 
12388 
12389 
12390 
12391 
12392 
12393 
12394 
12395 
12396 
12397 
12398 
12399 
12400 
12401 
12402 
12403 
12404 
12405 
12406 
12407 
12408 
12409 
12410 
12411 
12412 
12413 
12414 
12415 
12416 
12417 
12418 
12419 
12420 
12421 
12422 
12423 
12424 
12425 
12426 
12427 
12428 
12429 
12430 
12431 
12432 
12433 
12434 
12435 
12436 
12437 
12438 
12439 
12440 
12441 
12442 
12443 
12444 
12445 
12446 
12447 
12448 
12449 
12450 
12451 
12452 
12453 
12454 
12455 
12456 
12457 
12458 
12459 
12460 
12461 
12462 
12463 
12464 
12465 
12466 
12467 
12468 
12469 
12470 
12471 
12472 
12473 
12474 
12475 
12476 
12477 
12478 
12479 
12480 
12481 
12482 
12483 
12484 
12485 
12486 
12487 
12488 
12489 
12490 
12491 
12492 
12493 
12494 
12495 
12496 
12497 
12498 
12499 
12500 
12501 
12502 
12503 
12504 
12505 
12506 
12507 
12508 
12509 
12510 
12511 
12512 
12513 
12514 
12515 
12516 
12517 
12518 
12519 
12520 
12521 
12522 
12523 
12524 
12525 
12526 
12527 
12528 
12529 
12530 
12531 
12532 
12533 
12534 
12535 
12536 
12537 
12538 
12539 
12540 
12541 
12542 
12543 
12544 
12545 
12546 
12547 
12548 
12549 
12550 
12551 
12552 
12553 
12554 
12555 
12556 
12557 
12558 
12559 
12560 
12561 
12562 
12563 
12564 
12565 
12566 
12567 
12568 
12569 
12570 
12571 
12572 
12573 
12574 
12575 
12576 
12577 
12578 
12579 
12580 
12581 
12582 
12583 
12584 
12585 
12586 
12587 
12588 
12589 
12590 
12591 
12592 
12593 
12594 
12595 
12596 
12597 
12598 
12599 
12600 
12601 
12602 
12603 
12604 
12605 
12606 
12607 
12608 
12609 
12610 
12611 
12612 
12613 
12614 
12615 
12616 
12617 
12618 
12619 
12620 
12621 
12622 
12623 
12624 
12625 
12626 
12627 
12628 
12629 
12630 
12631 
12632 
12633 
12634 
12635 
12636 
12637 
12638 
12639 
12640 
12641 
12642 
12643 
12644 
12645 
12646 
12647 
12648 
12649 
12650 
12651 
12652 
12653 
12654 
12655 
12656 
12657 
12658 
12659 
12660 
12661 
12662 
12663 
12664 
12665 
12666 
12667 
12668 
12669 
12670 
12671 
12672 
12673 
12674 
12675 
12676 
12677 
12678 
12679 
12680 
12681 
12682 
12683 
12684 
12685 
12686 
12687 
12688 
12689 
12690 
12691 
12692 
12693 
12694 
12695 
12696 
12697 
12698 
12699 
12700 
12701 
12702 
12703 
12704 
12705 
12706 
12707 
12708 
12709 
12710 
12711 
12712 
12713 
12714 
12715 
12716 
12717 
12718 
12719 
12720 
12721 
12722 
12723 
12724 
12725 
12726 
12727 
12728 
12729 
12730 
12731 
12732 
12733 
12734 
12735 
12736 
12737 
12738 
12739 
12740 
12741 
12742 
12743 
12744 
12745 
12746 
12747 
12748 
12749 
12750 
12751 
12752 /*
12753  * dv2d - Divide Using Two Decimal Operands
12754  */
12755 
12756 void dv2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
12757 {
12758     EISstruct * e = & cpu.currentEISinstruction;
12759 
12760     fault_ipr_subtype_ mod_fault = 0;
12761 
12762 #ifndef EIS_SETUP
12763     setupOperandDescriptor(1, &mod_fault);
12764     setupOperandDescriptor(2, &mod_fault);
12765     setupOperandDescriptorCache(3);
12766 #endif
12767 
12768     parseNumericOperandDescriptor(1, &mod_fault);
12769     parseNumericOperandDescriptor(2, &mod_fault);
12770 
12771     L68_ (
12772       // L68 raises it immediately
12773       if (mod_fault)
12774         {
12775           doFault (FAULT_IPR,
12776                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12777                    "Illegal modifier");
12778         }
12779     )
12780 
12781     // Bits 1-8 MBZ
12782     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ as well
12783     if (IWB_IRODD & 0377400000000)
12784       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv2d 1-9 MBZ");
12785 
12786     DPS8M_ (
12787       // DPS8M raises it delayed
12788       if (mod_fault)
12789         {
12790           doFault (FAULT_IPR,
12791                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12792                    "Illegal modifier");
12793         }
12794     )
12795 
12796     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
12797     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
12798     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
12799 
12800     PNL (L68_ (if (R)
12801       DU_CYCLE_FRND;))
12802 
12803     uint srcTN = e->TN1;    // type of chars in src
12804 
12805     uint dstTN = e->TN2;    // type of chars in dst
12806     uint dstCN = e->CN2;    // starting at char pos CN
12807 
12808     e->ADDR3 = e->ADDR2;
12809 
12810     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
12811 
12812     /*
12813      * Here we need to distinguish between 4 type of numbers.
12814      *
12815      * CSFL - Floating-point, leading sign
12816      * CSLS - Scaled fixed-point, leading sign
12817      * CSTS - Scaled fixed-point, trailing sign
12818      * CSNS - Scaled fixed-point, unsigned
12819      */
12820 
12821     // determine precision
12822     switch(e->S1)
12823     {
12824         case CSFL:
12825             n1 = (int) e->N1 - 1; // need to account for the - sign
12826             if (srcTN == CTN4)
12827                 n1 -= 2;    // 2 4-bit digits exponent
12828             else
12829                 n1 -= 1;    // 1 9-bit digit exponent
12830             sc1 = 0;        // no scaling factor
12831             break;
12832 
12833         case CSLS:
12834         case CSTS:
12835             n1 = (int) e->N1 - 1; // only 1 sign
12836             sc1 = -e->SF1;
12837             break;
12838 
12839         case CSNS:
12840             n1 = (int) e->N1;     // no sign
12841             sc1 = -e->SF1;
12842             break;  // no sign wysiwyg
12843     }
12844 
12845     if (n1 < 1)
12846         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n1<1");
12847 
12848     switch(e->S2)
12849     {
12850         case CSFL:
12851             n2 = (int) e->N2 - 1; // need to account for the sign
12852             if (e->TN2 == CTN4)
12853                 n2 -= 2;    // 2 4-bit digit exponent
12854             else
12855                 n2 -= 1;    // 1 9-bit digit exponent
12856             sc2 = 0;        // no scaling factor
12857             break;
12858 
12859         case CSLS:
12860         case CSTS:
12861             n2 = (int) e->N2 - 1; // 1 sign
12862             sc2 = -e->SF2;
12863             break;
12864 
12865         case CSNS:
12866             n2 = (int) e->N2;     // no sign
12867             sc2 = -e->SF2;
12868             break;  // no sign wysiwyg
12869     }
12870 
12871     if (n2 < 1)
12872         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n2<1");
12873 
12874     decContext set;
12875     decContextDefaultDPS8(&set);
12876 
12877     set.traps=0;
12878 
12879     decNumber _1, _2, _3;
12880 
12881     EISloadInputBufferNumeric (1);   // according to MF1
12882 
12883     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);    // divisor
12884     if (e->sign == -1)
12885         op1->bits |= DECNEG;
12886     if (e->S1 == CSFL)
12887         op1->exponent = e->exponent;
12888 
12889     // check for divide by 0!
12890     if (decNumberIsZero(op1))
12891     {
12892         doFault(FAULT_DIV, fst_zero, "dv2d division by 0");
12893     }
12894 
12895     word9   inBufferop1 [64];
12896     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
12897 
12898     EISloadInputBufferNumeric (2);   // according to MF2
12899 
12900     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);    // dividend
12901     if (e->sign == -1)
12902         op2->bits |= DECNEG;
12903     if (e->S2 == CSFL)
12904         op2->exponent = e->exponent;
12905 
12906     int NQ;
12907     if (e->S2 == CSFL)
12908     {
12909         NQ = n2;
12910     }
12911     else
12912     {
12913         // count leading zeroes
12914         // TODO optimize - can these be somehow extracted from decNumbers?
12915         int clz1, clz2, i;
12916         for (i=0; i < op1->digits; i++)
12917             if (inBufferop1[i]!=0)
12918                 break;
12919         clz1 = i;
12920         for (i=0; i < op2->digits; i++)
12921             if (e->inBuffer[i]!=0) // this still holds op2 digits
12922                 break;
12923         clz2 = i;
12924         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: clz1 %d clz2 %d\n",clz1,clz2);
12925 
12926         // XXX are clz also valid for CSFL dividend / divisor? probably yes
12927         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
12928         NQ = (n2-clz2+1) - (n1-clz1) + (-(e->S1==CSFL?op1->exponent:(int)e->SF1));
12929 
12930 sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d S1 %d S2 %d N1 %d N2 %d clz1 %d clz2 %d E1 %d E2 %d SF2 %d NQ %d\n",e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF2,NQ);
12931     }
12932     if (NQ > 63)
12933         doFault(FAULT_DIV, fst_zero, "dv2d NQ>63");
12934     // Note: NQ is currently unused apart from this FAULT_DIV check. decNumber produces more digits than required, but they are then rounded/truncated
12935 
12936     // Yes, they're switched. op1=divisor
12937     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
12938     // Note DPS88 and DPS9000 are different when NQ <= 0
12939     // This is a flaw in the DPS8/70 hardware which was corrected in later models
12940     // ISOLTS-817 05b
12941 
12942     PRINTDEC("op2", op2);
12943     PRINTDEC("op1", op1);
12944     PRINTDEC("op3", op3);
12945 
12946     // let's check division results to see for anomalous conditions
12947     if (
12948         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
12949         (set.status & DEC_Invalid_operation) ||
12950         (set.status & DEC_Division_by_zero)
12951         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv2d anomalous results"); }      // divide by zero has already been checked before
12952 
12953     if (e->S2 == CSFL)
12954     {
12955         // justify CSFL left
12956         // This is a flaw in the DPS8/70 hardware which was corrected in later models
12957         // Note DPS88 and DPS9000 are different
12958         // ISOLTS-817 06c,06e
12959 
12960         decNumber _sf;
12961 
12962         if (n2 - op3->digits > 0)
12963         {
12964             decNumberFromInt32(&_sf, op3->exponent - (n2 - op3->digits));
12965             PRINTDEC("Value 1", op3)
12966             PRINTDEC("Value sf", &_sf)
12967             op3 = decNumberRescale(op3, op3, &_sf, &set);
12968             PRINTDEC("Value 2", op3)
12969         }
12970     }
12971 
12972     bool Ovr = false, EOvr = false, Trunc = false;
12973     uint8_t out[256];
12974 
12975     // CSFL: If the divisor is greater than the dividend after operand
12976     // alignment, the leading zero digit produced is counted and the effective
12977     // precision of the result is reduced by one.
12978     // This is a flaw in the DPS8/70 hardware which was corrected in later models
12979     // Note DPS88 and DPS9000 are different
12980     //
12981     // "greater after operand alignment" means scale until most-significant digits are nonzero, then compare magnitudes ignoring exponents
12982     // This passes ISOLTS-817 06e, ET 458,461,483,486
12983     char *res;
12984     if (e->S2 == CSFL) {
12985         decNumber _1a;
12986         decNumber _2a;
12987         decNumber _sf;
12988         if (op1->digits >= op2->digits) {
12989             // scale op2
12990             decNumberCopy(&_1a, op1);
12991             decNumberFromInt32(&_sf, op1->digits - op2->digits);
12992             decNumberShift(&_2a, op2, &_sf, &set);
12993         } else if (op1->digits < op2->digits) {
12994             // scale op1
12995             decNumberFromInt32(&_sf, op2->digits - op1->digits);
12996             decNumberShift(&_1a, op1, &_sf, &set);
12997             decNumberCopy(&_2a, op2);
12998         }
12999         _1a.exponent = 0;
13000         _2a.exponent = 0;
13001 
13002         PRINTDEC("dv2d: op1a", &_1a);
13003         PRINTDEC("dv2d: op2a", &_2a);
13004         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\n",op1->exponent,op2->exponent,op1->digits,op2->digits,_1a.digits,_2a.digits);
13005 
13006         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13007             // shorten the result field to get proper rounding
13008             res = formatDecimal(out, &set, op3, n2 -1, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13009 
13010             // prepend zero digit
13011             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13012             for (int i = n2; i > 0; i--) // incl.zero terminator
13013                  res[i] = res[i-1];
13014             res[0] = '0';
13015             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: addzero n2 %d %s exp %d\n",n2,res,op3->exponent);
13016         } else {
13017             // full n2 digits are returned
13018             res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13019         }
13020     } else {
13021         // same as all other decimal instructions
13022         res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13023     }
13024 
13025     if (decNumberIsZero(op3))
13026         op3->exponent = 127;
13027 
13028     // now write to memory in proper format.....
13029 
13030     int pos = (int) dstCN;
13031 
13032     // 1st, take care of any leading sign .......
13033     switch(e->S2)
13034     {
13035         case CSFL:  // floating-point, leading sign.
13036         case CSLS:  // fixed-point, leading sign
13037             switch(dstTN)
13038             {
13039                 case CTN4:
13040                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
13041                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13042                     else
13043                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13044                     break;
13045                 case CTN9:
13046                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13047                     break;
13048             }
13049             break;
13050 
13051         case CSTS:  // nuttin' to do here .....
13052         case CSNS:
13053             break;  // no sign wysiwyg
13054     }
13055 
13056     // 2nd, write the digits .....
13057     for(int i = 0 ; i < n2 ; i++)
13058         switch(dstTN)
13059         {
13060             case CTN4:
13061                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13062                 break;
13063             case CTN9:
13064                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13065                 break;
13066         }
13067 
13068     // 3rd, take care of any trailing sign or exponent ...
13069     switch(e->S2)
13070     {
13071         case CSTS:  // write trailing sign ....
13072             switch(dstTN)
13073             {
13074                 case CTN4:
13075                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
13076                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13077                     else
13078                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13079                     break;
13080                 case CTN9:
13081                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13082                     break;
13083             }
13084             break;
13085 
13086         case CSFL:  // floating-point, leading sign.
13087             // write the exponent
13088             switch(dstTN)
13089             {
13090                 case CTN4:
13091                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13092                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13093                     break;
13094                 case CTN9:
13095                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13096                     break;
13097             }
13098             break;
13099 
13100         case CSLS:  // fixed point, leading sign - already done
13101         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13102             break;
13103     }
13104 
13105     // set flags, etc ...
13106     if (e->S2 == CSFL)
13107     {
13108         if (op3->exponent > 127)
13109         {
13110             SET_I_EOFL;
13111             EOvr = true;
13112         }
13113         if (op3->exponent < -128)
13114         {
13115             SET_I_EUFL;
13116             EOvr = true;
13117         }
13118     }
13119 
13120     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13121     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13122 
13123     //SC_I_TRUNC (!R && Trunc); // no truncation flag for divide
13124 
13125     cleanupOperandDescriptor (1);
13126     cleanupOperandDescriptor (2);
13127     cleanupOperandDescriptor (3);
13128 
13129     //if (TST_I_TRUNC && T && tstOVFfault ())
13130     //  doFault(FAULT_OFL, fst_zero, "dv2d truncation(overflow) fault");
13131     if (EOvr && tstOVFfault ())
13132         doFault(FAULT_OFL, fst_zero, "dv2d over/underflow fault");
13133     if (Ovr)
13134     {
13135         SET_I_OFLOW;
13136         if (tstOVFfault ())
13137           doFault(FAULT_OFL, fst_zero, "dv2d overflow fault");
13138     }
13139 }
13140 
13141 /*
13142  * dv3d - Divide Using Three Decimal Operands
13143  */
13144 
13145 void dv3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
13146 
13147 {
13148     EISstruct * e = & cpu.currentEISinstruction;
13149 
13150     fault_ipr_subtype_ mod_fault = 0;
13151 
13152 #ifndef EIS_SETUP
13153     setupOperandDescriptor(1, &mod_fault);
13154     setupOperandDescriptor(2, &mod_fault);
13155     setupOperandDescriptor(3, &mod_fault);
13156 #endif
13157 
13158     parseNumericOperandDescriptor(1, &mod_fault);
13159     parseNumericOperandDescriptor(2, &mod_fault);
13160     parseNumericOperandDescriptor(3, &mod_fault);
13161 
13162     L68_ (
13163       // L68 raises it immediately
13164       if (mod_fault)
13165         {
13166           doFault (FAULT_IPR,
13167                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13168                    "Illegal modifier");
13169         }
13170     )
13171 
13172     // Bit 1 MBZ
13173     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ
13174     if (IWB_IRODD & 0200400000000)
13175       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv3d(): 1,9 MBZ");
13176 
13177     DPS8M_ (
13178       // DPS8M raises it delayed
13179       if (mod_fault)
13180         {
13181           doFault (FAULT_IPR,
13182                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13183                    "Illegal modifier");
13184         }
13185     )
13186 
13187     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
13188     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
13189     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
13190 
13191     PNL (L68_ (if (R)
13192       DU_CYCLE_FRND;))
13193 
13194     uint srcTN = e->TN1;    // type of chars in src
13195 
13196     uint dstTN = e->TN3;    // type of chars in dst
13197     uint dstCN = e->CN3;    // starting at char pos CN
13198 
13199     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
13200 
13201     /*
13202      * Here we need to distinguish between 4 type of numbers.
13203      *
13204      * CSFL - Floating-point, leading sign
13205      * CSLS - Scaled fixed-point, leading sign
13206      * CSTS - Scaled fixed-point, trailing sign
13207      * CSNS - Scaled fixed-point, unsigned
13208      */
13209 
13210     // determine precision
13211     switch(e->S1)
13212     {
13213         case CSFL:
13214             n1 = (int) e->N1 - 1; // need to account for the - sign
13215             if (srcTN == CTN4)
13216                 n1 -= 2;    // 2 4-bit digits exponent
13217             else
13218                 n1 -= 1;    // 1 9-bit digit exponent
13219             sc1 = 0;        // no scaling factor
13220             break;
13221 
13222         case CSLS:
13223         case CSTS:
13224             n1 = (int) e->N1 - 1; // only 1 sign
13225             sc1 = -e->SF1;
13226             break;
13227 
13228         case CSNS:
13229             n1 = (int) e->N1;     // no sign
13230             sc1 = -e->SF1;
13231             break;  // no sign wysiwyg
13232     }
13233 
13234     if (n1 < 1)
13235         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n1<1");
13236 
13237     switch(e->S2)
13238     {
13239         case CSFL:
13240             n2 = (int) e->N2 - 1; // need to account for the sign
13241             if (e->TN2 == CTN4)
13242                 n2 -= 2;    // 2 4-bit digit exponent
13243             else
13244                 n2 -= 1;    // 1 9-bit digit exponent
13245             sc2 = 0;        // no scaling factor
13246             break;
13247 
13248         case CSLS:
13249         case CSTS:
13250             n2 = (int) e->N2 - 1; // 1 sign
13251             sc2 = -e->SF2;
13252             break;
13253 
13254         case CSNS:
13255             n2 = (int) e->N2;     // no sign
13256             sc2 = -e->SF2;
13257             break;  // no sign wysiwyg
13258     }
13259 
13260     if (n2 < 1)
13261         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n2<1");
13262 
13263     switch(e->S3)
13264     {
13265         case CSFL:
13266             n3 = (int) e->N3 - 1; // need to account for the sign
13267             if (dstTN == CTN4)
13268                 n3 -= 2;    // 2 4-bit digit exponent
13269             else
13270                 n3 -= 1;    // 1 9-bit digit exponent
13271             break;
13272 
13273         case CSLS:
13274         case CSTS:
13275             n3 = (int) e->N3 - 1; // 1 sign
13276             break;
13277 
13278         case CSNS:
13279             n3 = (int) e->N3;     // no sign
13280             break;  // no sign wysiwyg
13281     }
13282     if (n3 < 1)
13283         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n3<1");
13284 
13285     decContext set;
13286     decContextDefaultDPS8(&set);
13287 
13288     set.traps=0;
13289 
13290     decNumber _1, _2, _3;
13291 
13292     EISloadInputBufferNumeric (1);   // according to MF1
13293 
13294     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
13295     //PRINTDEC("op1", op1);
13296     if (e->sign == -1)
13297         op1->bits |= DECNEG;
13298     if (e->S1 == CSFL)
13299         op1->exponent = e->exponent;
13300 
13301     // check for divide by 0!
13302     if (decNumberIsZero(op1))
13303     {
13304         doFault(FAULT_DIV, fst_zero, "dv3d division by 0");
13305     }
13306 
13307     word9   inBufferop1 [64];
13308     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13309 
13310     EISloadInputBufferNumeric (2);   // according to MF2
13311 
13312     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
13313     if (e->sign == -1)
13314         op2->bits |= DECNEG;
13315     if (e->S2 == CSFL)
13316         op2->exponent = e->exponent;
13317 
13318     // The number of required quotient digits, NQ, is determined before
13319     // division begins as follows:
13320     //  1) Floating-point quotient
13321     //      NQ = N3
13322     //  2) Fixed-point quotient
13323     //    NQ = (N2-LZ2+1) - (N1-LZ1) + (E2-E1-SF3)
13324     //    where: Nn = given operand field length
13325     //        LZn = leading zero count for operand n
13326     //        En = exponent of operand n
13327     //        SF3 = scaling factor of quotient
13328     // 3) Rounding
13329     //    If rounding is specified (R = 1), then one extra quotient digit is
13330     //    produced.
13331     // Note: rule 3 is already handled by formatDecimal rounding
13332     // Nn doesn't represent full field length, but length without sign and exponent (RJ78/DH03 seems like)
13333 
13334     int NQ;
13335     if (e->S3 == CSFL)
13336     {
13337         NQ = n3;
13338     }
13339     else
13340     {
13341         // count leading zeroes
13342         // TODO optimize - can these be somehow extracted from decNumbers?
13343         int clz1, clz2, i;
13344         for (i=0; i < op1->digits; i++)
13345             if (inBufferop1[i]!=0)
13346                 break;
13347         clz1 = i;
13348         for (i=0; i < op2->digits; i++)
13349             if (e->inBuffer[i]!=0) // this still holds op2 digits
13350                 break;
13351         clz2 = i;
13352         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: clz1 %d clz2 %d\n",clz1,clz2);
13353 
13354         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13355         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13356         NQ = (n2-clz2+1) - (n1-clz1) + ((e->S2==CSFL?op2->exponent:(int)e->SF2)-(e->S1==CSFL?op1->exponent:(int)e->SF1)-(int)e->SF3);
13357 
13358 sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d S1 %d S2 %d N1 %d N2 %d clz1 %d clz2 %d E1 %d E2 %d SF3 %d NQ %d\n",e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF3,NQ);
13359     }
13360     if (NQ > 63)
13361         doFault(FAULT_DIV, fst_zero, "dv3d NQ>63");
13362     // Note: NQ is currently unused apart from this FAULT_DIV check. decNumber produces more digits than required, but they are then rounded/truncated
13363 
13364     // Yes, they're switched. op1=divisor
13365     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13366     // Note DPS88 and DPS9000 are different when NQ <= 0
13367     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13368     // ISOLTS-817 05b
13369 
13370     PRINTDEC("op2", op2);
13371     PRINTDEC("op1", op1);
13372     PRINTDEC("op3", op3);
13373 
13374     // let's check division results to see for anomalous conditions
13375     if (
13376         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13377         (set.status & DEC_Invalid_operation) ||
13378         (set.status & DEC_Division_by_zero)
13379         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv3d anomalous results"); }      // divide by zero has already been checked before
13380 
13381     if (e->S3 == CSFL)
13382     {
13383         // justify CSFL left
13384         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13385         // Note DPS88 and DPS9000 are different
13386         // ISOLTS-817 06c,06e
13387 
13388         decNumber _sf;
13389 
13390         if (n3 - op3->digits > 0)
13391         {
13392             decNumberFromInt32(&_sf, op3->exponent - (n3 - op3->digits));
13393             PRINTDEC("Value 1", op3)
13394             PRINTDEC("Value sf", &_sf)
13395             op3 = decNumberRescale(op3, op3, &_sf, &set);
13396             PRINTDEC("Value 2", op3)
13397         }
13398     }
13399 
13400     bool Ovr = false, EOvr = false, Trunc = false;
13401     uint8_t out[256];
13402 
13403     // CSFL: If the divisor is greater than the dividend after operand
13404     // alignment, the leading zero digit produced is counted and the effective
13405     // precision of the result is reduced by one.
13406     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13407     // Note DPS88 and DPS9000 are different
13408     //
13409     // "greater after operand alignment" means scale until most-significant digits are nonzero, then compare magnitudes ignoring exponents
13410     // This passes ISOLTS-817 06e, ET 458,461,483,486
13411     char *res;
13412     if (e->S3 == CSFL) {
13413         decNumber _1a;
13414         decNumber _2a;
13415         decNumber _sf;
13416         if (op1->digits >= op2->digits) {
13417             // scale op2
13418             decNumberCopy(&_1a, op1);
13419             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13420             decNumberShift(&_2a, op2, &_sf, &set);
13421         } else if (op1->digits < op2->digits) {
13422             // scale op1
13423             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13424             decNumberShift(&_1a, op1, &_sf, &set);
13425             decNumberCopy(&_2a, op2);
13426         }
13427         _1a.exponent = 0;
13428         _2a.exponent = 0;
13429 
13430         PRINTDEC("dv3d: op1a", &_1a);
13431         PRINTDEC("dv3d: op2a", &_2a);
13432         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\n",op1->exponent,op2->exponent,op1->digits,op2->digits,_1a.digits,_2a.digits);
13433 
13434         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13435             // shorten the result field to get proper rounding
13436             res = formatDecimal(out, &set, op3, n3 -1, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13437 
13438             // prepend zero digit
13439             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13440             for (int i = n3; i > 0; i--) // incl.zero terminator
13441                  res[i] = res[i-1];
13442             res[0] = '0';
13443             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: addzero n3 %d %s exp %d\n",n3,res,op3->exponent);
13444         } else {
13445             // full n3 digits are returned
13446             res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13447         }
13448     } else {
13449         // same as all other decimal instructions
13450         res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13451     }
13452 
13453     if (decNumberIsZero(op3))
13454         op3->exponent = 127;
13455 
13456     //printf("%s\r\n", res);
13457 
13458     // now write to memory in proper format.....
13459 
13460     int pos = (int) dstCN;
13461 
13462     // 1st, take care of any leading sign .......
13463     switch(e->S3)
13464     {
13465         case CSFL:  // floating-point, leading sign.
13466         case CSLS:  // fixed-point, leading sign
13467             switch(dstTN)
13468             {
13469                 case CTN4:
13470                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
13471                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13472                     else
13473                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13474                     break;
13475                 case CTN9:
13476                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13477                     break;
13478             }
13479             break;
13480 
13481         case CSTS:  // nuttin' to do here .....
13482         case CSNS:
13483             break;  // no sign wysiwyg
13484     }
13485 
13486     // 2nd, write the digits .....
13487     for(int i = 0 ; i < n3 ; i++)
13488         switch(dstTN)
13489         {
13490             case CTN4:
13491                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13492                 break;
13493             case CTN9:
13494                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13495                 break;
13496             }
13497 
13498     // 3rd, take care of any trailing sign or exponent ...
13499     switch(e->S3)
13500     {
13501         case CSTS:  // write trailing sign ....
13502             switch(dstTN)
13503             {
13504                 case CTN4:
13505                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus sign character is placed appropriately if the result of the operation is positive.
13506                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13507                     else
13508                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13509                     break;
13510                 case CTN9:
13511                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13512                 break;
13513             }
13514             break;
13515 
13516         case CSFL:  // floating-point, leading sign.
13517             // write the exponent
13518             switch(dstTN)
13519             {
13520                 case CTN4:
13521                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13522                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13523                     break;
13524                 case CTN9:
13525                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13526                     break;
13527             }
13528             break;
13529 
13530         case CSLS:  // fixed point, leading sign - already done
13531         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13532             break;
13533     }
13534 
13535     // set flags, etc ...
13536     if (e->S3 == CSFL)
13537     {
13538         if (op3->exponent > 127)
13539         {
13540             SET_I_EOFL;
13541             EOvr = true;
13542         }
13543         if (op3->exponent < -128)
13544         {
13545             SET_I_EUFL;
13546             EOvr = true;
13547         }
13548     }
13549 
13550     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13551     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13552 
13553     // SC_I_TRUNC(!R && Trunc); // no truncation flag for divide
13554 
13555     cleanupOperandDescriptor (1);
13556     cleanupOperandDescriptor (2);
13557     cleanupOperandDescriptor (3);
13558 
13559     //if (TST_I_TRUNC && T && tstOVFfault ())
13560     //  doFault(FAULT_OFL, fst_zero, "dv3d truncation(overflow) fault");
13561     if (EOvr && tstOVFfault ())
13562         doFault(FAULT_OFL, fst_zero, "dv3d over/underflow fault");
13563     if (Ovr)
13564     {
13565         SET_I_OFLOW;
13566         if (tstOVFfault ())
13567           doFault(FAULT_OFL, fst_zero, "dv3d overflow fault");
13568     }
13569 }

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