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-2022 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 // XXX ticket #31
 718 // This a little brute force; it we fault on the next read, the cached value
 719 // is lost. There might be a way to logic it up so that when the next read
 720 // word offset changes, then we write the cache before doing the read. For
 721 // right now, be pessimistic. Sadly, since this is a bit loop, it is very.
 722     if (flush)
 723       {
 724         EISWriteCache (p);
 725       }
 726 }
 727 
 728 static word36 EISReadIdx (EISaddr * p, uint n)
     /* [previous][next][first][last][top][bottom][index][help] */
 729   {
 730 #ifdef EIS_PTR
 731     long eisaddr_idx = EISADDR_IDX (p);
 732 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 733 
 734     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadIdx addr %06o n %u\n", cpu.du.Dk_PTR_W[eisaddr_idx], n);
 735     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 736 #else
 737     long eisaddr_idx = EISADDR_IDX (p);
 738     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadIdx %ld addr %06o n %u\n", eisaddr_idx, p->address, n);
 739     word18 addressN = p -> address + n;
 740 #endif
 741     addressN &= AMASK;
 742 
 743     word18 paragraphAddress = addressN & paragraphMask;
 744     word3 paragraphOffset = addressN & paragraphOffsetMask;
 745 
 746     if (p -> cacheValid && p -> cachedAddr == paragraphAddress)
 747       {
 748         return p -> cachedParagraph [paragraphOffset];
 749       }
 750     if (p -> cacheValid && p -> cacheDirty)
 751       {
 752         EISWriteCache (p);
 753       }
 754     EISReadCache (p, paragraphAddress);
 755     return p -> cachedParagraph [paragraphOffset];
 756   }
 757 
 758 static word36 EISRead (EISaddr * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 759   {
 760 #ifdef EIS_PTR
 761     long eisaddr_idx = EISADDR_IDX (p);
 762 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 763 
 764     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISRead addr %06o\n", cpu.du.Dk_PTR_W[eisaddr_idx]);
 765 #else
 766     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISRead addr %06o\n", p->address);
 767 #endif
 768     return EISReadIdx (p, 0);
 769   }
 770 
 771 
 772 
 773 
 774 
 775 
 776 
 777 
 778 
 779 
 780 
 781 
 782 
 783 
 784 
 785 
 786 
 787 
 788 static void EISReadPage (EISaddr * p, uint n, word36 * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 789   {
 790 #ifdef EIS_PTR
 791     long eisaddr_idx = EISADDR_IDX (p);
 792 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 793     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 794 #else
 795     word18 addressN = p -> address + n;
 796 #endif
 797     addressN &= AMASK;
 798 
 799     sim_debug (DBG_TRACEEXT, & cpu_dev, "%s addr %06o\n", __func__, addressN);
 800     if ((addressN & PGMK) != 0)
 801       {
 802         sim_warn ("EISReadPage not aligned %06o\n", addressN);
 803         addressN &= (word18) ~PGMK;
 804       }
 805 
 806     word3 saveTRR = cpu.TPR.TRR;
 807 
 808     if (p -> mat == viaPR)
 809       {
 810         cpu.TPR.TRR = p -> RNR;
 811         cpu.TPR.TSR = p -> SNR;
 812         cpu.cu.XSF = 0;
 813         ReadPage (addressN, data, true);
 814 
 815         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 816           {
 817             for (uint i = 0; i < PGSZ; i ++)
 818 #ifdef EIS_PTR
 819               sim_debug (DBG_TRACEEXT, & cpu_dev,
 820                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 821                            __func__, data [i], cpu.TPR.TSR, addressN + i);
 822 #else
 823               sim_debug (DBG_TRACEEXT, & cpu_dev,
 824                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 825                            __func__, data [i], p -> SNR, addressN + i);
 826 #endif
 827           }
 828       }
 829     else
 830       {
 831         //if (get_addr_mode() == APPEND_mode)
 832           //{
 833         cpu.TPR.TRR = cpu.PPR.PRR;
 834         cpu.TPR.TSR = cpu.PPR.PSR;
 835         cpu.cu.XSF = 0;
 836           //}
 837 
 838         ReadPage (addressN, data, false);
 839         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 840           {
 841             for (uint i = 0; i < PGSZ; i ++)
 842               sim_debug (DBG_TRACEEXT, & cpu_dev,
 843                          "%s: %012"PRIo64"@%o:%06o\n",
 844                          __func__, data [i], cpu.TPR.TSR, addressN + i);
 845           }
 846       }
 847     cpu.TPR.TRR = saveTRR;
 848   }
 849 
 850 static void EISWritePage (EISaddr * p, uint n, word36 * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 851   {
 852 #ifdef EIS_PTR
 853     long eisaddr_idx = EISADDR_IDX (p);
 854 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 855     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 856 #else
 857     word18 addressN = p -> address + n;
 858 #endif
 859     addressN &= AMASK;
 860 
 861     sim_debug (DBG_TRACEEXT, & cpu_dev, "%s addr %06o\n", __func__, addressN);
 862     if ((addressN & PGMK) != 0)
 863       {
 864         sim_warn ("EISWritePage not aligned %06o\n", addressN);
 865         addressN &= (uint) ~PGMK;
 866       }
 867 
 868     word3 saveTRR = cpu.TPR.TRR;
 869 
 870     if (p -> mat == viaPR)
 871       {
 872         cpu.TPR.TRR = p -> RNR;
 873         cpu.TPR.TSR = p -> SNR;
 874         cpu.cu.XSF = 0;
 875         WritePage (addressN, data, true);
 876 
 877         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 878           {
 879             for (uint i = 0; i < PGSZ; i ++)
 880 #ifdef EIS_PTR
 881               sim_debug (DBG_TRACEEXT, & cpu_dev,
 882                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 883                            __func__, data [i], cpu.TPR.TSR, addressN + i);
 884 #else
 885               sim_debug (DBG_TRACEEXT, & cpu_dev,
 886                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 887                            __func__, data [i], p -> SNR, addressN + i);
 888 #endif
 889           }
 890       }
 891     else
 892       {
 893         //if (get_addr_mode() == APPEND_mode)
 894           //{
 895         cpu.TPR.TRR = cpu.PPR.PRR;
 896         cpu.TPR.TSR = cpu.PPR.PSR;
 897         cpu.cu.XSF = 0;
 898           //}
 899 
 900         WritePage (addressN, data, false);
 901         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 902           {
 903             for (uint i = 0; i < PGSZ; i ++)
 904               sim_debug (DBG_TRACEEXT, & cpu_dev,
 905                          "%s: %012"PRIo64"@%o:%06o\n",
 906                          __func__, data [i], cpu.TPR.TSR, addressN + i);
 907           }
 908       }
 909     cpu.TPR.TRR = saveTRR;
 910   }
 911 
 912 static word9 EISget469 (int k, uint i)
     /* [previous][next][first][last][top][bottom][index][help] */
 913   {
 914     EISstruct * e = & cpu.currentEISinstruction;
 915 
 916     uint nPos = 4; // CTA9
 917 #ifdef EIS_PTR3
 918     switch (cpu.du.TAk[k-1])
 919 #else
 920     switch (e -> TA [k - 1])
 921 #endif
 922       {
 923         case CTA4:
 924             nPos = 8;
 925             break;
 926 
 927         case CTA6:
 928             nPos = 6;
 929             break;
 930       }
 931 
 932     word18 address = e -> WN [k - 1];
 933     uint nChars = i + e -> CN [k - 1];
 934 
 935     address += nChars / nPos;
 936     uint residue = nChars % nPos;
 937 
 938     PNL (cpu.du.Dk_PTR_W[k-1] = address);
 939 #ifdef EIS_PTR
 940     cpu.du.Dk_PTR_W[k-1] = address;
 941 #else
 942     e -> addr [k - 1].address = address;
 943 #endif
 944     word36 data = EISRead (& e -> addr [k - 1]);    // read it from memory
 945 
 946     word9 c = 0;
 947 #ifdef EIS_PTR3
 948     switch (cpu.du.TAk[k-1])
 949 #else
 950     switch (e -> TA [k - 1])
 951 #endif
 952       {
 953         case CTA4:
 954           c = (word9) get4 (data, (int) residue);
 955           break;
 956 
 957         case CTA6:
 958           c = (word9) get6 (data, (int) residue);
 959           break;
 960 
 961         case CTA9:
 962           c = get9 (data, (int) residue);
 963           break;
 964       }
 965 #ifdef EIS_PTR3
 966     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISGet469 : k: %u TAk %u coffset %u c %o \n", k, cpu.du.TAk[k - 1], residue, c);
 967 #else
 968     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISGet469 : k: %u TAk %u coffset %u c %o \n", k, e -> TA [k - 1], residue, c);
 969 #endif
 970 
 971     return c;
 972   }
 973 
 974 static void EISput469 (int k, uint i, word9 c469)
     /* [previous][next][first][last][top][bottom][index][help] */
 975   {
 976     EISstruct * e = & cpu.currentEISinstruction;
 977 
 978     uint nPos = 4; // CTA9
 979 #ifdef EIS_PTR3
 980     switch (cpu.du.TAk[k-1])
 981 #else
 982     switch (e -> TA [k - 1])
 983 #endif
 984       {
 985         case CTA4:
 986           nPos = 8;
 987           break;
 988 
 989         case CTA6:
 990           nPos = 6;
 991           break;
 992       }
 993 
 994     word18 address = e -> WN [k - 1];
 995     uint nChars = i + e -> CN [k - 1];
 996 
 997     address += nChars / nPos;
 998     uint residue = nChars % nPos;
 999 
1000     PNL (cpu.du.Dk_PTR_W[k-1] = address);
1001 #ifdef EIS_PTR
1002     cpu.du.Dk_PTR_W[k-1] = address;
1003 #else
1004     e -> addr [k - 1].address = address;
1005 #endif
1006     word36 data = EISRead (& e -> addr [k - 1]);    // read it from memory
1007 
1008     word36 w = 0;
1009 #ifdef EIS_PTR3
1010     switch (cpu.du.TAk[k-1])
1011 #else
1012     switch (e -> TA [k - 1])
1013 #endif
1014       {
1015         case CTA4:
1016           w = put4 (data, (int) residue, (word4) c469);
1017           break;
1018 
1019         case CTA6:
1020           w = put6 (data, (int) residue, (word6) c469);
1021           break;
1022 
1023         case CTA9:
1024           w = put9 (data, (int) residue, c469);
1025           break;
1026       }
1027     EISWriteIdx (& e -> addr [k - 1], 0, w, true);
1028   }
1029 
1030 /*
1031  * return a 4- or 9-bit character at memory "*address" and position "*pos".
1032  * Increment pos (and address if necessary)
1033  */
1034 
1035 static word9 EISget49 (EISaddr * p, int * pos, int tn)
     /* [previous][next][first][last][top][bottom][index][help] */
1036   {
1037     int maxPos = tn == CTN4 ? 7 : 3;
1038 
1039     if (* pos > maxPos)        // overflows to next word?
1040       {   // yep....
1041         * pos = 0;        // reset to 1st byte
1042         // bump source to next address
1043 #ifdef EIS_PTR
1044         long eisaddr_idx = EISADDR_IDX (p);
1045 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
1046         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;
1047 #else
1048         p -> address = (p -> address + 1) & AMASK;
1049 #endif
1050         p -> data = EISRead (p);    // read it from memory
1051       }
1052     else
1053       {
1054         p -> data = EISRead (p);   // read data word from memory
1055       }
1056 
1057     word9 c = 0;
1058     switch (tn)
1059       {
1060         case CTN4:
1061           c = get4 (p -> data, * pos);
1062           break;
1063         case CTN9:
1064           c = get9 (p -> data, * pos);
1065           break;
1066       }
1067 
1068     (* pos) ++;
1069     return c;
1070   }
1071 
1072 static bool EISgetBitRWN (EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
1073   {
1074 #ifdef EIS_PTR
1075     long eisaddr_idx = EISADDR_IDX (p);
1076 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
1077 
1078 #endif
1079     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
1080     int baseBitPosn = baseCharPosn + p -> bPos;
1081     baseBitPosn += (int) cpu.du.CHTALLY;
1082 
1083     int bitPosn = baseBitPosn % 36;
1084     int woff = baseBitPosn / 36;
1085 
1086 #ifdef EIS_PTR
1087     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
1088     cpu.du.Dk_PTR_W[eisaddr_idx] += (uint) woff;
1089     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
1090 #else
1091     word18 saveAddr = p -> address;
1092     p -> address += (uint) woff;
1093 #endif
1094 
1095     p -> data = EISRead (p); // read data word from memory
1096 
1097     if (p -> mode == eRWreadBit)
1098       {
1099         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
1100       }
1101     else if (p -> mode == eRWwriteBit)
1102       {
1103         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
1104 
1105         EISWriteIdx (p, 0, p -> data, flush); // write data word to memory
1106       }
1107 
1108     p->last_bit_posn = bitPosn;
1109 
1110 #ifdef EIS_PTR
1111     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
1112 #else
1113     p -> address = saveAddr;
1114 #endif
1115     return p -> bit;
1116   }
1117 
1118 static void setupOperandDescriptorCache (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
1119   {
1120     EISstruct * e = & cpu.currentEISinstruction;
1121     e -> addr [k - 1]. cacheValid = false;
1122   }
1123 
1124 //
1125 // 5.2.10.5  Operand Descriptor Address Preparation Flowchart
1126 //
1127 // A flowchart of the operations involved in operand descriptor address
1128 // preparation is shown in Figure 5-2. The chart depicts the address
1129 // preparation for operand descriptor 1 of a multiword instruction as described
1130 // by modification field 1 (MF1). A similar type address preparation would be
1131 // carried out for each operand descriptor as specified by its MF code.
1132 //    (Bull Nova 9000 pg 5-40  67 A2 RJ78 REV02)
1133 //
1134 // 1. The multiword instruction is obtained from memory.
1135 //
1136 // 2. The indirect (ID) bit of MF1 is queried to determine if the descriptor
1137 // for operand 1 is present or is an indirect word.
1138 //
1139 // 3. This step is reached only if an indirect word was in the operand
1140 // descriptor location. Address modification for the indirect word is now
1141 // performed. If the AR bit of the indirect word is 1, address register
1142 // modification step 4 is performed.
1143 //
1144 // 4. The y field of the indirect word is added to the contents of the
1145 // specified address register.
1146 //
1147 // 5. A check is now made to determine if the REG field of the indirect word
1148 // specifies that a register type modification be performed.
1149 //
1150 // 6. The indirect address as modified by the address register is now modified
1151 // by the contents of the specified register, producing the effective address
1152 // of the operand descriptor.
1153 //
1154 // 7. The operand descriptor is obtained from the location determined by the
1155 // generated effective address in item 6.
1156 //
1157 
1158 static void setupOperandDescriptor (int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1159   {
1160     EISstruct * e = & cpu.currentEISinstruction;
1161     switch (k)
1162       {
1163         case 1:
1164           PNL (L68_ (DU_CYCLE_FA_I1;))
1165           PNL (L68_ (DU_CYCLE_GDLDA;))
1166           e -> MF1 = getbits36_7 (cpu.cu.IWB, 29);
1167           break;
1168         case 2:
1169           PNL (L68_ (DU_CYCLE_FA_I2;))
1170           PNL (L68_ (DU_CYCLE_GDLDB;))
1171           e -> MF2 = getbits36_7 (cpu.cu.IWB, 11);
1172           break;
1173         case 3:
1174           PNL (L68_ (DU_CYCLE_FA_I3;))
1175           PNL (L68_ (DU_CYCLE_GDLDC;))
1176           e -> MF3 = getbits36_7 (cpu.cu.IWB,  2);
1177           break;
1178       }
1179 
1180     word18 MFk = e -> MF [k - 1];
1181 
1182     if (MFk & MFkID)
1183     {
1184         PNL (L68_ (if (k == 1)
1185                      DU_CYCLE_LDWRT1;
1186                    if (k == 2)
1187                      DU_CYCLE_LDWRT2;))
1188 
1189         word36 opDesc = e -> op [k - 1];
1190 
1191 // 18-28 MBZ check breaks Multics; line 161 of sys_trouble.alm contains
1192 //
1193 // 000103 aa 040100 1006 20    160   mlr     (id),(pr),fill(040) copy error message
1194 // 000104 0a 000126 0002 05    161   arg     trouble_messages-1,al
1195 // 000105 aa 300063 200063     162   desc9a  bb|fgbx.message+3(1),64-13
1196 //
1197 // bit 28 of 000104 is set
1198 //
1199 
1200 
1201 
1202 
1203 
1204 
1205 
1206 
1207 
1208 
1209 
1210 
1211 
1212 
1213 
1214 
1215 
1216 
1217 
1218 
1219 
1220 
1221         // Bits 30, 31 MBZ
1222         // RJ78 p. 5-39, ISOLTS 840 07a,07b
1223         if (opDesc & 060)
1224           {
1225             *mod_fault |= FR_ILL_MOD;
1226             //doFault (FAULT_IPR, fst_ill_mod, "setupOperandDescriptor 30,31 MBZ");
1227           }
1228 
1229         // fill operand according to MFk....
1230         word18 address = GETHI (opDesc);
1231         PNL (cpu.du.Dk_PTR_W[k-1] = address);
1232 #ifdef EIS_PTR
1233         cpu.du.Dk_PTR_W[k-1] = address;
1234 #else
1235         e -> addr [k - 1].address = address;
1236 #endif
1237 
1238         // Indirect descriptor control. If ID = 1 for Mfk, then the kth word
1239         // following the instruction word is an indirect pointer to the operand
1240         // descriptor for the kth operand; otherwise, that word is the operand
1241         // descriptor.
1242         //
1243         // If MFk.ID = 1, then the kth word following an EIS multiword
1244         // instruction word is not an operand descriptor, but is an indirect
1245         // pointer to an operand descriptor and is interpreted as shown in
1246         // Figure 4-5.
1247 
1248         // Mike Mondy michael.mondy@coffeebird.net sez' ...
1249         // EIS indirect pointers to operand descriptors use PR registers.
1250         // However, operand descriptors use AR registers according to the
1251         // description of the AR registers and the description of EIS operand
1252         // descriptors. However, the description of the MF field
1253         // claims that operands use PR registers. The AR doesn't have a
1254         // segment field. Emulation confirms that operand descriptors
1255         // need to be fetched via segments given in PR registers.
1256 
1257         bool a = opDesc & (1 << 6);
1258         if (a)
1259           {
1260             // A 3-bit pointer register number (n) and a 15-bit offset relative
1261             // to C(PRn.WORDNO) if A = 1 (all modes)
1262             word3 n = (word3) getbits18 (address, 0, 3);
1263             CPTUR (cptUsePRn + n);
1264             word15 offset = address & MASK15;  // 15-bit signed number
1265             address = (cpu.AR [n].WORDNO + SIGNEXT15_18 (offset)) & AMASK;
1266 
1267             PNL (cpu.du.Dk_PTR_W[k-1] = address);
1268 #ifdef EIS_PTR
1269             cpu.du.Dk_PTR_W[k-1] = address;
1270 #else
1271             e -> addr [k - 1].address = address;
1272 #endif
1273             cpu.cu.TSN_PRNO[k-1] = n;
1274             cpu.cu.TSN_VALID[k-1] = 1;
1275             e -> addr [k - 1].SNR = cpu.PR [n].SNR;
1276             e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR,
1277                                             cpu.TPR.TRR,
1278                                             cpu.PPR.PRR);
1279 
1280             e -> addr [k - 1].mat = viaPR;   // ARs involved
1281 sim_debug (DBG_TRACEEXT, & cpu_dev, "AR n %u k %u\n", n, k - 1);
1282           }
1283         else
1284           {
1285             e->addr [k - 1].mat = OperandRead;      // no ARs involved yet
1286 sim_debug (DBG_TRACEEXT, & cpu_dev, "No ARb %u\n", k - 1);
1287           }
1288 
1289         // Address modifier for ADDRESS. All register modifiers except du and
1290         // dl may be used. If the ic modifier is used, then ADDRESS is an
1291         // 18-bit offset relative to value of the instruction counter for the
1292         // instruction word. C(REG) is always interpreted as a word offset. REG
1293 
1294         uint reg = opDesc & 017;
1295         // XXX RH03/RJ78 say a,q modifiers are also available here. AL39 says al/ql only
1296         address += getMFReg18 (reg, false, true, mod_fault); // ID=1: disallow du, allow n,ic
1297         address &= AMASK;
1298 
1299         PNL (cpu.du.Dk_PTR_W[k-1] = address);
1300 
1301 #ifdef EIS_PTR
1302         cpu.du.Dk_PTR_W[k-1] = address;
1303 #else
1304         e -> addr [k - 1].address = address;
1305 #endif
1306 
1307         // read EIS operand .. this should be an indirectread
1308         e -> op [k - 1] = EISRead (& e -> addr [k - 1]);
1309     }
1310     else
1311     {
1312           e->addr [k - 1].mat = OperandRead;      // no ARs involved yet
1313 sim_debug (DBG_TRACEEXT, & cpu_dev, "No ARa %u\n", k - 1);
1314     }
1315     setupOperandDescriptorCache (k);
1316 }
1317 
1318 void setupEISoperands (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1319   {
1320     PNL (cpu.du.POP = 0);
1321     PNL (cpu.du.POL = 0);
1322 
1323 #ifdef EIS_SETUP
1324     for (int i = 0; i < 3; i ++)
1325       {
1326         if (i < cpu.currentInstruction.info -> ndes)
1327           setupOperandDescriptor (i + 1);
1328         else
1329           setupOperandDescriptorCache (i + 1);
1330       }
1331 #endif
1332   }
1333 
1334 static void parseAlphanumericOperandDescriptor (uint k, uint useTA, bool allowDU, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1335   {
1336     EISstruct * e = & cpu.currentEISinstruction;
1337     word18 MFk = e -> MF [k - 1];
1338 
1339     PNL (L68_ (if (k == 1)
1340       DU_CYCLE_ANLD1;
1341     else if (k == 2)
1342       DU_CYCLE_ANLD2;
1343     else if (k == 3)
1344       DU_CYCLE_ANSTR;))
1345 
1346     PNL (cpu.du.POP = 1);
1347 
1348     word36 opDesc = e -> op [k - 1];
1349 
1350     word8 ARn_CHAR = 0;
1351     word6 ARn_BITNO = 0;
1352 
1353     word18 address = GETHI (opDesc);
1354 
1355 #ifdef EIS_PTR3
1356     if (useTA != k)
1357       cpu.du.TAk[k-1] = cpu.du.TAk[useTA-1];
1358     else
1359       cpu.du.TAk[k-1] = getbits36_2 (opDesc, 21);    // type alphanumeric
1360 #else
1361     if (useTA != k)
1362       e -> TA [k - 1] = e -> TA [useTA - 1];
1363     else
1364       e -> TA [k - 1] = getbits36_2 (opDesc, 21);    // type alphanumeric
1365 #endif
1366 
1367 #ifdef PANEL68
1368     if (k == 1) // Use data from first operand
1369       {
1370         switch (e->TA[0])
1371           {
1372             case CTA9:
1373               cpu.dataMode = 0102; // 9 bit an
1374               cpu.ou.opsz = is_9 >> 12;
1375               break;
1376             case CTA6:
1377               cpu.dataMode = 0042; // 6 bit an
1378               cpu.ou.opsz = is_6 >> 12;
1379               break;
1380             case CTA4:
1381               cpu.dataMode = 0022; // 4 bit an
1382               cpu.ou.opsz = is_4 >> 12;
1383               break;
1384           }
1385       }
1386 #endif
1387 
1388 // 8. Modification of the operand descriptor address begins. This step is
1389 // reached directly from 2 if no indirection is involved. The AR bit of MF1 is
1390 // checked to determine if address register modification is specified.
1391 //
1392 // 9. Address register modification is performed on the operand descriptor as
1393 // described under "Address Modification with Address Registers" above. The
1394 // character and bit positions of the specified address register are used in
1395 // one of two ways, depending on the type of operand descriptor, i.e., whether
1396 // the type is a bit string, a numeric, or an alphanumeric descriptor.
1397 //
1398 // 10. The REG field of MF1 is checked for a legal code. If DU is specified in
1399 // the REG field of MF2 in one of the four multiword instructions (SCD, SCDR,
1400 // SCM, or SCMR) for which DU is legal, the CN field is ignored and the
1401 // character or characters are arranged within the 18 bits of the word address
1402 // portion of the operand descriptor.
1403 //
1404 // 11. The count contained in the register specified by the REG field code is
1405 // appropriately converted and added to the operand address.
1406 //
1407 // 12. The operand is retrieved from the calculated effective address location.
1408 //
1409 
1410     if (MFk & MFkAR)
1411       {
1412         // if MKf contains ar then it Means Y-charn is not the memory address
1413         // of the data but is a reference to a pointer register pointing to the
1414         // data.
1415         word3 n = (word3) getbits18 (address, 0, 3);
1416         CPTUR (cptUsePRn + n);
1417         word18 offset = SIGNEXT15_18 ((word15) address);  // 15-bit signed number
1418         address = (cpu.AR [n].WORDNO + offset) & AMASK;
1419 
1420         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1421         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1422 
1423         cpu.cu.TSN_PRNO[k-1] = n;
1424         cpu.cu.TSN_VALID[k-1] = 1;
1425         e -> addr [k - 1].SNR = cpu.PR [n].SNR;
1426         e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1427 
1428         e -> addr [k - 1].mat = viaPR;   // ARs involved
1429 sim_debug (DBG_TRACEEXT, & cpu_dev, "AR n %u k %u\n", n, k - 1);
1430       }
1431 
1432     PNL (cpu.du.POL = 1);
1433 
1434     uint CN = getbits36_3 (opDesc, 18);    // character number
1435 
1436     sim_debug (DBG_TRACEEXT, & cpu_dev, "initial CN%u %u\n", k, CN);
1437 
1438     if (MFk & MFkRL)
1439     {
1440         uint reg = opDesc & 017;
1441 // XXX Handle N too big intelligently....
1442         e -> N [k - 1] = (uint) getMFReg36 (reg, false, false, mod_fault); // RL=1: disallow du,n,ic
1443 #ifdef EIS_PTR3
1444         switch (cpu.du.TAk[k-1])
1445 #else
1446         switch (e -> TA [k - 1])
1447 #endif
1448           {
1449             case CTA4:
1450               e -> N [k - 1] &= 017777777; // 22-bits of length
1451               break;
1452 
1453             case CTA6:
1454             case CTA9:
1455               e -> N [k - 1] &= 07777777;  // 21-bits of length.
1456               break;
1457 
1458             default:
1459               L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TA 3");)
1460               // DPS8M
1461               *mod_fault |= FR_ILL_PROC;
1462               break;
1463           }
1464       }
1465     else
1466       e -> N [k - 1] = opDesc & 07777;
1467 
1468     //if (e->N [k - 1] == 0)
1469       //doFault (FAULT_IPR, FR_ILL_PROC, "parseAlphanumericOperandDescriptor N 0");
1470 
1471     sim_debug (DBG_TRACEEXT, & cpu_dev, "N%u %o\n", k, e->N[k-1]);
1472 
1473     word36 r = getMFReg36 (MFk & 017, allowDU, true, mod_fault); // allow du based on instruction, allow n,ic
1474 
1475     if ((MFk & 017) == 4)   // reg == IC ?
1476       {
1477         address += r;
1478         address &= AMASK;
1479         r = 0;
1480       }
1481 
1482     // If seems that the effect address calcs given in AL39 p.6-27 are not
1483     // quite right. E.g. For CTA4/CTN4 because of the 4 "slop" bits you need
1484     // to do 32-bit calcs not 36-bit!
1485     uint effBITNO = 0;
1486     uint effCHAR = 0;
1487     uint effWORDNO = 0;
1488 
1489 #ifdef EIS_PTR3
1490     switch (cpu.du.TAk[k-1])
1491 #else
1492     switch (e -> TA [k - 1])
1493 #endif
1494       {
1495         case CTA4:
1496           {
1497             // Calculate character number of ARn CHAR and BITNO
1498             uint bitoffset = ARn_CHAR * 9u + ARn_BITNO;
1499             uint arn_char4 = bitoffset * 2 / 9; // / 4.5
1500             // 8 chars per word plus the number of chars in r, plus the
1501             // number of chars in ARn CHAR/BITNO plus the CN from the operand
1502 // XXX Handle 'r' too big intelligently...
1503             uint nchars = address * 8 + (uint) r + arn_char4 + CN;
1504 
1505             effWORDNO = nchars / 8; // 8 chars/word
1506             effCHAR = nchars % 8; // effCHAR is the 4 bit char number, not
1507                                   // the 9-bit char no
1508             effBITNO = (nchars & 1) ? 5 : 0;
1509 
1510             effWORDNO &= AMASK;
1511 
1512             e -> CN [k - 1] = effCHAR;
1513             e -> WN [k - 1] = effWORDNO;
1514 
1515             sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA4\n",
1516                        k, e -> CN [k - 1]);
1517           }
1518           break;
1519 
1520         case CTA6:
1521           if (CN >= 6) {
1522             L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TAn CTA6 CN >= 6");)
1523             // DPS8M
1524             *mod_fault |= FR_ILL_PROC;
1525           }
1526           effBITNO = (9u * ARn_CHAR + 6u * r + ARn_BITNO) % 9u;
1527           effCHAR = ((6u * CN +
1528                       9u * ARn_CHAR +
1529                       6u * r + ARn_BITNO) % 36u) / 6u;//9;
1530           effWORDNO = (uint) (address +
1531                            (6u * CN +
1532                             9u * ARn_CHAR +
1533                             6u * r +
1534                             ARn_BITNO) / 36u);
1535           effWORDNO &= AMASK;
1536 
1537           e -> CN [k - 1] = effCHAR;   // ??????
1538           e -> WN [k - 1] = effWORDNO;
1539           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA6\n",
1540                      k, e -> CN [k - 1]);
1541           break;
1542 
1543         case CTA9:
1544           if (CN & 01) {
1545             L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor CTA9 & CN odd");)
1546             // DPS8M
1547             *mod_fault |= FR_ILL_PROC;
1548           }
1549           CN = (CN >> 1);
1550 
1551           effBITNO = 0;
1552           effCHAR = (CN + ARn_CHAR + r) % 4;
1553           sim_debug (DBG_TRACEEXT, & cpu_dev,
1554                      "effCHAR %d = (CN %d + ARn_CHAR %d + r %"PRId64") %% 4)\n",
1555                      effCHAR, CN, ARn_CHAR, r);
1556           effWORDNO = (uint) (address +
1557                            ((9u * CN +
1558                              9u * ARn_CHAR +
1559                              9u * r +
1560                              ARn_BITNO) / 36u));
1561           effWORDNO &= AMASK;
1562 
1563           e -> CN [k - 1] = effCHAR;   // ??????
1564           e -> WN [k - 1] = effWORDNO;
1565           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA9\n",
1566                      k, e -> CN [k - 1]);
1567           break;
1568 
1569         default:
1570           L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TA1 3");)
1571           // DPS8M
1572           *mod_fault |= FR_ILL_PROC;
1573           break;
1574     }
1575 
1576     EISaddr * a = & e -> addr [k - 1];
1577     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1578 #ifdef EIS_PTR
1579     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1580 #else
1581     a -> address = effWORDNO;
1582 #endif
1583     a -> cPos= (int) effCHAR;
1584     a -> bPos = (int) effBITNO;
1585 
1586 #ifndef EIS_PTR3
1587     // a->_type = eisTA;
1588     a -> TA = (int) e -> TA [k - 1];
1589 #endif
1590   }
1591 
1592 static void parseArgOperandDescriptor (uint k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1593   {
1594     PNL (L68_ (if (k == 1)
1595       DU_CYCLE_NLD1;
1596     else if (k == 2)
1597       DU_CYCLE_NLD2;
1598     else if (k == 3)
1599       DU_CYCLE_GSTR;))
1600 
1601     EISstruct * e = & cpu.currentEISinstruction;
1602     word36 opDesc = e -> op [k - 1];
1603     word18 y = GETHI (opDesc);
1604     word1 yA = GET_A (opDesc);
1605 
1606     uint yREG = opDesc & 0xf;
1607 
1608     word36 r = getMFReg36 (yREG, false, true, mod_fault); // disallow du, allow n,ic
1609 
1610     word8 ARn_CHAR = 0;
1611     word6 ARn_BITNO = 0;
1612 
1613     PNL (cpu.du.POP = 1);
1614 
1615     if (yA)
1616       {
1617         // if operand contains A (bit-29 set) then it Means Y-char9n is not
1618         // the memory address of the data but is a reference to a pointer
1619         // register pointing to the data.
1620         word3 n = GET_ARN (opDesc);
1621         CPTUR (cptUsePRn + n);
1622         word15 offset = y & MASK15;  // 15-bit signed number
1623         y = (cpu.AR [n].WORDNO + SIGNEXT15_18 (offset)) & AMASK;
1624 
1625         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1626         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1627 
1628         cpu.cu.TSN_PRNO[k-1] = n;
1629         cpu.cu.TSN_VALID[k-1] = 1;
1630         e -> addr [k - 1].SNR = cpu.PR[n].SNR;
1631         e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1632         e -> addr [k - 1].mat = viaPR;
1633       }
1634 
1635     y += ((9u * ARn_CHAR + 36u * r + ARn_BITNO) / 36u);
1636     y &= AMASK;
1637 
1638     PNL (cpu.du.Dk_PTR_W[k-1] = y);
1639 
1640 #ifdef EIS_PTR
1641     cpu.du.Dk_PTR_W[k-1] = y;
1642 #else
1643     e -> addr [k - 1].address = y;
1644 #endif
1645   }
1646 
1647 static void parseNumericOperandDescriptor (int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1648 {
1649     PNL (L68_ (if (k == 1)
1650       DU_CYCLE_NLD1;
1651     else if (k == 2)
1652       DU_CYCLE_NLD2;
1653     else if (k == 3)
1654       DU_CYCLE_GSTR;))
1655 
1656     EISstruct * e = & cpu.currentEISinstruction;
1657     word18 MFk = e->MF[k-1];
1658 
1659     PNL (cpu.du.POP = 1);
1660 
1661     word36 opDesc = e->op[k-1];
1662 
1663     word8 ARn_CHAR = 0;
1664     word6 ARn_BITNO = 0;
1665 
1666     word18 address = GETHI(opDesc);
1667     if (MFk & MFkAR)
1668     {
1669         // if MKf contains ar then it Means Y-charn is not the memory address
1670         // of the data but is a reference to a pointer register pointing to the
1671         // data.
1672         word3 n = (word3) getbits18 (address, 0, 3);
1673         CPTUR (cptUsePRn + n);
1674         word15 offset = address & MASK15;  // 15-bit signed number
1675         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1676 
1677         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1678         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1679 
1680         cpu.cu.TSN_PRNO[k-1] = n;
1681         cpu.cu.TSN_VALID[k-1] = 1;
1682         e->addr[k-1].SNR = cpu.PR[n].SNR;
1683         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1684 
1685         e->addr[k-1].mat = viaPR;   // ARs involved
1686     }
1687 
1688     PNL (cpu.du.POL = 1);
1689 
1690     word3 CN = getbits36_3 (opDesc, 18);    // character number
1691     e->TN[k-1] = getbits36_1 (opDesc, 21); // type numeric
1692 
1693 #ifdef PANEL68
1694     if (k == 1)
1695       {
1696         if (e->TN[0])
1697           cpu.dataMode = 0021; // 4 bit numeric
1698         else
1699           cpu.dataMode = 0101; // 9 bit numeric
1700       }
1701 #endif
1702 
1703     e->S[k-1]  = getbits36_2 (opDesc, 22);    // Sign and decimal type of data
1704     e->SF[k-1] = SIGNEXT6_int (getbits36_6 (opDesc, 24));    // Scaling factor.
1705 
1706     // Operand length. If MFk.RL = 0, this field contains the operand length in
1707     // digits. If MFk.RL = 1, it contains the REG code for the register holding
1708     // the operand length and C(REG) is treated as a 0 modulo 64 number. See
1709     // Table 4-1 and EIS modification fields (MF) above for a discussion of
1710     // register codes.
1711 
1712     if (MFk & MFkRL)
1713     {
1714         uint reg = opDesc & 017;
1715         e->N[k-1] = getMFReg18(reg, false, false, mod_fault) & 077; // RL=1: disallow du,n,ic
1716     }
1717     else
1718         e->N[k-1] = opDesc & 077;
1719 
1720     sim_debug (DBG_TRACEEXT, & cpu_dev, "parseNumericOperandDescriptor(): N%u %0o\n", k, e->N[k-1]);
1721 
1722     word36 r = getMFReg36(MFk & 017, false, true, mod_fault); // disallow du, allow n, ic
1723     if ((MFk & 017) == 4)   // reg == IC ?
1724     {
1725         address += r;
1726         address &= AMASK;
1727         r = 0;
1728     }
1729 
1730 // handled in numeric instructions
1731 
1732 
1733 
1734 
1735 
1736 
1737 
1738 
1739 
1740 
1741 // Causes:
1742 //DBG(662088814)> CPU0 FAULT: Fault 10(012), sub 4294967296(040000000000), dfc N, 'parseNumericOperandDescriptor N=1 S=0|1|2'
1743 //DBG(662088814)> CPU0 FAULT: 00257:004574 bound_process_env_:command_query_+04574
1744 //DBG(662088814)> CPU0 FAULT:       664 end print_question;
1745 //DBG(662088814)> CPU0 FAULT: 00257:004574 4 000100301500 (BTD PR0|100) 000100 301(1) 0 0 0 00
1746 
1747     uint effBITNO = 0;
1748     uint effCHAR = 0;
1749     uint effWORDNO = 0;
1750 
1751     // If seems that the effect address calcs given in AL39 p.6-27 are not
1752     // quite right.
1753     // E.g. For CTA4/CTN4 because of the 4 "slop" bits you need to do 32-bit
1754     // calcs not 36-bit!
1755 
1756     switch (e->TN[k-1])
1757     {
1758         case CTN4:
1759           {
1760             // Calculate character number of ARn CHAR and BITNO
1761             uint bitoffset = ARn_CHAR * 9u + ARn_BITNO;
1762             uint arn_char4 = bitoffset * 2u / 9u; // / 4.5
1763             //// The odd chars start at the 6th bit, not the 5th
1764             //if (bitoffset & 1) // if odd
1765             //  arn_char4 ++;
1766             // 8 chars per word plus the number of chars in r, plus the number of chars in ARn CHAR/BITNO
1767 // XXX Handle 'r' too big intelligently...
1768             uint nchars = (uint) (address * 8u + r + arn_char4 + CN);
1769 
1770             effWORDNO = nchars / 8u; // 8 chars/word
1771             effCHAR = nchars % 8u; // effCHAR is the 4 bit char number, not the 9-bit char no
1772             effBITNO = (nchars & 1u) ? 5u : 0u;
1773             effWORDNO &= AMASK;
1774 
1775             e->CN[k-1] = effCHAR;        // ?????
1776           }
1777           break;
1778 
1779         case CTN9:
1780             if (CN & 1u) {
1781               L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseNumericOperandDescriptor CTA9 & CN odd");)
1782               // DPS8M
1783               *mod_fault |= FR_ILL_PROC;
1784             }
1785             CN = (CN >> 1u) & 03u;
1786 
1787             effBITNO = 0;
1788             effCHAR = ((word36) CN + (word36) ARn_CHAR + r) % 4u;
1789             effWORDNO = (uint) (address + (9u*CN + 9u*ARn_CHAR + 9u*r + ARn_BITNO) / 36);
1790             effWORDNO &= AMASK;
1791 
1792             e->CN[k-1] = effCHAR;        // ?????
1793 
1794             break;
1795         default:
1796 #ifdef EIS_PTR3
1797             sim_printf ("parseNumericOperandDescriptor(ta=%d) How'd we get here 2?\n", cpu.du.TAk[k-1]);
1798 #else
1799             sim_printf ("parseNumericOperandDescriptor(ta=%d) How'd we get here 2?\n", e->TA[k-1]);
1800 #endif
1801             break;
1802     }
1803 
1804     EISaddr *a = &e->addr[k-1];
1805     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1806 #ifdef EIS_PTR
1807     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1808 #else
1809     a->address = effWORDNO;
1810 #endif
1811     a->cPos = (int) effCHAR;
1812     a->bPos = (int) effBITNO;
1813 
1814     // a->_type = eisTN;
1815     a->TN = (int) e->TN[k-1];
1816 
1817 #ifdef EIS_PTR
1818     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]);
1819 #else
1820     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]);
1821 #endif
1822 
1823 }
1824 
1825 static void parseBitstringOperandDescriptor (int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1826 {
1827     PNL (L68_ (if (k == 1)
1828       DU_CYCLE_ANLD1;
1829     else if (k == 2)
1830       DU_CYCLE_ANLD2;
1831     else if (k == 3)
1832       DU_CYCLE_ANSTR;))
1833 
1834     EISstruct * e = & cpu.currentEISinstruction;
1835     word18 MFk = e->MF[k-1];
1836     word36 opDesc = e->op[k-1];
1837 
1838 #ifdef PANEL68
1839     if (k == 1)
1840       cpu.dataMode = 0010; // 1 bit not alpha, not alpha numeric
1841 #endif
1842     word8 ARn_CHAR = 0;
1843     word6 ARn_BITNO = 0;
1844 
1845     PNL (cpu.du.POP = 1);
1846 
1847     word18 address = GETHI(opDesc);
1848     if (MFk & MFkAR)
1849     {
1850         // if MKf contains ar then it Means Y-charn is not the memory address
1851         // of the data but is a reference to a pointer register pointing to the
1852         // data.
1853         word3 n = (word3) getbits18 (address, 0, 3);
1854         CPTUR (cptUsePRn + n);
1855         word15 offset = address & MASK15;  // 15-bit signed number
1856         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1857 
1858         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d AR%d\n", k, n);
1859 
1860         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1861         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1862         cpu.cu.TSN_PRNO[k-1] = n;
1863         cpu.cu.TSN_VALID[k-1] = 1;
1864         e->addr[k-1].SNR = cpu.PR[n].SNR;
1865         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1866         e->addr[k-1].mat = viaPR;   // ARs involved
1867     }
1868     PNL (cpu.du.POL = 1);
1869 
1870     //Operand length. If MFk.RL = 0, this field contains the string length of
1871     //the operand. If MFk.RL = 1, this field contains the code for a register
1872     //holding the operand string length. See Table 4-1 and EIS modification
1873     //fields (MF) above for a discussion of register codes.
1874     if (MFk & MFkRL)
1875     {
1876         uint reg = opDesc & 017;
1877         e->N[k-1] = getMFReg36(reg, false, false, mod_fault) & 077777777;  // RL=1: disallow du,n,ic
1878         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d RL reg %u val %"PRIo64"\n", k, reg, (word36)e->N[k-1]);
1879     }
1880     else
1881     {
1882         e ->N[k-1] = opDesc & 07777;
1883     }
1884 
1885     sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d opdesc %012"PRIo64"\n", k, opDesc);
1886     sim_debug (DBG_TRACEEXT, & cpu_dev, "N%u %u\n", k, e->N[k-1]);
1887 
1888     word4 B = getbits36_4(opDesc, 20);    // bit# from descriptor
1889     word2 C = getbits36_2 (opDesc, 18);     // char# from descriptor
1890 
1891     if (B >= 9) {
1892       L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseBitstringOperandDescriptor B >= 9");)
1893       // DPS8M
1894       *mod_fault |= FR_ILL_PROC;
1895     }
1896 
1897     word36 r = getMFReg36(MFk & 017, false, true, mod_fault);  // disallow du, allow n,ic
1898     if ((MFk & 017) == 4)   // reg == IC ?
1899     {
1900         // If reg == IC, then R is in words, not bits.
1901         //r *= 36;
1902         address += r;
1903         address &= AMASK;
1904         r = 0;
1905     }
1906 
1907     uint effBITNO = (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 9u;
1908     uint effCHAR = ((9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 36u) / 9u;
1909     uint effWORDNO = (uint) (address + (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) / 36u);
1910     effWORDNO &= AMASK;
1911 
1912     e->B[k-1] = effBITNO;
1913     e->C[k-1] = effCHAR;
1914 
1915     EISaddr *a = &e->addr[k-1];
1916     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1917 #ifdef EIS_PTR
1918     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1919 #else
1920     a->address = effWORDNO;
1921 #endif
1922     a->cPos = (int) effCHAR;
1923     a->bPos = (int) effBITNO;
1924 }
1925 
1926 static void cleanupOperandDescriptor (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
1927   {
1928     EISstruct * e = & cpu.currentEISinstruction;
1929     if (e -> addr [k - 1].cacheValid && e -> addr [k - 1].cacheDirty)
1930       {
1931         EISWriteCache(& e -> addr [k - 1]);
1932       }
1933     e -> addr [k - 1].cacheDirty = false;
1934   }
1935 
1936 // For a4bd/s4bd, the world is made of 32 bit words, so the address space
1937 // is 2^18 * 32 bits
1938 #define n4bits (1 << 23)
1939 // For a4bd/s4bd, the world is made of 8 4-bitcharacter words, so the address space
1940 // is 2^18 * 8 characters
1941 #define n4chars (1 << 21)
1942 // For axbd/sxbd, the world is made of 36 bits words, so the address space
1943 // is 2^18 * 36 bits
1944 #define nxbits ((1 << 18) * 36)
1945 
1946 // 2 * (s->BITNO / 9) + (s->BITNO % 9) / 4;
1947 static unsigned int cntFromBit[36] = {
1948     0, 0, 0, 0, 0, 1, 1, 1, 1,
1949     2, 2, 2, 2, 2, 3, 3, 3, 3,
1950     4, 4, 4, 4, 4, 5, 5, 5, 5,
1951     6, 6, 6, 6, 6, 7, 7, 7, 7
1952 };
1953 
1954 static word6 bitFromCnt[8] = {1, 5, 10, 14, 19, 23, 28, 32};
1955 
1956 void a4bd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1957   {
1958     // 8 4-bit characters/word
1959 
1960     uint ARn = GET_ARN (cpu.cu.IWB);
1961     CPTUR (cptUsePRn + ARn);
1962     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
1963 //if (current_running_cpu_idx)
1964 //sim_printf ("a4bd address %o %d.\n", address, address);
1965 
1966     word4 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
1967                                      // au, qu, al, ql, xn)
1968     // r is the count of 4bit characters
1969     word36 ur = getCrAR (reg);
1970     int32 r = SIGNEXT22_32 ((word22) ur);
1971 //if (current_running_cpu_idx)
1972 //sim_printf ("a4bd r %o %d.\n", r, r);
1973 
1974     uint augend = 0; // in 4bit characters
1975     if (GET_A (cpu.cu.IWB))
1976        {
1977 //if (current_running_cpu_idx)
1978 //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);
1979 
1980          //augend = cpu.AR[ARn].WORDNO * 32u + cntFromBit [GET_AR_BITNO (ARn)];
1981          // force to 4 bit character boundary
1982          //augend = augend & ~3;
1983          //augend = cpu.AR[ARn].WORDNO * 8 + cpu.AR[ARn].CHAR * 2;
1984          augend = cpu.AR[ARn].WORDNO * 8u + GET_AR_CHAR (ARn) * 2u;
1985 
1986          //if (cpu.AR[ARn].BITNO >= 5)
1987          if (GET_AR_BITNO (ARn) >= 5u)
1988            augend ++;
1989        }
1990 
1991 //if (current_running_cpu_idx)
1992 //sim_printf ("a4bd augend %o %d.\n", augend, augend);
1993 
1994     int32_t addend = address * 8 + r;  // in characters
1995 
1996 //if (current_running_cpu_idx)
1997 //sim_printf ("a4bd addend %o %d.\n", addend, addend);
1998 
1999     int32_t sum = (int32_t) augend + addend;
2000 //if (current_running_cpu_idx)
2001 //sim_printf ("a4bd sum %o %d.\n", sum, sum);
2002 
2003     // Handle over/under flow
2004     while (sum < 0)
2005       sum += n4chars;
2006     sum = sum % n4chars;
2007 //if (current_running_cpu_idx)
2008 //sim_printf ("a4bd sum %o %d.\n", sum, sum);
2009 
2010     cpu.AR[ARn].WORDNO = (word18) (sum / 8) & AMASK;
2011 //if (current_running_cpu_idx)
2012 //sim_printf ("a4bd WORDNO %o %d.\n", cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO);
2013 
2014 //    // 0aaaabbbb0ccccdddd0eeeeffff0gggghhhh
2015 //    //             111111 11112222 22222233
2016 //    //  01234567 89012345 67890123 45678901   // 4 bit notation offset
2017 //    static int tab [32] = { 1,  2,  3,  4,  5,  6,  7,  8,
2018 //                           10, 11, 12, 13, 14, 15, 16, 17,
2019 //                           19, 20, 21, 22, 23, 24, 25, 26,
2020 //                           28, 29, 30, 31, 32, 33, 34, 35};
2021 //
2022     //uint bitno = sum % 32;
2023 //    AR [ARn].BITNO = tab [bitno];
2024     //cpu.AR [ARn].BITNO = bitFromCnt[bitno % 8];
2025     //SET_PR_BITNO (ARn, bitFromCnt[bitno % 8]);
2026     uint char4no = (uint) (sum % 8);
2027 //if (current_running_cpu_idx)
2028 //sim_printf ("a4bd char4no %d.\n", char4no);
2029 
2030     SET_AR_CHAR_BITNO (ARn, (word2) (char4no / 2), (char4no % 2) ? 5 : 0);
2031 #ifdef TESTING
2032     HDBGRegARW (ARn, "a4bd");
2033 #endif
2034 //if (current_running_cpu_idx)
2035 //sim_printf ("a4bd CHAR %o %d.\n", cpu.AR[ARn].CHAR, cpu.AR[ARn].CHAR);
2036 //if (current_running_cpu_idx)
2037 //sim_printf ("a4bd BITNO %o %d.\n", cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2038   }
2039 
2040 void s4bd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2041   {
2042     uint ARn = GET_ARN (cpu.cu.IWB);
2043     CPTUR (cptUsePRn + ARn);
2044     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2045     word4 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2046                                   // au, qu, al, ql, xn)
2047     // r is the count of characters
2048     word36 ur = getCrAR (reg);
2049     int32 r = SIGNEXT22_32 ((word22) ur);
2050 
2051     uint minuend = 0;
2052     if (GET_A (cpu.cu.IWB))
2053        {
2054          //minuend = cpu.AR [ARn].WORDNO * 32 + cntFromBit [GET_PR_BITNO (ARn)];
2055          minuend = cpu.AR [ARn].WORDNO * 32 + cntFromBit [GET_AR_CHAR (ARn) * 9 + GET_AR_BITNO (ARn)];
2056          // force to 4 bit character boundary
2057          minuend = minuend & (unsigned int) ~3;
2058        }
2059     int32_t subtractend = address * 32 + r * 4;
2060     int32_t difference = (int32_t) minuend - subtractend;
2061 
2062     // Handle over/under flow
2063     while (difference < 0)
2064       difference += n4bits;
2065     difference = difference % n4bits;
2066 
2067     cpu.AR [ARn].WORDNO = (word18) (difference / 32) & AMASK;
2068 
2069 //    // 0aaaabbbb0ccccdddd0eeeeffff0gggghhhh
2070 //    //             111111 11112222 22222233
2071 //    //  01234567 89012345 67890123 45678901   // 4 bit notation offset
2072 //    static int tab [32] = { 1,  2,  3,  4,  5,  6,  7,  8,
2073 //                       10, 11, 12, 13, 14, 15, 16, 17,
2074 //                       19, 20, 21, 22, 23, 24, 25, 26,
2075 //                       28, 29, 30, 31, 32, 33, 34, 35};
2076 //
2077 
2078     uint bitno = (uint) (difference % 32);
2079 //    cpu.AR [ARn].BITNO = tab [bitno];
2080     // SET_PR_BITNO (ARn, bitFromCnt[bitno % 8]);
2081     SET_AR_CHAR_BITNO (ARn, bitFromCnt[bitno % 8] / 9, bitFromCnt[bitno % 8] % 9);
2082 #ifdef TESTING
2083     HDBGRegARW (ARn, "s4bd");
2084 #endif
2085   }
2086 
2087 void axbd (uint sz)
     /* [previous][next][first][last][top][bottom][index][help] */
2088   {
2089     uint ARn = GET_ARN (cpu.cu.IWB);
2090     CPTUR (cptUsePRn + ARn);
2091     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2092     word6 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2093                                   // au, qu, al, ql, xn)
2094     // r is the count of characters
2095     word36 rcnt = getCrAR (reg);
2096     int32_t r;
2097 
2098     if (sz == 1)
2099       r = SIGNEXT24_32 ((word24) rcnt);
2100     else if (sz == 4)
2101       r = SIGNEXT22_32 ((word22) rcnt);
2102     else if (sz == 6)
2103       r = SIGNEXT21_32 ((word21) rcnt);
2104     else if (sz == 9)
2105       r = SIGNEXT21_32 ((word21) rcnt);
2106     else // if (sz == 36)
2107       r = SIGNEXT18_32 ((word18) rcnt);
2108 
2109     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);
2110 
2111     uint augend = 0;
2112     if (GET_A (cpu.cu.IWB))
2113       {
2114        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));
2115        augend = cpu.AR[ARn].WORDNO * 36u + GET_AR_CHAR (ARn) * 9u + GET_AR_BITNO (ARn);
2116       }
2117     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd augend 0%o\n", augend);
2118     // force to character boundary
2119     //if (sz == 9 || sz == 36 || GET_A (cpu.cu.IWB))
2120     if (sz == 9 || GET_A (cpu.cu.IWB))
2121       {
2122         augend = (augend / sz) * sz;
2123         sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd force augend 0%o\n", augend);
2124       }
2125 // If sz == 9, this is an a9bd instruction; ISOLTS says that r is in characters, not bits.
2126 // wow. That breaks the boot bad.
2127 //    if (sz == 9)
2128 //      {
2129 //        r *= 9;
2130 //if (current_running_cpu_idx)
2131 //sim_printf ("axbd force chars 0%o %d. bits\n", r, r);
2132 //      }
2133 
2134     int32_t addend = address * 36 + r * (int32_t) sz;
2135     int32_t sum = (int32_t) augend + addend;
2136 
2137     // Handle over/under flow
2138     while (sum < 0)
2139       sum += nxbits;
2140     sum = sum % nxbits;
2141 
2142     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2143 
2144     cpu.AR [ARn].WORDNO = (word18) (sum / 36) & AMASK;
2145     //SET_PR_BITNO (ARn, sum % 36);
2146 #ifdef TESTING
2147     HDBGRegARR (ARn, "axbd");
2148 #endif
2149     SET_AR_CHAR_BITNO (ARn, (word2)((sum % 36) / 9), (word2)(sum % 9));
2150 #ifdef TESTING
2151     HDBGRegARW (ARn, "axbd");
2152 #endif
2153   }
2154 
2155 
2156 void abd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2157   {
2158     uint ARn = GET_ARN (cpu.cu.IWB);
2159     CPTUR (cptUsePRn + ARn);
2160 
2161     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2162 //if (current_running_cpu_idx)
2163 //sim_printf ("address %o\n", address);
2164     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2165     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2166     word24 r = getCrAR ((word4) reg) & MASK24;
2167 //if (current_running_cpu_idx)
2168 //sim_printf ("r 0%o %d.\n", r, r);
2169 //if (current_running_cpu_idx)
2170 //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);
2171 
2172     //if (cpu.AR[ARn].BITNO > 8)
2173       //cpu.AR[ARn].BITNO = 8;
2174     if (GET_AR_BITNO (ARn) > 8)
2175       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2176 
2177     if (GET_A (cpu.cu.IWB))
2178       {
2179 //if (current_running_cpu_idx)
2180 //sim_printf ("A 1\n");
2181         //word24 bits = 9 * cpu.AR[ARn].CHAR + cpu.AR[ARn].BITNO + r;
2182         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) + r;
2183 //if (current_running_cpu_idx)
2184 //sim_printf ("bits 0%o %d.\n", bits, bits);
2185         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO + address +
2186                               bits / 36) & MASK18;
2187         if (r % 36)
2188           {
2189             //cpu.AR[ARn].CHAR = (bits % 36) / 9;
2190             //cpu.AR[ARn].BITNO = bits % 9;
2191             SET_AR_CHAR_BITNO (ARn, (bits % 36) / 9,
2192                                     bits % 9);
2193           }
2194       }
2195     else
2196       {
2197 //if (current_running_cpu_idx)
2198 //sim_printf ("A 0\n");
2199         cpu.AR[ARn].WORDNO = (address + r / 36) & MASK18;
2200         if (r % 36)
2201           {
2202             //cpu.AR[ARn].CHAR = (r % 36) / 9;
2203             //cpu.AR[ARn].BITNO = r % 9;
2204             SET_AR_CHAR_BITNO (ARn, (r % 36) / 9,
2205                                     r % 9);
2206           }
2207       }
2208 # ifdef TESTING
2209     HDBGRegARW (ARn, "abd");
2210 # endif
2211 //if (current_running_cpu_idx)
2212 //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);
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 
2358 void awd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2359   {
2360     uint ARn = GET_ARN (cpu.cu.IWB);
2361     CPTUR (cptUsePRn + ARn);
2362     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2363     // 4-bit register modification (None except
2364     // au, qu, al, ql, xn)
2365     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2366     // r is the count of characters
2367 // XXX This code is assuming that 'r' has 18 bits of data....
2368     int32_t r = (int32_t) (getCrAR (reg) & MASK18);
2369     r = SIGNEXT18_32 ((word18) r);
2370 
2371     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2372                "awd ARn 0%o address 0%o reg 0%o r 0%o\n", ARn, address, reg, r);
2373 
2374     uint augend = 0;
2375     if (GET_A (cpu.cu.IWB))
2376       {
2377        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));
2378 
2379        //augend = cpu.AR [ARn].WORDNO * 36 + GET_AR_CHAR (ARn) * 9 + GET_AR_BITNO (ARn);
2380        augend = cpu.AR [ARn].WORDNO;
2381       }
2382 
2383     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "awd augend 0%o\n", augend);
2384 
2385     int32_t addend = address + r;
2386     int32_t sum = (int32_t) augend + addend;
2387 
2388     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "awd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2389 
2390     cpu.AR[ARn].WORDNO = (word18) sum & AMASK;
2391     SET_AR_CHAR_BITNO (ARn, 0, 0);
2392 #ifdef TESTING
2393     HDBGRegARW (ARn, "awd");
2394 #endif
2395   }
2396 
2397 void sbd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2398   {
2399     uint ARn = GET_ARN (cpu.cu.IWB);
2400 
2401     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2402     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2403     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2404     word24 r = getCrAR ((word4) reg) & MASK24;
2405     if (GET_AR_BITNO (ARn) > 8)
2406       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2407 
2408     if (GET_A (cpu.cu.IWB))
2409       {
2410         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) - r;
2411         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2412                              address + bits / 36) & MASK18;
2413         if (r % 36)
2414           {
2415             SET_AR_CHAR_BITNO (ARn, (- ((bits % 36) / 9)) & MASK2,
2416                                     (- (bits % 9)) & MASK4);
2417           }
2418       }
2419     else
2420       {
2421         cpu.AR[ARn].WORDNO = (- (address + r / 36)) & MASK18;
2422         if (r % 36)
2423           {
2424             SET_AR_CHAR_BITNO (ARn, (- ((r % 36) / 9)) & MASK2,
2425                                     (- (r % 9)) & MASK4);
2426           }
2427       }
2428 #ifdef TESTING
2429     HDBGRegARW (ARn, "sbd");
2430 #endif
2431   }
2432 
2433 void swd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2434   {
2435     uint ARn = GET_ARN (cpu.cu.IWB);
2436     CPTUR (cptUsePRn + ARn);
2437     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2438     // 4-bit register modification (None except
2439     // au, qu, al, ql, xn)
2440     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2441     // r is the count of characters
2442 // XXX This code is assuming that 'r' has 18 bits of data....
2443     int32_t r = (int32_t) (getCrAR (reg) & MASK18);
2444     r = SIGNEXT18_32 ((word18) r);
2445 
2446     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);
2447 
2448     uint minued = 0;
2449     if (GET_A (cpu.cu.IWB))
2450       {
2451        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));
2452 
2453        //minued = cpu.AR [ARn].WORDNO * 36 + GET_AR_BITNO (ARn);
2454        minued = cpu.AR [ARn].WORDNO;
2455       }
2456 
2457     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "swd minued 0%o\n", minued);
2458 
2459     int32_t subtractend = address + r;
2460     int32_t difference = (int32_t) minued - subtractend;
2461 
2462     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "swd minued 0%o subtractend 0%o difference 0%o\n", minued, subtractend, difference);
2463 
2464     cpu.AR [ARn].WORDNO = (word18) difference & AMASK;
2465     SET_AR_CHAR_BITNO (ARn, 0, 0);
2466 #ifdef TESTING
2467     HDBGRegARW (ARn, "swd");
2468 #endif
2469   }
2470 
2471 void s9bd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2472   {
2473     uint ARn = GET_ARN (cpu.cu.IWB);
2474     CPTUR (cptUsePRn + ARn);
2475     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2476     // 4-bit register modification (None except
2477     // au, qu, al, ql, xn)
2478     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2479 
2480     // r is the count of 9-bit characters
2481     word21 r = getCrAR (reg) & MASK21;;
2482 
2483     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "s9bd r 0%o\n", r);
2484 
2485     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);
2486 
2487     if (GET_A (cpu.cu.IWB))
2488       {
2489         //cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2490         //                      address +
2491         //                      (cpu.AR[ARn].CHAR - r) / 4) & MASK18;
2492         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2493                               address +
2494                               (GET_AR_CHAR (ARn) - r) / 4) & MASK18;
2495         //if (r % 36)
2496           //{
2497             //cpu.AR[ARn].CHAR = ((cpu.AR[ARn].CHAR - r) % 4) & MASK2;
2498             //cpu.AR[ARn].CHAR = (cpu.AR[ARn].CHAR - r)  & MASK2;
2499             SET_AR_CHAR_BITNO (ARn, (GET_AR_CHAR (ARn) - r)  & MASK2, 0);
2500           //}
2501       }
2502     else
2503       {
2504         cpu.AR[ARn].WORDNO = (- (address + (r + 3) / 4)) & MASK18;
2505         //if (r % 36)
2506           //{
2507             //cpu.AR[ARn].CHAR = (-r) & MASK2;
2508             SET_AR_CHAR_BITNO (ARn, (-r) & MASK2, 0);
2509           //}
2510       }
2511     //cpu.AR[ARn].BITNO = 0;
2512 #ifdef TESTING
2513     HDBGRegARW (ARn, "s9bd");
2514 #endif
2515 //if (current_running_cpu_idx)
2516 //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);
2517   }
2518 
2519 //
2520 // Address Register arithmetic
2521 //
2522 // This code handles Address Register arithmetic
2523 //
2524 // asxbd (  ,       )
2525 // ABD     1   false
2526 // A4BD    4   false
2527 // A6BD    6   false
2528 // A9BD    9   false
2529 // AWD    36   false
2530 // SBD     1   true
2531 // S4BD    4   true
2532 // S6BD    6   true
2533 // S9BD    9   true
2534 // SWD    36   true
2535 //
2536 
2537 // The general approach is do all of the math as unsigned number of bits,
2538 // modulo 2^18 * 36 (the number of bits in a segment).
2539 //
2540 // To handle subtraction underflow, a preemptive borrow is done if the
2541 // the operation will underflow.
2542 //
2543 // Notes:
2544 //   According to ISOLTS 805, WORDNO is unsigned; this disagrees with AL-39
2545 
2546 void asxbd (uint sz, bool sub)
     /* [previous][next][first][last][top][bottom][index][help] */
2547   {
2548     // Map charno:bitno to bit offset for 4 bit char set
2549     uint map4 [64] =
2550       {      // 9-bit    4-bit
2551           0, // 0  0      0
2552           0, // 0  1      0
2553           0, // 0  2      0
2554           0, // 0  3      0
2555           0, // 0  4      0
2556           5, // 0  5      1
2557           5, // 0  6      1
2558           5, // 0  7      1
2559           5, // 0  8      1
2560           5, // 0  9  ill     guess
2561           5, // 0 10  ill     guess
2562           5, // 0 11  ill     guess
2563           5, // 0 12  ill     guess
2564           5, // 0 13  ill     guess
2565           5, // 0 14  ill     guess
2566           5, // 0 15  ill     guess
2567           9, // 1  0      2
2568           9, // 1  1      2
2569           9, // 1  2      2
2570           9, // 1  3      2
2571           9, // 1  4      2
2572          14, // 1  5      3
2573          14, // 1  6      3
2574          14, // 1  7      3
2575          14, // 1  8      3
2576          14, // 1  9  ill     guess
2577          14, // 1 10  ill ISOLTS 805 loop point 010226 sxbd test no 28 (4bit)
2578          14, // 1 11  ill     guess
2579          14, // 1 12  ill     guess
2580          14, // 1 13  ill     guess
2581          14, // 1 14  ill     guess
2582          14, // 1 15  ill     guess
2583          18, // 2  0      4
2584          18, // 2  1      4
2585          18, // 2  2      4
2586          18, // 2  3      4
2587          18, // 2  4      4
2588          23, // 2  5      5
2589          23, // 2  6      5
2590          23, // 2  7      5
2591          23, // 2  8      5
2592          23, // 2  9  ill     guess
2593          23, // 2 10  ill     guess
2594          23, // 2 11  ill     guess
2595          23, // 2 12  ill   ISOLTS 805 loop point 010226 sxbd test no 26 (4bit)
2596          23, // 2 13  ill     guess
2597          23, // 2 14  ill     guess
2598          23, // 2 15  ill     guess
2599          27, // 3  0      6
2600          27, // 3  1      6
2601          27, // 3  2      6
2602          27, // 3  3      6
2603          27, // 3  4      6
2604          32, // 3  5      7
2605          32, // 3  6      7
2606          32, // 3  7      7
2607          32, // 3  8      7
2608          32, // 3  9  ill     guess
2609          32, // 3 10  ill     guess
2610          32, // 3 11  ill     guess
2611          32, // 3 12  ill     guess
2612          32, // 3 13  ill     guess
2613          32, // 3 14  ill   ISOLTS 805 loop point 010226 sxbd test no 24 (4bit)
2614          32  // 3 15  ill     guess
2615       };
2616     // Map charno:bitno to bit offset for 6 bit char set
2617     uint map6 [64] =
2618       {      // 9-bit    6-bit
2619           0, // 0  0      0
2620           1, // 0  1      0
2621           2, // 0  2      0
2622           3, // 0  3      0
2623           4, // 0  4      0
2624           5, // 0  5      0
2625           6, // 0  6      1
2626           7, // 0  7      1
2627           8, // 0  8      1
2628           6, // 0  9  ill  ISOLTS 805 loop point 010100 sxbd test no 12
2629           6, // 0 10  ill     guess
2630           6, // 0 11  ill     guess
2631           6, // 0 12  ill     guess
2632           6, // 0 13  ill     guess
2633           6, // 0 14  ill     guess
2634           6, // 0 15  ill     guess
2635           9, // 1  0      1
2636          10, // 1  1      1
2637          11, // 1  2      1
2638          12, // 1  3      2
2639          13, // 1  4      2
2640          14, // 1  5      2
2641          15, // 1  6      2
2642          16, // 1  7      2
2643          17, // 1  8      2
2644          12, // 1  9  ill     guess
2645          12, // 1 10  ill     guess
2646          12, // 1 11  ill ISOLTS 805 loop point 010100 sxbd test no 12
2647          12, // 1 12  ill     guess
2648          12, // 1 13  ill     guess
2649          12, // 1 14  ill     guess
2650          12, // 1 15  ill     guess
2651          18, // 2  0      3
2652          19, // 2  1      3
2653          20, // 2  2      3
2654          21, // 2  3      3
2655          22, // 2  4      3
2656          23, // 2  5      3
2657          24, // 2  6      4
2658          25, // 2  7      4
2659          26, // 2  8      4
2660          24, // 2  9  ill     guess
2661          24, // 2 10  ill     guess
2662          24, // 2 11  ill     guess
2663          24, // 2 12  ill     guess
2664          24, // 2 13  ill   ISOLTS 805 loop point 010100 sxbd test no 10
2665          24, // 2 14  ill     guess
2666          24, // 2 15  ill     guess
2667          27, // 3  0      4
2668          28, // 3  1      4
2669          29, // 3  2      4
2670          30, // 3  3      5
2671          31, // 3  4      5
2672          32, // 3  5      5
2673          33, // 3  6      5
2674          34, // 3  7      5
2675          35, // 3  8      5
2676          30, // 3  9  ill     guess
2677          30, // 3 10  ill     guess
2678          30, // 3 11  ill     guess
2679          30, // 3 12  ill     guess
2680          30, // 3 13  ill     guess
2681          30, // 3 14  ill     guess
2682          30  // 3 15  ill   ISOLTS 805 loop point 010100 sxbd test no 8 (6bit)
2683       };
2684     // Map charno:bitno to 1 and 9 bit offset
2685     uint map9 [64] =
2686       {      // 9-bit
2687           0, // 0  0
2688           1, // 0  1
2689           2, // 0  2
2690           3, // 0  3
2691           4, // 0  4
2692           5, // 0  5
2693           6, // 0  6
2694           7, // 0  7
2695           8, // 0  8
2696           8, // 0  9  ill     guess
2697           8, // 0 10  ill     guess
2698           8, // 0 11  ill     guess
2699           8, // 0 12  ill     guess
2700           8, // 0 13  ill     guess
2701           8, // 0 14  ill     guess
2702           8, // 0 15  ill     guess
2703           9, // 1  0
2704          10, // 1  1
2705          11, // 1  2
2706          12, // 1  3
2707          13, // 1  4
2708          14, // 1  5
2709          15, // 1  6
2710          16, // 1  7
2711          17, // 1  8
2712          17, // 1  9  ill     guess
2713          17, // 1 10  ill     guess
2714          17, // 1 11  ill     guess
2715          17, // 1 12  ill     guess
2716          17, // 1 13  ill     guess
2717          17, // 1 14  ill     guess
2718          17, // 1 15  ill     guess
2719          18, // 2  0
2720          19, // 2  1
2721          20, // 2  2
2722          21, // 2  3
2723          22, // 2  4
2724          23, // 2  5
2725          24, // 2  6
2726          25, // 2  7
2727          26, // 2  8
2728          26, // 2  9  ill     guess
2729          26, // 2 10  ill     guess
2730          26, // 2 11  ill     guess
2731          26, // 2 12  ill     guess
2732          26, // 2 13  ill     guess
2733          26, // 2 14  ill     guess
2734          26, // 2 15  ill     guess
2735          27, // 3  0
2736          28, // 3  1
2737          29, // 3  2
2738          30, // 3  3
2739          31, // 3  4
2740          32, // 3  5
2741          33, // 3  6
2742          34, // 3  7
2743          35, // 3  8
2744          35, // 3  9  ill     guess
2745          35, // 3 10  ill     guess
2746          35, // 3 11  ill     guess
2747          35, // 3 12  ill     guess
2748          35, // 3 13  ill     guess
2749          35, // 3 14  ill     guess
2750          35  // 3 15  ill     guess
2751       };
2752 
2753 //
2754 // Extract the operand data from the instruction
2755 //
2756 
2757     uint ARn = GET_ARN (cpu.cu.IWB);
2758     uint address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2759     word4 reg = (word4) GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2760                                   // au, qu, al, ql, xn)
2761 
2762 //
2763 // Calculate r
2764 //
2765 
2766     // r is the count of characters (or bits if sz is 1; words if sz == 36)
2767     word36 rcnt = getCrAR (reg);
2768 
2769     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd sz %d r 0%"PRIo64"\n", sz, rcnt);
2770 
2771     // Crop rcnt into r based on the operand size.
2772     uint r = 0;
2773 
2774     if (sz == 1)
2775       r = (uint) (rcnt & MASK24);
2776     else if (sz == 4)
2777       r = (uint) (rcnt & MASK22);
2778     else if (sz == 6)
2779       r = (uint) (rcnt & MASK21);
2780     else if (sz == 9)
2781       r = (uint) (rcnt & MASK21);
2782     else // if (sz == 36)
2783       r = (uint) (rcnt & MASK18);
2784 
2785     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);
2786 
2787 //
2788 // Calculate augend
2789 //
2790 
2791     // If A is set, the instruction is AR = AR op operand; if not, AR = 0 op operand.
2792     uint augend = 0;
2793     if (GET_A (cpu.cu.IWB))
2794       {
2795         // For AWD/SWD, leave CHAR/BITNO alone
2796         if (sz == 36)
2797           {
2798             augend = cpu.AR[ARn].WORDNO * 36u;
2799           }
2800         else
2801           {
2802             uint bitno = GET_AR_BITNO (ARn);
2803             uint charno = GET_AR_CHAR (ARn);
2804 
2805             // The behavior of the DU for cases of CHAR > 9 is not defined; some values
2806             // are tested by ISOLTS, and have been recorded in the mapx tables; the
2807             // missing values are guessed at.
2808 
2809             uint * map;
2810             if (sz == 4)
2811               map = map4;
2812             else if (sz == 6)
2813               map = map6;
2814             else
2815               map = map9;
2816 
2817             augend = cpu.AR[ARn].WORDNO * 36u + map [charno * 16 + bitno];
2818             augend = augend % nxbits;
2819           }
2820       }
2821 
2822 //
2823 // Calculate addend
2824 //
2825 
2826     uint addend = 0;
2827     if (sz == 4)
2828       {
2829         // r is the number of 4 bit characters; each character is actually
2830         // 4.5 bits long
2831         addend = address * 36u + (r * 9) / 2;
2832 
2833         // round the odd character up one bit
2834         // (the odd character starts at bit n/2 + 1, not n/2.)
2835         if ((! sub) && r % 2) // r is odd
2836           addend ++;
2837       }
2838     else
2839       addend = address * 36u + r * sz;
2840 
2841     // Handle overflow
2842     addend = addend % nxbits;
2843 
2844 //
2845 // Calculate sum or difference
2846 //
2847 
2848     uint sum = 0;
2849     if (sub)
2850       {
2851         // Prevent underflow
2852         if (addend > augend)
2853           augend += nxbits;
2854         sum = augend - addend;
2855       }
2856     else
2857       {
2858         sum = augend + addend;
2859         sum %= nxbits;
2860       }
2861 
2862     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2863 
2864 //
2865 // Adjust to character boundary
2866 //
2867 
2868     if (sz == 6 || sz == 9)
2869       {
2870         sum = (sum / sz) * sz;
2871       }
2872 
2873 //
2874 // Convert sum to WORDNO/CHAR/BITNO
2875 //
2876 
2877     cpu.AR [ARn].WORDNO = (word18) (sum / 36u) & AMASK;
2878 
2879     // If AWD/SWD clear CHAR/BITNO
2880 
2881     if (sz == 36)
2882       {
2883         SET_AR_CHAR_BITNO (ARn, 0, 0);
2884       }
2885     else
2886       {
2887         if (sz == 4)
2888           {
2889             static uint tab [36] [2] =
2890               {
2891                 // char bitno  offset  4-bit charno
2892                 { 0, 0 }, // 0   0
2893                 { 0, 0 }, // 1
2894                 { 0, 0 }, // 2
2895                 { 0, 0 }, // 3
2896                 { 0, 0 }, // 4
2897 
2898                 { 0, 5 }, // 5   1
2899                 { 0, 5 }, // 6
2900                 { 0, 5 }, // 7
2901                 { 0, 5 }, // 8
2902 
2903                 { 1, 0 }, // 9   2
2904                 { 1, 0 }, // 10
2905                 { 1, 0 }, // 11
2906                 { 1, 0 }, // 12
2907                 { 1, 0 }, // 13
2908 
2909                 { 1, 5 }, // 15  3
2910                 { 1, 5 }, // 15
2911                 { 1, 5 }, // 16
2912                 { 1, 5 }, // 17
2913 
2914                 { 2, 0 }, // 18  4
2915                 { 2, 0 }, // 19
2916                 { 2, 0 }, // 20
2917                 { 2, 0 }, // 21
2918                 { 2, 0 }, // 22
2919 
2920                 { 2, 5 }, // 23  5
2921                 { 2, 5 }, // 24
2922                 { 2, 5 }, // 25
2923                 { 2, 5 }, // 26
2924 
2925                 { 3, 0 }, // 27  6
2926                 { 3, 0 }, // 28
2927                 { 3, 0 }, // 29
2928                 { 3, 0 }, // 30
2929                 { 3, 0 }, // 31
2930 
2931                 { 3, 5 }, // 32  7
2932                 { 3, 5 }, // 33
2933                 { 3, 5 }, // 34
2934                 { 3, 5 }  // 35
2935               };
2936             uint charno = tab [sum % 36u] [0];
2937             uint bitno = tab [sum % 36u] [1];
2938             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
2939           }
2940         else
2941           {
2942             uint charno = (sum % 36u) / 9;
2943             uint bitno = sum % 9;
2944             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
2945           }
2946       }
2947 #ifdef TESTING
2948     HDBGRegARW (ARn, "asxbd");
2949 #endif
2950   }
2951 
2952 void cmpc (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2953   {
2954     EISstruct * e = & cpu.currentEISinstruction;
2955 
2956     // For i = 1, 2, ..., minimum (N1,N2)
2957     //    C(Y-charn1)i-1 :: C(Y-charn2)i-1
2958     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
2959     //    C(FILL) :: C(Y-charn2)i-1
2960     // If N1 > N2, then for i = N2+1, N2+2, ..., N1
2961     //    C(Y-charn1)i-1 :: C(FILL)
2962     //
2963     // Indicators:
2964     //     Zero: If C(Y-charn1)i-1 = C(Y-charn2)i-1 for all i, then ON;
2965     //       otherwise, OFF
2966     //     Carry: If C(Y-charn1)i-1 < C(Y-charn2)i-1 for any i, then OFF;
2967     //       otherwise ON
2968 
2969     // Both strings are treated as the data type given for the left-hand
2970     // string, TA1. A data type given for the right-hand string, TA2, is
2971     // ignored.
2972     //
2973     // Comparison is made on full 9-bit fields. If the given data type is not
2974     // 9-bit (TA1 ≠ 0), then characters from C(Y-charn1) and C(Y-charn2) are
2975     // high- order zero filled. All 9 bits of C(FILL) are used.
2976     //
2977     // Instruction execution proceeds until an inequality is found or the
2978     // larger string length count is exhausted.
2979 
2980     fault_ipr_subtype_ mod_fault = 0;
2981 
2982 #ifndef EIS_SETUP
2983     setupOperandDescriptor (1, &mod_fault);
2984     setupOperandDescriptor (2, &mod_fault);
2985 #endif
2986     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
2987     parseAlphanumericOperandDescriptor (2, 1, false, &mod_fault);
2988 
2989     L68_ (
2990       // L68 raises it immediately
2991       if (mod_fault)
2992         {
2993           doFault (FAULT_IPR,
2994                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
2995                    "Illegal modifier");
2996         }
2997     )
2998 
2999     // Bits 9-10 MBZ
3000     if (IWB_IRODD & 0000600000000)
3001       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpc 9-10 MBZ");
3002 
3003     // Bit 23 of OP1 MBZ
3004     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3005       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "cmpc op1 23 MBZ");
3006 
3007 // ISOLTS ps846    test-07a    dec add test
3008 // Sets TA2 to the same as TA1. AL39 says TA2 ignored.
3009 // Try only check bit 23.
3010 // ISOLTS 880 test-04c sets bit 23.
3011 
3012 
3013 
3014 
3015 
3016 
3017 
3018 
3019     DPS8M_ (
3020       // DPS8M raises it delayed
3021       if (mod_fault)
3022         {
3023           doFault (FAULT_IPR,
3024                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3025                    "Illegal modifier");
3026         }
3027     )
3028 
3029     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
3030 
3031     SET_I_ZERO;  // set ZERO flag assuming strings are equal ...
3032     SET_I_CARRY; // set CARRY flag assuming strings are equal ...
3033 
3034     PNL (L68_ (if (max (e->N1, e->N2) < 128)
3035       DU_CYCLE_FLEN_128;))
3036 
3037     for (; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
3038       {
3039         word9 c1 = EISget469 (1, cpu.du.CHTALLY); // get Y-char1n
3040         word9 c2 = EISget469 (2, cpu.du.CHTALLY); // get Y-char2n
3041 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpc tally %d c1 %03o c2 %03o\n", cpu.du.CHTALLY, c1, c2);
3042         if (c1 != c2)
3043           {
3044             CLR_I_ZERO;  // an inequality found
3045             SC_I_CARRY (c1 > c2);
3046             cleanupOperandDescriptor (1);
3047             cleanupOperandDescriptor (2);
3048             return;
3049           }
3050       }
3051 
3052     if (e -> N1 < e -> N2)
3053       {
3054         for( ; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY ++)
3055           {
3056             word9 c1 = fill;     // use fill for Y-char1n
3057             word9 c2 = EISget469 (2, cpu.du.CHTALLY); // get Y-char2n
3058 
3059             if (c1 != c2)
3060               {
3061                 CLR_I_ZERO;  // an inequality found
3062                 SC_I_CARRY (c1 > c2);
3063                 cleanupOperandDescriptor (1);
3064                 cleanupOperandDescriptor (2);
3065                 return;
3066               }
3067           }
3068       }
3069     else if (e->N1 > e->N2)
3070       {
3071         for ( ; cpu.du.CHTALLY < e->N1; cpu.du.CHTALLY ++)
3072           {
3073             word9 c1 = EISget469 (1, cpu.du.CHTALLY); // get Y-char1n
3074             word9 c2 = fill;   // use fill for Y-char2n
3075 
3076             if (c1 != c2)
3077               {
3078                 CLR_I_ZERO;  // an inequality found
3079                 SC_I_CARRY (c1 > c2);
3080                 cleanupOperandDescriptor (1);
3081                 cleanupOperandDescriptor (2);
3082                 return;
3083               }
3084           }
3085       }
3086     // else ==
3087     cleanupOperandDescriptor (1);
3088     cleanupOperandDescriptor (2);
3089   }
3090 
3091 /*
3092  * SCD - Scan Characters Double
3093  */
3094 
3095 void scd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3096   {
3097     EISstruct * e = & cpu.currentEISinstruction;
3098 
3099     // For i = 1, 2, ..., N1-1
3100     //   C(Y-charn1)i-1,i :: C(Y-charn2)0,1
3101     // On instruction completion, if a match was found:
3102     //   00...0 → C(Y3)0,11
3103     //   i-1 → C(Y3)12,35
3104     // If no match was found:
3105     //   00...0 → C(Y3)0,11
3106     //      N1-1→ C(Y3)12,35
3107     //
3108 
3109     // The REG field of MF1 is checked for a legal code. If DU is specified in
3110     // the REG field of MF2 in one of the four multiword instructions (SCD,
3111     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3112     // the character or characters are arranged within the 18 bits of the word
3113     // address portion of the operand descriptor.
3114 
3115     fault_ipr_subtype_ mod_fault = 0;
3116 
3117 #ifndef EIS_SETUP
3118     setupOperandDescriptor (1, &mod_fault);
3119     setupOperandDescriptor (2, &mod_fault);
3120     setupOperandDescriptorCache (3);
3121 #endif
3122 
3123     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3124     parseAlphanumericOperandDescriptor (2, 1, true, &mod_fault); // use TA1
3125     parseArgOperandDescriptor (3, &mod_fault);
3126 
3127     L68_ (
3128       // L68 raises it immediately
3129       if (mod_fault)
3130         {
3131           doFault (FAULT_IPR,
3132                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3133                    "Illegal modifier");
3134         }
3135     )
3136 
3137     // Bits 0-10 MBZ
3138     if (IWB_IRODD & 0777600000000)
3139       {
3140         //sim_printf ("scd %12"PRIo64"\n", IWB_IRODD);
3141         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scd 0-10 MBZ");
3142       }
3143 
3144     // Bit 23 of OP1 MBZ
3145     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3146       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op1 23 MBZ");
3147 
3148     // Bits 18-28. 30-31 of OP3 MBZ
3149     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3150       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op3 18-28. 30-31 MBZ");
3151 
3152     DPS8M_ (
3153       // DPS8M raises it delayed
3154       if (mod_fault)
3155         {
3156           doFault (FAULT_IPR,
3157                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3158                    "Illegal modifier");
3159         }
3160     )
3161 
3162     // Both the string and the test character pair are treated as the data type
3163     // given for the string, TA1. A data type given for the test character
3164     // pair, TA2, is ignored.
3165 
3166     // fetch 'test' char - double
3167     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3168     // instruction word does not contain an operand descriptor for the test
3169     // character; instead, it contains the test character as a direct upper
3170     // operand in bits 0,8.
3171 
3172     word9 c1 = 0;
3173     word9 c2 = 0;
3174 
3175     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3176       {
3177         // per Bull RJ78, p. 5-45
3178 #ifdef EIS_PTR3
3179         switch (TA1) // Use TA1, not TA2
3180 #else
3181         switch (e -> TA1) // Use TA1, not TA2
3182 #endif
3183         {
3184             case CTA4:
3185 #ifdef EIS_PTR
3186               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3187               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3188 #else
3189               c1 = (e -> ADDR2.address >> 13) & 017;
3190               c2 = (e -> ADDR2.address >>  9) & 017;
3191 #endif
3192               break;
3193 
3194             case CTA6:
3195 #ifdef EIS_PTR
3196               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3197               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3198 #else
3199               c1 = (e -> ADDR2.address >> 12) & 077;
3200               c2 = (e -> ADDR2.address >>  6) & 077;
3201 #endif
3202               break;
3203 
3204             case CTA9:
3205 #ifdef EIS_PTR
3206               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3207               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3208 #else
3209               c1 = (e -> ADDR2.address >> 9) & 0777;
3210               c2 = (e -> ADDR2.address     ) & 0777;
3211 #endif
3212               break;
3213           }
3214       }
3215     else
3216       {
3217         c1 = EISget469 (2, 0);
3218         c2 = EISget469 (2, 1);
3219       }
3220 
3221 #ifdef EIS_PTR3
3222     switch (TA1) // Use TA1, not TA2
3223 #else
3224     switch (e -> TA1) // Use TA1, not TA2
3225 #endif
3226       {
3227         case CTA4:
3228           c1 &= 017;    // keep 4-bits
3229           c2 &= 017;    // keep 4-bits
3230           break;
3231 
3232         case CTA6:
3233           c1 &= 077;    // keep 6-bits
3234           c2 &= 077;    // keep 6-bits
3235           break;
3236 
3237         case CTA9:
3238           c1 &= 0777;   // keep 9-bits
3239           c2 &= 0777;   // keep 9-bits
3240           break;
3241       }
3242 
3243     PNL (L68_ (if (e->N1 < 128)
3244       DU_CYCLE_FLEN_128;))
3245 
3246     word9 yCharn11;
3247     word9 yCharn12;
3248     if (e -> N1)
3249       {
3250         uint limit = e -> N1 - 1;
3251         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3252           {
3253             yCharn11 = EISget469 (1, cpu.du.CHTALLY);
3254             yCharn12 = EISget469 (1, cpu.du.CHTALLY + 1);
3255             if (yCharn11 == c1 && yCharn12 == c2)
3256               break;
3257           }
3258         SC_I_TALLY (cpu.du.CHTALLY == limit);
3259       }
3260     else
3261       {
3262         SET_I_TALLY;
3263       }
3264 
3265     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3266     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3267     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3268 
3269     cleanupOperandDescriptor (1);
3270     cleanupOperandDescriptor (2);
3271     cleanupOperandDescriptor (3);
3272  }
3273 
3274 /*
3275  * SCDR - Scan Characters Double Reverse
3276  */
3277 
3278 void scdr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3279   {
3280     EISstruct * e = & cpu.currentEISinstruction;
3281 
3282     // For i = 1, 2, ..., N1-1
3283     //   C(Y-charn1)N1-i-1,N1-i :: C(Y-charn2)0,1
3284     // On instruction completion, if a match was found:
3285     //   00...0 → C(Y3)0,11
3286     //   i-1 → C(Y3)12,35
3287     // If no match was found:
3288     //   00...0 → C(Y3)0,11
3289     //      N1-1→ C(Y3)12,35
3290     //
3291 
3292     // The REG field of MF1 is checked for a legal code. If DU is specified in
3293     // the REG field of MF2 in one of the four multiword instructions (SCD,
3294     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3295     // the character or characters are arranged within the 18 bits of the word
3296     // address portion of the operand descriptor.
3297 
3298     fault_ipr_subtype_ mod_fault = 0;
3299 
3300 #ifndef EIS_SETUP
3301     setupOperandDescriptor(1, &mod_fault);
3302     setupOperandDescriptor(2, &mod_fault);
3303     setupOperandDescriptorCache(3);
3304 #endif
3305 
3306     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
3307     parseAlphanumericOperandDescriptor(2, 1, true, &mod_fault); // Use TA1
3308     parseArgOperandDescriptor (3, &mod_fault);
3309 
3310     L68_ (
3311       // L68 raises it immediately
3312       if (mod_fault)
3313         {
3314           doFault (FAULT_IPR,
3315                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3316                    "Illegal modifier");
3317         }
3318     )
3319 
3320     // Bits 0-10 MBZ
3321     if (IWB_IRODD & 0777600000000)
3322       {
3323         //sim_printf ("scdr %12"PRIo64"\n", IWB_IRODD);
3324         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scdr 0-10 MBZ");
3325       }
3326 
3327     // Bit 23 of OP1 MBZ
3328     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3329       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op1 23 MBZ");
3330 
3331     // Bits 18-28. 30-31 of OP3 MBZ
3332     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3333       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op3 18-28. 30-31 MBZ");
3334 
3335     DPS8M_ (
3336       // DPS8M raises it delayed
3337       if (mod_fault)
3338         {
3339           doFault (FAULT_IPR,
3340                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3341                    "Illegal modifier");
3342         }
3343     )
3344 
3345     // Both the string and the test character pair are treated as the data type
3346     // given for the string, TA1. A data type given for the test character
3347     // pair, TA2, is ignored.
3348 
3349     // fetch 'test' char - double
3350     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3351     // instruction word does not contain an operand descriptor for the test
3352     // character; instead, it contains the test character as a direct upper
3353     // operand in bits 0,8.
3354 
3355     word9 c1 = 0;
3356     word9 c2 = 0;
3357 
3358     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3359       {
3360         // per Bull RJ78, p. 5-45
3361 #ifdef EIS_PTR3
3362         switch (TA1) // Use TA1, not TA2
3363 #else
3364         switch (e -> TA1)
3365 #endif
3366           {
3367             case CTA4:
3368 #ifdef EIS_PTR
3369               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3370               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3371 #else
3372               c1 = (e -> ADDR2.address >> 13) & 017;
3373               c2 = (e -> ADDR2.address >>  9) & 017;
3374 #endif
3375               break;
3376 
3377             case CTA6:
3378 #ifdef EIS_PTR
3379               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3380               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3381 #else
3382               c1 = (e -> ADDR2.address >> 12) & 077;
3383               c2 = (e -> ADDR2.address >>  6) & 077;
3384 #endif
3385               break;
3386 
3387             case CTA9:
3388 #ifdef EIS_PTR
3389               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3390               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3391 #else
3392               c1 = (e -> ADDR2.address >> 9) & 0777;
3393               c2 = (e -> ADDR2.address     ) & 0777;
3394 #endif
3395               break;
3396           }
3397       }
3398     else
3399       {
3400         c1 = EISget469 (2, 0);
3401         c2 = EISget469 (2, 1);
3402       }
3403 
3404 #ifdef EIS_PTR3
3405     switch (TA1) // Use TA1, not TA2
3406 #else
3407     switch (e -> TA1) // Use TA1, not TA2
3408 #endif
3409       {
3410         case CTA4:
3411           c1 &= 017;    // keep 4-bits
3412           c2 &= 017;    // keep 4-bits
3413           break;
3414 
3415         case CTA6:
3416           c1 &= 077;    // keep 6-bits
3417           c2 &= 077;    // keep 6-bits
3418           break;
3419 
3420         case CTA9:
3421           c1 &= 0777;   // keep 9-bits
3422           c2 &= 0777;   // keep 9-bits
3423           break;
3424       }
3425 
3426     word9 yCharn11;
3427     word9 yCharn12;
3428 
3429     PNL (L68_ (if (e->N1 < 128)
3430       DU_CYCLE_FLEN_128;))
3431 
3432     if (e -> N1)
3433       {
3434         uint limit = e -> N1 - 1;
3435 
3436         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3437           {
3438             yCharn11 = EISget469 (1, limit - cpu.du.CHTALLY - 1);
3439             yCharn12 = EISget469 (1, limit - cpu.du.CHTALLY);
3440 
3441             if (yCharn11 == c1 && yCharn12 == c2)
3442                 break;
3443           }
3444         SC_I_TALLY (cpu.du.CHTALLY == limit);
3445       }
3446     else
3447       {
3448         SET_I_TALLY;
3449       }
3450 
3451     //word36 CY3 = bitfieldInsert36(0, cpu.du.CHTALLY, 0, 24);
3452     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3453     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3454 
3455     cleanupOperandDescriptor (1);
3456     cleanupOperandDescriptor (2);
3457     cleanupOperandDescriptor (3);
3458   }
3459 
3460 /*
3461  * SCM - Scan with Mask
3462  */
3463 
3464 void scm (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3465   {
3466     EISstruct * e = & cpu.currentEISinstruction;
3467 
3468     // For characters i = 1, 2, ..., N1
3469     //   For bits j = 0, 1, ..., 8
3470     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j ⊕ (C(Y-charn2)0)j)
3471     //      If C(Z)0,8 = 00...0, then
3472     //           00...0 → C(Y3)0,11
3473     //           i-1 → C(Y3)12,35
3474     //      otherwise, continue scan of C(Y-charn1)
3475     // If a masked character match was not found, then
3476     //   00...0 → C(Y3)0,11
3477     //   N1 → C(Y3)12,35
3478 
3479     // Starting at location YC1, the L1 type TA1 characters are masked and
3480     // compared with the assumed type TA1 character contained either in
3481     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3482     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3483     // mask is right-justified in bit positions 0-8 of the instruction word.
3484     // Each bit position of the mask that is a 1 prevents that bit position in
3485     // the two characters from entering into the compare.
3486 
3487     // The masked compare operation continues until either a match is found or
3488     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3489     // incremented by 1. When a match is found or when the L1 tally runs out,
3490     // this count is stored right-justified in bits 12-35 of location Y3 and
3491     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3492     // string remain unchanged. The RL bit of the MF2 field is not used.
3493 
3494     // The REG field of MF1 is checked for a legal code. If DU is specified in
3495     // the REG field of MF2 in one of the four multiword instructions (SCD,
3496     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3497     // the character or characters are arranged within the 18 bits of the word
3498     // address portion of the operand descriptor.
3499 
3500     fault_ipr_subtype_ mod_fault = 0;
3501 
3502 #ifndef EIS_SETUP
3503     setupOperandDescriptor (1, &mod_fault);
3504     setupOperandDescriptor (2, &mod_fault);
3505     setupOperandDescriptorCache (3);
3506 #endif
3507 
3508     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3509     parseAlphanumericOperandDescriptor (2, 1, true, &mod_fault);
3510     parseArgOperandDescriptor (3, &mod_fault);
3511 
3512     L68_ (
3513       // L68 raises it immediately
3514       if (mod_fault)
3515         {
3516           doFault (FAULT_IPR,
3517                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3518                    "Illegal modifier");
3519         }
3520     )
3521 
3522     // Bits 9-10 MBZ
3523     if (IWB_IRODD & 0000600000000)
3524       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scm 9-10 MBZ");
3525 
3526     // Bit 23 of OP1 MBZ
3527     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3528       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op1 23 MBZ");
3529 
3530     // Bits 18-28, 39-31 of OP3 MBZ
3531     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3532       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op3 18-28, 39-31 MBZ");
3533 
3534     DPS8M_ (
3535       // DPS8M raises it delayed
3536       if (mod_fault)
3537         {
3538           doFault (FAULT_IPR,
3539                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3540                    "Illegal modifier");
3541         }
3542     )
3543 
3544     // Both the string and the test character pair are treated as the data type
3545     // given for the string, TA1. A data type given for the test character
3546     // pair, TA2, is ignored.
3547 
3548     // get 'mask'
3549     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3550 
3551     // fetch 'test' char
3552     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3553     // instruction word does not contain an operand descriptor for the test
3554     // character; instead, it contains the test character as a direct upper
3555     // operand in bits 0,8.
3556 
3557     word9 ctest = 0;
3558     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3559       {
3560         word18 duo = GETHI (e -> OP2);
3561         // per Bull RJ78, p. 5-45
3562 #ifdef EIS_PTR3
3563         switch (TA1) // Use TA1, not TA2
3564 #else
3565         switch (e -> TA1)
3566 #endif
3567           {
3568             case CTA4:
3569               ctest = (duo >> 13) & 017;
3570               break;
3571             case CTA6:
3572               ctest = (duo >> 12) & 077;
3573               break;
3574             case CTA9:
3575               ctest = (duo >> 9) & 0777;
3576               break;
3577           }
3578       }
3579     else
3580       {
3581         ctest = EISget469 (2, 0);
3582       }
3583 
3584 #ifdef EIS_PTR3
3585     switch (TA1) // Use TA1, not TA2
3586 #else
3587     switch (e -> TA1) // use TA1, not TA2
3588 #endif
3589       {
3590         case CTA4:
3591             ctest &= 017;    // keep 4-bits
3592             break;
3593         case CTA6:
3594             ctest &= 077;    // keep 6-bits
3595             break;
3596         case CTA9:
3597             ctest &= 0777;   // keep 9-bits
3598       }
3599 
3600     PNL (L68_ (if (e->N1 < 128)
3601       DU_CYCLE_FLEN_128;))
3602 
3603     uint limit = e -> N1;
3604 
3605     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3606       {
3607         word9 yCharn1 = EISget469 (1, cpu.du.CHTALLY);
3608         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3609         if (c == 0)
3610           {
3611             //00...0 → C(Y3)0,11
3612             //i-1 → C(Y3)12,35
3613             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3614             break;
3615           }
3616       }
3617     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3618     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3619 
3620     SC_I_TALLY (cpu.du.CHTALLY == limit);
3621 
3622     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3623 
3624     cleanupOperandDescriptor (1);
3625     cleanupOperandDescriptor (2);
3626     cleanupOperandDescriptor (3);
3627   }
3628 /*
3629  * SCMR - Scan with Mask in Reverse
3630  */
3631 
3632 void scmr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3633   {
3634     EISstruct * e = & cpu.currentEISinstruction;
3635 
3636     // For characters i = 1, 2, ..., N1
3637     //   For bits j = 0, 1, ..., 8
3638     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j ⊕ (C(Y-charn2)0)j)
3639     //      If C(Z)0,8 = 00...0, then
3640     //           00...0 → C(Y3)0,11
3641     //           i-1 → C(Y3)12,35
3642     //      otherwise, continue scan of C(Y-charn1)
3643     // If a masked character match was not found, then
3644     //   00...0 → C(Y3)0,11
3645     //   N1 → C(Y3)12,35
3646 
3647     // Starting at location YC1, the L1 type TA1 characters are masked and
3648     // compared with the assumed type TA1 character contained either in
3649     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3650     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3651     // mask is right-justified in bit positions 0-8 of the instruction word.
3652     // Each bit position of the mask that is a 1 prevents that bit position in
3653     // the two characters from entering into the compare.
3654 
3655     // The masked compare operation continues until either a match is found or
3656     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3657     // incremented by 1. When a match is found or when the L1 tally runs out,
3658     // this count is stored right-justified in bits 12-35 of location Y3 and
3659     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3660     // string remain unchanged. The RL bit of the MF2 field is not used.
3661 
3662     // The REG field of MF1 is checked for a legal code. If DU is specified in
3663     // the REG field of MF2 in one of the four multiword instructions (SCD,
3664     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3665     // the character or characters are arranged within the 18 bits of the word
3666     // address portion of the operand descriptor.
3667 
3668     fault_ipr_subtype_ mod_fault = 0;
3669 
3670 #ifndef EIS_SETUP
3671     setupOperandDescriptor (1, &mod_fault);
3672     setupOperandDescriptor (2, &mod_fault);
3673     setupOperandDescriptorCache (3);
3674 #endif
3675 
3676     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3677     parseAlphanumericOperandDescriptor (2, 1, true, &mod_fault);
3678     parseArgOperandDescriptor (3, &mod_fault);
3679 
3680     L68_ (
3681       // L68 raises it immediately
3682       if (mod_fault)
3683         {
3684           doFault (FAULT_IPR,
3685                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3686                    "Illegal modifier");
3687         }
3688     )
3689 
3690     // Bits 9-10 MBZ
3691     if (IWB_IRODD & 0000600000000)
3692       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scmr 9-10 MBZ");
3693 
3694     // Bit 23 of OP1 MBZ
3695     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3696       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op1 23 MBZ");
3697 
3698     // Bits 18 of OP3 MBZ
3699     //if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000400000)
3700     //  doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18 MBZ");
3701 
3702     // Bits 18-28, 39-31 of OP3 MBZ
3703     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3704       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18-28, 39-31 MBZ");
3705 
3706     DPS8M_ (
3707       // DPS8M raises it delayed
3708       if (mod_fault)
3709         {
3710           doFault (FAULT_IPR,
3711                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3712                    "Illegal modifier");
3713         }
3714     )
3715 
3716     // Both the string and the test character pair are treated as the data type
3717     // given for the string, TA1. A data type given for the test character
3718     // pair, TA2, is ignored.
3719 
3720     // get 'mask'
3721     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3722 
3723     // fetch 'test' char
3724     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3725     // instruction word does not contain an operand descriptor for the test
3726     // character; instead, it contains the test character as a direct upper
3727     // operand in bits 0,8.
3728 
3729     word9 ctest = 0;
3730     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3731       {
3732         word18 duo = GETHI (e -> OP2);
3733         // per Bull RJ78, p. 5-45
3734 #ifdef EIS_PTR3
3735         switch (TA1) // Use TA1, not TA2
3736 #else
3737         switch (e -> TA1)
3738 #endif
3739           {
3740             case CTA4:
3741               ctest = (duo >> 13) & 017;
3742               break;
3743             case CTA6:
3744               ctest = (duo >> 12) & 077;
3745               break;
3746             case CTA9:
3747               ctest = (duo >> 9) & 0777;
3748               break;
3749           }
3750       }
3751     else
3752       {
3753         ctest = EISget469 (2, 0);
3754       }
3755 
3756 #ifdef EIS_PTR3
3757     switch (TA1) // Use TA1, not TA2
3758 #else
3759     switch (e -> TA1) // use TA1, not TA2
3760 #endif
3761       {
3762         case CTA4:
3763             ctest &= 017;    // keep 4-bits
3764             break;
3765         case CTA6:
3766             ctest &= 077;    // keep 6-bits
3767             break;
3768         case CTA9:
3769             ctest &= 0777;   // keep 9-bits
3770       }
3771 
3772     PNL (L68_ (if (e->N1 < 128)
3773       DU_CYCLE_FLEN_128;))
3774 
3775     uint limit = e -> N1;
3776     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3777       {
3778         word9 yCharn1 = EISget469 (1, limit - cpu.du.CHTALLY - 1);
3779         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3780         if (c == 0)
3781           {
3782             //00...0 → C(Y3)0,11
3783             //i-1 → C(Y3)12,35
3784             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3785             break;
3786           }
3787       }
3788     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3789     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3790 
3791     SC_I_TALLY (cpu.du.CHTALLY == limit);
3792 
3793     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
3794 
3795     cleanupOperandDescriptor (1);
3796     cleanupOperandDescriptor (2);
3797     cleanupOperandDescriptor (3);
3798   }
3799 
3800 /*
3801  * TCT - Test Character and Translate
3802  */
3803 
3804 
3805 
3806 
3807 
3808 
3809 
3810 
3811 
3812 
3813 
3814 
3815 
3816 
3817 
3818 
3819 
3820 
3821 
3822 
3823 
3824 
3825 static word9 xlate (EISaddr * xlatTbl, uint dstTA, uint c)
     /* [previous][next][first][last][top][bottom][index][help] */
3826   {
3827     uint idx = (c / 4) & 0177;      // max 128-words (7-bit index)
3828     word36 entry = EISReadIdx(xlatTbl, idx);
3829 
3830     uint pos9 = c % 4;      // lower 2-bits
3831     word9 cout = GETBYTE (entry, pos9);
3832     switch (dstTA)
3833       {
3834         case CTA4:
3835           return cout & 017;
3836         case CTA6:
3837           return cout & 077;
3838         case CTA9:
3839           return cout;
3840       }
3841     return 0;
3842   }
3843 
3844 void tct (void)
     /* [previous][next][first][last][top][bottom][index][help] */
3845   {
3846     EISstruct * e = & cpu.currentEISinstruction;
3847 
3848     // For i = 1, 2, ..., N1
3849     //   m = C(Y-charn1)i-1
3850     //   If C(Y-char92)m ≠ 00...0, then
3851     //     C(Y-char92)m → C(Y3)0,8
3852     //     000 → C(Y3)9,11
3853     //     i-1 → C(Y3)12,35
3854     //   otherwise, continue scan of C(Y-charn1)
3855     // If a non-zero table entry was not found, then 00...0 → C(Y3)0,11
3856     // N1 → C(Y3)12,35
3857     //
3858     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
3859     // otherwise, OFF
3860     //
3861     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
3862     // then characters from C(Y-charn1) are high-order zero filled in forming
3863     // the table index, m.
3864     // Instruction execution proceeds until a non-zero table entry is found or
3865     // the string length count is exhausted.
3866     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
3867     // on a word boundary.
3868 
3869     fault_ipr_subtype_ mod_fault = 0;
3870 
3871 #ifndef EIS_SETUP
3872     setupOperandDescriptor (1, &mod_fault);
3873     setupOperandDescriptorCache (2);
3874     setupOperandDescriptorCache (3);
3875 #endif
3876 
3877     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
3878     parseArgOperandDescriptor (2, &mod_fault);
3879     parseArgOperandDescriptor (3, &mod_fault);
3880 
3881     L68_ (
3882       // L68 raises it immediately
3883       if (mod_fault)
3884         {
3885           doFault (FAULT_IPR,
3886                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3887                    "Illegal modifier");
3888         }
3889     )
3890 
3891     // Bits 0-17 MBZ
3892     if (IWB_IRODD & 0777777000000)
3893       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tct 0-17 MBZ");
3894 
3895     // Bit 23 of OP1 MBZ
3896     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3897       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op1 23 MBZ");
3898 
3899     // Bits 18-28, 39-31 of OP2 MBZ
3900     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
3901       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op2 18-28, 39-31 MBZ");
3902 
3903     // Bits 18-28, 39-31 of OP3 MBZ
3904     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3905       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op3 18-28, 39-31 MBZ");
3906 
3907     DPS8M_ (
3908       // DPS8M raises it delayed
3909       if (mod_fault)
3910         {
3911           doFault (FAULT_IPR,
3912                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3913                    "Illegal modifier");
3914         }
3915     )
3916 
3917 #ifdef EIS_PTR3
3918     sim_debug (DBG_TRACEEXT, & cpu_dev,
3919                "TCT CN1: %d TA1: %d\n", e -> CN1, TA1);
3920 #else
3921     sim_debug (DBG_TRACEEXT, & cpu_dev,
3922                "TCT CN1: %d TA1: %d\n", e -> CN1, e -> TA1);
3923 #endif
3924 
3925     uint srcSZ = 0;
3926 
3927 #ifdef EIS_PTR3
3928     switch (TA1)
3929 #else
3930     switch (e -> TA1)
3931 #endif
3932       {
3933         case CTA4:
3934             srcSZ = 4;
3935             break;
3936         case CTA6:
3937             srcSZ = 6;
3938             break;
3939         case CTA9:
3940             srcSZ = 9;
3941             break;
3942       }
3943 
3944     // ISOLTS-878 01h asserts no prepaging
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 
3983     word36 CY3 = 0;
3984 
3985     sim_debug (DBG_TRACEEXT, & cpu_dev,
3986                "TCT N1 %d\n", e -> N1);
3987 
3988     PNL (L68_ (if (e->N1 < 128)
3989       DU_CYCLE_FLEN_128;))
3990 
3991     for ( ; cpu.du.CHTALLY < e -> N1; cpu.du.CHTALLY ++)
3992       {
3993         word9 c = EISget469 (1, cpu.du.CHTALLY); // get src char
3994 
3995         uint m = 0;
3996 
3997         switch (srcSZ)
3998           {
3999             case 4:
4000               m = c & 017;    // truncate upper 2-bits
4001               break;
4002             case 6:
4003               m = c & 077;    // truncate upper 3-bits
4004               break;
4005             case 9:
4006               m = c;          // keep all 9-bits
4007               break;              // should already be 0-filled
4008           }
4009 
4010         word9 cout = xlate (&e->ADDR2, CTA9, m);
4011 
4012         sim_debug (DBG_TRACEEXT, & cpu_dev,
4013                    "TCT c %03o %c cout %03o %c\n",
4014                    m, isprint ((int) m) ? '?' : (char) m,
4015                    cout, isprint ((int) cout) ? '?' : (char) cout);
4016 
4017         if (cout)
4018           {
4019             // CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4020             CY3 = setbits36_9 (0, 0, cout);
4021             break;
4022           }
4023       }
4024 
4025     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4026 
4027     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4028     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4029     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
4030 
4031     cleanupOperandDescriptor (1);
4032     cleanupOperandDescriptor (2);
4033     cleanupOperandDescriptor (3);
4034   }
4035 
4036 void tctr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
4037   {
4038     EISstruct * e = & cpu.currentEISinstruction;
4039 
4040     // For i = 1, 2, ..., N1
4041     //   m = C(Y-charn1)N1-i
4042     //   If C(Y-char92)m ≠ 00...0, then
4043     //     C(Y-char92)m → C(Y3)0,8
4044     //     000 → C(Y3)9,11
4045     //     i-1 → C(Y3)12,35
4046     //   otherwise, continue scan of C(Y-charn1) If a non-zero table entry was
4047     //   not found, then
4048     // 00...0 → C(Y3)0,11
4049     // N1 → C(Y3)12,35
4050     //
4051     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
4052     // otherwise, OFF
4053     //
4054     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
4055     // then characters from C(Y-charn1) are high-order zero filled in forming
4056     // the table index, m.
4057 
4058     // Instruction execution proceeds until a non-zero table entry is found or
4059     // the string length count is exhausted.
4060 
4061     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
4062     // on a word boundary.
4063 
4064     fault_ipr_subtype_ mod_fault = 0;
4065 
4066 #ifndef EIS_SETUP
4067     setupOperandDescriptor (1, &mod_fault);
4068     setupOperandDescriptorCache (2);
4069     setupOperandDescriptorCache (3);
4070 #endif
4071 
4072     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
4073     parseArgOperandDescriptor (2, &mod_fault);
4074     parseArgOperandDescriptor (3, &mod_fault);
4075 
4076     L68_ (
4077       // L68 raises it immediately
4078       if (mod_fault)
4079         {
4080           doFault (FAULT_IPR,
4081                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4082                    "Illegal modifier");
4083         }
4084     )
4085 
4086     // Bits 0-17 MBZ
4087     if (IWB_IRODD & 0777777000000)
4088       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tctr 0-17 MBZ");
4089 
4090     // Bit 23 of OP1 MBZ
4091     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4092       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op1 23 MBZ");
4093 
4094     // Bits 18-28, 39-31 of OP2 MBZ
4095     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
4096       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op2 18-28, 39-31 MBZ");
4097 
4098     // Bits 18-28, 39-31 of OP3 MBZ
4099     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
4100       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op3 18-28, 39-31 MBZ");
4101 
4102     DPS8M_ (
4103       // DPS8M raises it delayed
4104       if (mod_fault)
4105         {
4106           doFault (FAULT_IPR,
4107                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4108                    "Illegal modifier");
4109         }
4110     )
4111 
4112 #ifdef EIS_PTR3
4113     sim_debug (DBG_TRACEEXT, & cpu_dev,
4114                "TCTR CN1: %d TA1: %d\n", e -> CN1, TA1);
4115 #else
4116     sim_debug (DBG_TRACEEXT, & cpu_dev,
4117                "TCTR CN1: %d TA1: %d\n", e -> CN1, e -> TA1);
4118 #endif
4119 
4120     uint srcSZ = 0;
4121 
4122 #ifdef EIS_PTR3
4123     switch (TA1)
4124 #else
4125     switch (e -> TA1)
4126 #endif
4127       {
4128         case CTA4:
4129             srcSZ = 4;
4130             break;
4131         case CTA6:
4132             srcSZ = 6;
4133             break;
4134         case CTA9:
4135             srcSZ = 9;
4136             break;
4137       }
4138 
4139     // ISOLTS-878 01i asserts no prepaging
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 
4178     word36 CY3 = 0;
4179 
4180     sim_debug (DBG_TRACEEXT, & cpu_dev,
4181                "TCT N1 %d\n", e -> N1);
4182 
4183     PNL (L68_ (if (e->N1 < 128)
4184       DU_CYCLE_FLEN_128;))
4185 
4186     uint limit = e -> N1;
4187     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
4188       {
4189         word9 c = EISget469 (1, limit - cpu.du.CHTALLY - 1); // get src char
4190 
4191         uint m = 0;
4192 
4193         switch (srcSZ)
4194           {
4195             case 4:
4196               m = c & 017;    // truncate upper 2-bits
4197               break;
4198             case 6:
4199               m = c & 077;    // truncate upper 3-bits
4200               break;
4201             case 9:
4202               m = c;          // keep all 9-bits
4203               break;              // should already be 0-filled
4204           }
4205 
4206         word9 cout = xlate (&e->ADDR2, CTA9, m);
4207 
4208         sim_debug (DBG_TRACEEXT, & cpu_dev,
4209                    "TCT c %03o %c cout %03o %c\n",
4210                    m, isprint ((int) m) ? '?' : (char) m,
4211                    cout, isprint ((int) cout) ? '?' : (char) cout);
4212 
4213         if (cout)
4214           {
4215             //CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4216             CY3 = setbits36_9 (0, 0, cout);
4217             break;
4218           }
4219       }
4220 
4221     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4222 
4223     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4224     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4225     EISWriteIdx (& e -> ADDR3, 0, CY3, true);
4226 
4227     cleanupOperandDescriptor (1);
4228     cleanupOperandDescriptor (2);
4229     cleanupOperandDescriptor (3);
4230   }
4231 
4232 /*
4233  * MLR - Move Alphanumeric Left to Right
4234  *
4235  * (Nice, simple instruction if it weren't for the stupid overpunch stuff that ruined it!!!!)
4236  */
4237 
4238 /*
4239  * does 6-bit char represent a GEBCD negative overpunch? if so, which numeral?
4240  * Refer to Bull NovaScale 9000 RJ78 Rev2 p11-178
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 
4267 // RJ78 p.11-178,D-6
4268 static bool isGBCDOvp (uint c, bool * isNeg)
     /* [previous][next][first][last][top][bottom][index][help] */
4269   {
4270     if (c & 020)
4271       {
4272         * isNeg = false;
4273         return true;
4274       }
4275     if (c & 040)
4276       {
4277         * isNeg = true;
4278         return true;
4279       }
4280     return false;
4281   }
4282 
4283 // Applies to both MLR and MRL
4284 //
4285 // If L1 is greater than L2, the least significant (L1-L2) characters are not moved and
4286 // the Truncation indicator is set. If L1 is less than L2, bits 0-8, 3-8, or 5-8 of the FILL
4287 // character (depending on TA2) are inserted as the least significant (L2-L1)
4288 // characters. If L1 is less than L2, bit 0 of C(FILL) = 1, TA1 = 01, and TA2 = 10
4289 // (6-4 move); the hardware looks for a 6-bit overpunched sign. If a negative
4290 // overpunch sign is found, a negative sign (octal 15) is inserted as the last FILL
4291 // character. If a negative overpunch sign is not found, a positive sign (octal 14) is
4292 // inserted as the last FILL character
4293 
4294 void mlr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
4295   {
4296     EISstruct * e = & cpu.currentEISinstruction;
4297 
4298     // For i = 1, 2, ..., minimum (N1,N2)
4299     //     C(Y-charn1)N1-i → C(Y-charn2)N2-i
4300     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4301     //    C(FILL) → C(Y-charn2)N2-i
4302     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4303 
4304     fault_ipr_subtype_ mod_fault = 0;
4305 
4306 #ifndef EIS_SETUP
4307     setupOperandDescriptor (1, &mod_fault);
4308     setupOperandDescriptor (2, &mod_fault);
4309     //setupOperandDescriptorCache (3);
4310 #endif
4311 
4312     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
4313     parseAlphanumericOperandDescriptor(2, 2, false, &mod_fault);
4314 
4315     L68_ (
4316       // L68 raises it immediately
4317       if (mod_fault)
4318         {
4319           doFault (FAULT_IPR,
4320                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4321                    "Illegal modifier");
4322         }
4323     )
4324 
4325     // Bit 10 MBZ
4326     if (IWB_IRODD & 0000200000000)
4327       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mlr 10 MBZ");
4328 
4329     // Bit 23 of OP1 MBZ
4330     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4331       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op1 23 MBZ");
4332 
4333     // Bit 23 of OP2 MBZ
4334     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4335       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op2 23 MBZ");
4336 
4337     DPS8M_ (
4338       // DPS8M raises it delayed
4339       if (mod_fault)
4340         {
4341           doFault (FAULT_IPR,
4342                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4343                    "Illegal modifier");
4344         }
4345     )
4346 
4347     int srcSZ = 0, dstSZ = 0;
4348 
4349 #ifdef EIS_PTR3
4350     switch (TA1)
4351 #else
4352     switch (e -> TA1)
4353 #endif
4354       {
4355         case CTA4:
4356           srcSZ = 4;
4357           break;
4358         case CTA6:
4359           srcSZ = 6;
4360           break;
4361         case CTA9:
4362           srcSZ = 9;
4363           break;
4364       }
4365 
4366 #ifdef EIS_PTR3
4367     switch (TA2)
4368 #else
4369     switch (e -> TA2)
4370 #endif
4371       {
4372         case CTA4:
4373           dstSZ = 4;
4374           break;
4375         case CTA6:
4376           dstSZ = 6;
4377           break;
4378         case CTA9:
4379           dstSZ = 9;
4380           break;
4381       }
4382 
4383     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4384 
4385     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4386     word9 fillT = fill;  // possibly truncated fill pattern
4387 
4388     // play with fill if we need to use it
4389     switch (dstSZ)
4390       {
4391         case 4:
4392           fillT = fill & 017;    // truncate upper 5-bits
4393           break;
4394         case 6:
4395           fillT = fill & 077;    // truncate upper 3-bits
4396           break;
4397       }
4398 
4399     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4400     // and the truncation indicator is set ON.
4401 
4402     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4403     // characters are high-order truncated as they are moved to C(Y-charn2). No
4404     // character conversion takes place.
4405 
4406     // The user of string replication or overlaying is warned that the decimal
4407     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4408     // units of Y-block8 words and that the overlayed string, C(Y-charn2), is
4409     // not returned to main memory until the unit of Y-block8 words is filled or
4410     // the instruction completes.
4411 
4412     // If T = 1 and the truncation indicator is set ON by execution of the
4413     // instruction, then a truncation (overflow) fault occurs.
4414 
4415     // Attempted execution with the xed instruction causes an illegal procedure
4416     // fault.
4417 
4418     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4419     // illegal procedure fault.
4420 
4421     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4422       DU_CYCLE_FLEN_128;))
4423 
4424 #ifdef EIS_PTR3
4425     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4426                (TA2 == 2); // (6-4 move)
4427 #else
4428     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4429                (e -> TA2 == 2); // (6-4 move)
4430 #endif
4431     //word9 on;     // number overpunch represents (if any)
4432     bool isNeg = false;
4433     //bool bOvp = false;  // true when a negative overpunch character has been
4434                         // found @ N1-1
4435 
4436 #ifdef EIS_PTR3
4437     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);
4438 #else
4439     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);
4440 #endif
4441 
4442 //
4443 // Multics frequently uses certain code sequences which are easily detected
4444 // and optimized; eg. it uses the MLR instruction to copy or zero segments.
4445 //
4446 // The MLR implementation is correct, not efficient. Copy invokes 12 append
4447 // cycles per word, and fill 8.
4448 //
4449 
4450 //
4451 // Page copy
4452 //
4453 
4454     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4455 #ifdef EIS_PTR3
4456         TA1 == CTA9 &&  // src and dst are both char 9
4457         TA2 == CTA9 &&
4458 #else
4459         e -> TA1 == CTA9 &&  // src and dst are both char 9
4460         e -> TA2 == CTA9 &&
4461 #endif
4462         (e -> N1 % (PGSZ * 4)) == 0 &&  // a page
4463         e -> N2 == e -> N1 && // the src is the same size as the dest.
4464         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4465         e -> CN2 == 0 &&
4466 #ifdef EIS_PTR
4467         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4468         (cpu.du.D2_PTR_W & PGMK) == 0)
4469 #else
4470         (e -> ADDR1.address & PGMK) == 0 &&
4471         (e -> ADDR2.address & PGMK) == 0)
4472 #endif
4473       {
4474         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #3\n");
4475         while (cpu.du.CHTALLY < e -> N1)
4476           {
4477             word36 pg [PGSZ];
4478             EISReadPage (& e -> ADDR1, cpu.du.CHTALLY / 4, pg);
4479             EISWritePage (& e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4480             cpu.du.CHTALLY += PGSZ * 4;
4481           }
4482         cleanupOperandDescriptor (1);
4483         cleanupOperandDescriptor (2);
4484         // truncation fault check does need to be checked for here since
4485         // it is known that N1 == N2
4486         CLR_I_TRUNC;
4487         return;
4488       }
4489 
4490 //
4491 // Page zero
4492 //
4493 
4494     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4495 #ifdef EIS_PTR3
4496         TA1 == CTA9 &&  // src and dst are both char 9
4497         TA2 == CTA9 &&
4498 #else
4499         e -> TA1 == CTA9 &&  // src and dst are both char 9
4500         e -> TA2 == CTA9 &&
4501 #endif
4502         e -> N1 == 0 && // the source is entirely fill
4503         (e -> N2 % (PGSZ * 4)) == 0 &&  // a page
4504         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4505         e -> CN2 == 0 &&
4506 #ifdef EIS_PTR
4507         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4508         (cpu.du.D2_PTR_W& PGMK) == 0)
4509 #else
4510         (e -> ADDR1.address & PGMK) == 0 &&
4511         (e -> ADDR2.address & PGMK) == 0)
4512 #endif
4513       {
4514         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #4\n");
4515         word36 pg [PGSZ];
4516         if (fill)
4517           {
4518             word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4519             for (uint i = 0; i < PGSZ; i ++)
4520               pg [i] = w;
4521           }
4522         else
4523           {
4524            memset (pg, 0, sizeof (pg));
4525           }
4526         while (cpu.du.CHTALLY < e -> N2)
4527           {
4528             EISWritePage (& e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4529             cpu.du.CHTALLY += PGSZ * 4;
4530           }
4531         cleanupOperandDescriptor (1);
4532         cleanupOperandDescriptor (2);
4533         // truncation fault check does need to be checked for here since
4534         // it is known that N1 == N2
4535         CLR_I_TRUNC;
4536         return;
4537       }
4538 
4539 // Test for the case of aligned word move; and do things a word at a time,
4540 // instead of a byte at a time...
4541 
4542 #ifdef EIS_PTR3
4543     if (TA1 == CTA9 &&  // src and dst are both char 9
4544         TA2 == CTA9 &&
4545 #else
4546     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4547         e -> TA2 == CTA9 &&
4548 #endif
4549         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4550         e -> N2 == e -> N1 && // the src is the same size as the dest.
4551         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4552         e -> CN2 == 0)
4553       {
4554         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #1\n");
4555         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4556           {
4557             uint n = cpu.du.CHTALLY / 4;
4558             word36 w = EISReadIdx (& e -> ADDR1, n);
4559             EISWriteIdx (& e -> ADDR2, n, w, true);
4560           }
4561         cleanupOperandDescriptor (1);
4562         cleanupOperandDescriptor (2);
4563         // truncation fault check does need to be checked for here since
4564         // it is known that N1 == N2
4565         CLR_I_TRUNC;
4566         return;
4567       }
4568 
4569 // Test for the case of aligned word fill; and do things a word at a time,
4570 // instead of a byte at a time...
4571 
4572 #ifdef EIS_PTR3
4573     if (TA1 == CTA9 && // src and dst are both char 9
4574         TA2 == CTA9 &&
4575 #else
4576     if (e -> TA1 == CTA9 && // src and dst are both char 9
4577         e -> TA2 == CTA9 &&
4578 #endif
4579         e -> N1 == 0 && // the source is entirely fill
4580         e -> N2 % 4 == 0 && // a whole number of words in the dest
4581         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4582         e -> CN2 == 0)
4583       {
4584         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #2\n");
4585         word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4586         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4587           {
4588             uint n = cpu.du.CHTALLY / 4;
4589             EISWriteIdx (& e -> ADDR2, n, w, true);
4590           }
4591         cleanupOperandDescriptor (1);
4592         cleanupOperandDescriptor (2);
4593         // truncation fault check does need to be checked for here since
4594         // it is known that N1 <= N2
4595         CLR_I_TRUNC;
4596         return;
4597       }
4598 
4599     for ( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
4600       {
4601         word9 c = EISget469 (1, cpu.du.CHTALLY); // get src char
4602         word9 cout = 0;
4603 
4604 #ifdef EIS_PTR3
4605         if (TA1 == TA2)
4606 #else
4607         if (e -> TA1 == e -> TA2)
4608 #endif
4609           EISput469 (2, cpu.du.CHTALLY, c);
4610         else
4611           {
4612             // If data types are dissimilar (TA1 ≠ TA2), each character is
4613             // high-order truncated or zero filled, as appropriate, as it is
4614             // moved. No character conversion takes place.
4615             cout = c;
4616             switch (srcSZ)
4617               {
4618                 case 6:
4619                   switch(dstSZ)
4620                     {
4621                       case 4:
4622                         cout = c & 017;    // truncate upper 2-bits
4623                         break;
4624                       case 9:
4625                         break;              // should already be 0-filled
4626                     }
4627                   break;
4628                 case 9:
4629                   switch(dstSZ)
4630                     {
4631                       case 4:
4632                         cout = c & 017;    // truncate upper 5-bits
4633                         break;
4634                       case 6:
4635                         cout = c & 077;    // truncate upper 3-bits
4636                         break;
4637                     }
4638                   break;
4639               }
4640 
4641             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
4642             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
4643             // negative overpunch sign is found, then the minus sign character
4644             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
4645             // is placed in C(Y-charn2)N2-1.
4646 
4647             if (ovp && (cpu.du.CHTALLY == e -> N1 - 1))
4648               {
4649                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
4650                 // ISOLTS-838 01e, RJ78 p. 11-126
4651                 isGBCDOvp (c, & isNeg);
4652               }
4653             EISput469 (2, cpu.du.CHTALLY, cout);
4654           }
4655       }
4656 
4657     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4658     //    C(FILL) → C(Y-charn2)N2-i
4659     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4660     // characters are high-order truncated as they are moved to C(Y-charn2). No
4661     // character conversion takes place.
4662 
4663     if (e -> N1 < e -> N2)
4664       {
4665         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
4666           {
4667             // if there's an overpunch then the sign will be the last of the fill
4668             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
4669               {
4670                 if (isNeg)
4671                   EISput469 (2, cpu.du.CHTALLY, 015); // 015 is decimal -
4672                 else
4673                   EISput469 (2, cpu.du.CHTALLY, 014); // 014 is decimal +
4674               }
4675             else
4676               EISput469 (2, cpu.du.CHTALLY, fillT);
4677           }
4678     }
4679     cleanupOperandDescriptor (1);
4680     cleanupOperandDescriptor (2);
4681 
4682     if (e -> N1 > e -> N2)
4683       {
4684         SET_I_TRUNC;
4685         if (T && ! TST_I_OMASK)
4686           doFault (FAULT_OFL, fst_zero, "mlr truncation fault");
4687       }
4688     else
4689       CLR_I_TRUNC;
4690   }
4691 
4692 void mrl (void)
     /* [previous][next][first][last][top][bottom][index][help] */
4693   {
4694     EISstruct * e = & cpu.currentEISinstruction;
4695 
4696     // For i = 1, 2, ..., minimum (N1,N2)
4697     //     C(Y-charn1)N1-i → C(Y-charn2)N2-i
4698     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4699     //    C(FILL) → C(Y-charn2)N2-i
4700     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4701 
4702     fault_ipr_subtype_ mod_fault = 0;
4703 
4704 #ifndef EIS_SETUP
4705     setupOperandDescriptor (1, &mod_fault);
4706     setupOperandDescriptor (2, &mod_fault);
4707     //setupOperandDescriptorCache (3);
4708 #endif
4709 
4710     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
4711     parseAlphanumericOperandDescriptor(2, 2, false, &mod_fault);
4712 
4713     L68_ (
4714       // L68 raises it immediately
4715       if (mod_fault)
4716         {
4717           doFault (FAULT_IPR,
4718                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4719                    "Illegal modifier");
4720         }
4721     )
4722 
4723     // Bit 10 MBZ
4724     if (IWB_IRODD & 0000200000000)
4725       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mrl 10 MBZ");
4726 
4727     // Bit 23 of OP1 MBZ
4728     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4729       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op1 23 MBZ");
4730 
4731     // Bit 23 of OP2 MBZ
4732     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4733       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op2 23 MBZ");
4734 
4735     DPS8M_ (
4736       // DPS8M raises it delayed
4737       if (mod_fault)
4738         {
4739           doFault (FAULT_IPR,
4740                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4741                    "Illegal modifier");
4742         }
4743     )
4744 
4745     int srcSZ = 0, dstSZ = 0;
4746 
4747 #ifdef EIS_PTR3
4748     switch (TA1)
4749 #else
4750     switch (e -> TA1)
4751 #endif
4752       {
4753         case CTA4:
4754           srcSZ = 4;
4755           break;
4756         case CTA6:
4757           srcSZ = 6;
4758           break;
4759         case CTA9:
4760           srcSZ = 9;
4761           break;
4762       }
4763 
4764 #ifdef EIS_PTR3
4765     switch (TA2)
4766 #else
4767     switch (e -> TA2)
4768 #endif
4769       {
4770         case CTA4:
4771           dstSZ = 4;
4772           break;
4773         case CTA6:
4774           dstSZ = 6;
4775           break;
4776         case CTA9:
4777           dstSZ = 9;
4778           break;
4779       }
4780 
4781     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4782 
4783     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4784     word9 fillT = fill;  // possibly truncated fill pattern
4785 
4786     // play with fill if we need to use it
4787     switch (dstSZ)
4788       {
4789         case 4:
4790           fillT = fill & 017;    // truncate upper 5-bits
4791           break;
4792         case 6:
4793           fillT = fill & 077;    // truncate upper 3-bits
4794           break;
4795       }
4796 
4797     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4798     // and the truncation indicator is set ON.
4799 
4800     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4801     // characters are high-order truncated as they are moved to C(Y-charn2). No
4802     // character conversion takes place.
4803 
4804     // The user of string replication or overlaying is warned that the decimal
4805     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4806     // units of Y-block8 words and that the overlayed string, C(Y-charn2), is
4807     // not returned to main memory until the unit of Y-block8 words is filled or
4808     // the instruction completes.
4809 
4810     // If T = 1 and the truncation indicator is set ON by execution of the
4811     // instruction, then a truncation (overflow) fault occurs.
4812 
4813     // Attempted execution with the xed instruction causes an illegal procedure
4814     // fault.
4815 
4816     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4817     // illegal procedure fault.
4818 
4819 #ifdef EIS_PTR3
4820     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4821                (TA2 == 2); // (6-4 move)
4822 #else
4823     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4824                (e -> TA2 == 2); // (6-4 move)
4825 #endif
4826     bool isNeg = false;
4827     //bool bOvp = false;  // true when a negative overpunch character has been
4828                         // found @ N1-1
4829 
4830     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4831       DU_CYCLE_FLEN_128;))
4832 
4833 //
4834 // Test for the case of aligned word move; and do things a word at a time,
4835 // instead of a byte at a time...
4836 
4837 #ifdef EIS_PTR3
4838     if (TA1 == CTA9 &&  // src and dst are both char 9
4839         TA2 == CTA9 &&
4840 #else
4841     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4842         e -> TA2 == CTA9 &&
4843 #endif
4844         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4845         e -> N2 == e -> N1 && // the src is the same size as the dest.
4846         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4847         e -> CN2 == 0)
4848       {
4849         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #1\n");
4850         uint limit = e -> N2;
4851         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY += 4)
4852           {
4853             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
4854             word36 w = EISReadIdx (& e -> ADDR1, n);
4855             EISWriteIdx (& e -> ADDR2, n, w, true);
4856           }
4857         cleanupOperandDescriptor (1);
4858         cleanupOperandDescriptor (2);
4859         // truncation fault check does need to be checked for here since
4860         // it is known that N1 == N2
4861         CLR_I_TRUNC;
4862         return;
4863       }
4864 
4865 // Test for the case of aligned word fill; and do things a word at a time,
4866 // instead of a byte at a time...
4867 
4868 #ifdef EIS_PTR3
4869     if (TA1 == CTA9 && // src and dst are both char 9
4870         TA2 == CTA9 &&
4871 #else
4872     if (e -> TA1 == CTA9 && // src and dst are both char 9
4873         e -> TA2 == CTA9 &&
4874 #endif
4875         e -> N1 == 0 && // the source is entirely fill
4876         e -> N2 % 4 == 0 && // a whole number of words in the dest
4877         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4878         e -> CN2 == 0)
4879       {
4880         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #2\n");
4881         word36 w = (word36) fill |
4882                   ((word36) fill << 9) |
4883                   ((word36) fill << 18) |
4884                   ((word36) fill << 27);
4885         uint limit = e -> N2;
4886         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4887           {
4888             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
4889             EISWriteIdx (& e -> ADDR2, n, w, true);
4890           }
4891         cleanupOperandDescriptor (1);
4892         cleanupOperandDescriptor (2);
4893         // truncation fault check does need to be checked for here since
4894         // it is known that N1 <= N2
4895         CLR_I_TRUNC;
4896         return;
4897       }
4898 
4899     for ( ; cpu.du.CHTALLY < min (e -> N1, e -> N2); cpu.du.CHTALLY ++)
4900       {
4901         word9 c = EISget469 (1, e -> N1 - cpu.du.CHTALLY - 1); // get src char
4902         word9 cout = 0;
4903 
4904 #ifdef EIS_PTR3
4905         if (TA1 == TA2)
4906 #else
4907         if (e -> TA1 == e -> TA2)
4908 #endif
4909           EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, c);
4910         else
4911           {
4912             // If data types are dissimilar (TA1 ≠ TA2), each character is
4913             // high-order truncated or zero filled, as appropriate, as it is
4914             // moved. No character conversion takes place.
4915             cout = c;
4916             switch (srcSZ)
4917               {
4918                 case 6:
4919                   switch(dstSZ)
4920                     {
4921                       case 4:
4922                         cout = c & 017;    // truncate upper 2-bits
4923                         break;
4924                       case 9:
4925                         break;              // should already be 0-filled
4926                     }
4927                   break;
4928                 case 9:
4929                   switch(dstSZ)
4930                     {
4931                       case 4:
4932                         cout = c & 017;    // truncate upper 5-bits
4933                         break;
4934                       case 6:
4935                         cout = c & 077;    // truncate upper 3-bits
4936                         break;
4937                     }
4938                   break;
4939               }
4940 
4941             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
4942             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
4943             // negative overpunch sign is found, then the minus sign character
4944             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
4945             // is placed in C(Y-charn2)N2-1.
4946 
4947 // ISOLTS 838 01f, RJ78 p.11-154 - the rightmost digit is examined for overpunch.
4948             if (ovp && (cpu.du.CHTALLY == 0))
4949               {
4950                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
4951                 isGBCDOvp (c, & isNeg);
4952               }
4953             EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, cout);
4954           }
4955       }
4956 
4957     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4958     //    C(FILL) → C(Y-charn2)N2-i
4959     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4960     // characters are high-order truncated as they are moved to C(Y-charn2). No
4961     // character conversion takes place.
4962 
4963     if (e -> N1 < e -> N2)
4964       {
4965         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
4966           {
4967             // if there's an overpunch then the sign will be the last of the fill
4968             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
4969               {
4970                 if (isNeg)
4971                   EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, 015); // 015 is decimal -
4972                 else
4973                   EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, 014); // 014 is decimal +
4974               }
4975             else
4976               {
4977                  EISput469 (2, e -> N2 - cpu.du.CHTALLY - 1, fillT);
4978               }
4979           }
4980     }
4981     cleanupOperandDescriptor (1);
4982     cleanupOperandDescriptor (2);
4983 
4984     if (e -> N1 > e -> N2)
4985       {
4986         SET_I_TRUNC;
4987         if (T && ! TST_I_OMASK)
4988           doFault (FAULT_OFL, fst_zero, "mrl truncation fault");
4989       }
4990     else
4991       CLR_I_TRUNC;
4992   }
4993 
4994 // decimalZero
4995 //
4996 //  Try 1:
4997 //
4998 // This makes MVE 1-28 and all of MVNE work
4999 // Fails MVE 29-37 (6->6)
5000 //    #define decimalZero (e->srcTA != CTA4 ? '0' : 0)
5001 //
5002 // Try 2
5003 // This makes MVE 1-10 and 20-37 and all of MVNE work
5004 // Fails MVE 11-19 (6->9)
5005 //    #define decimalZero (e->srcTA == CTA9 ? '0' : 0)
5006 //
5007 // Try 4
5008 //
5009 #define isDecimalZero(c) ((e->srcTA == CTA9) ? \
5010                           ((c) == '0') : \
5011                           (((c) & 017) == 0))
5012 
5013 /*
5014  * Load the entire sending string number (maximum length 63 characters) into
5015  * the decimal unit input buffer as 4-bit digits (high-order truncating 9-bit
5016  * data). Strip the sign and exponent characters (if any), put them aside into
5017  * special holding registers and decrease the input buffer count accordingly.
5018  */
5019 
5020 static void EISloadInputBufferNumeric (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5021 {
5022     EISstruct * e = & cpu.currentEISinstruction;
5023 
5024     word9 *p = e->inBuffer; // p points to position in inBuffer where 4-bit chars are stored
5025     memset(e->inBuffer, 0, sizeof(e->inBuffer));   // initialize to all 0's
5026 
5027     int pos = (int) e->CN[k-1];
5028 
5029     int TN = (int) e->TN[k-1];
5030     int S = (int) e->S[k-1];  // This is where MVNE gets really nasty.
5031     // I spit on the designers of this instruction set (and of COBOL.) >Ptui!<
5032 
5033     int N = (int) e->N[k-1];  // number of chars in src string
5034 
5035     EISaddr *a = &e->addr[k-1];
5036 
5037     e->sign = 1;
5038     e->exponent = 0;
5039 
5040     for(int n = 0 ; n < N ; n += 1)
5041     {
5042         word9 c = EISget49(a, &pos, TN);
5043         sim_debug (DBG_TRACEEXT, & cpu_dev, "src: %d: %o\n", n, c);
5044 
5045         /*
5046          * Here we need to distinguish between 4 type of numbers.
5047          *
5048          * CSFL - Floating-point, leading sign
5049          * CSLS - Scaled fixed-point, leading sign
5050          * CSTS - Scaled fixed-point, trailing sign
5051          * CSNS - Scaled fixed-point, unsigned
5052          */
5053         switch(S)
5054         {
5055             case CSFL:  // this is the real evil one ....
5056                 // Floating-point:
5057                 // [sign=c0] c1×10(n-3) + c2×10(n-4) + ... + c(n-3) [exponent=8
5058                 // bits]
5059                 //
5060                 // where:
5061                 //
5062                 //  ci is the decimal value of the byte in the ith byte
5063                 //  position.
5064                 //
5065                 //  [sign=ci] indicates that ci is interpreted as a sign byte.
5066                 //
5067                 //  [exponent=8 bits] indicates that the exponent value is
5068                 //  taken from the last 8 bits of the string. If the data is in
5069                 //  9-bit bytes, the exponent is bits 1-8 of c(n-1). If the
5070                 //  data is in 4- bit bytes, the exponent is the binary value
5071                 //  of the concatenation of c(n-2) and c(n-1).
5072 
5073                 if (n == 0) // first had better be a sign ....
5074                 {
5075                     c &= 0xf;   // hack off all but lower 4 bits
5076 
5077                     if (c < 012 || c > 017) //-V560
5078                       doFault (FAULT_IPR,
5079                                fst_ill_dig,
5080                                "loadInputBufferNumeric(1): illegal char in "
5081                                "input");
5082 
5083                     if (c == 015)   // '-'
5084                         e->sign = -1;
5085 
5086                     e->srcTally -= 1;   // 1 less source char
5087                 }
5088                 else if (TN == CTN9 && n == N-1)    // the 9-bit exponent (of which only 8-bits are used)
5089                 {
5090                     e->exponent = (signed char)(c & 0377); // want to do a sign extend
5091                     e->srcTally -= 1;   // 1 less source char
5092                 }
5093                 else if (TN == CTN4 && n == N-2)    // the 1st 4-chars of the 8-bit exponent
5094                 {
5095                     e->exponent = (c & 0xf);// << 4;
5096                     e->exponent <<= 4;
5097                     e->srcTally -= 1;   // 1 less source char
5098                 }
5099                 else if (TN == CTN4 && n == N-1)    // the 2nd 4-chars of the 8-bit exponent
5100                 {
5101                     e->exponent |= (c & 0xf);
5102 
5103                     signed char ce = (signed char) (e->exponent & 0xff);
5104                     e->exponent = ce;
5105 
5106                     e->srcTally -= 1;   // 1 less source char
5107                 }
5108                 else
5109                 {
5110                     c &= 0xf;   // hack off all but lower 4 bits
5111                     if (c > 011)
5112                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(2): illegal char in input"); // TODO: generate ill proc fault
5113 
5114                     *p++ = c; // store 4-bit char in buffer
5115                 }
5116                 break;
5117 
5118             case CSLS:
5119                 // 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
5120                 c &= 0xf;   // hack off all but lower 4 bits
5121 
5122                 if (n == 0) // first had better be a sign ....
5123                 {
5124                     if (c < 012 || c > 017) //-V560
5125                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(3): illegal char in input"); // TODO: generate ill proc fault
5126 
5127                     if (c == 015)  // '-'
5128                         e->sign = -1;
5129                     e->srcTally -= 1;   // 1 less source char
5130                 }
5131                 else
5132                 {
5133                     if (c > 011) //-V560
5134                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(4): illegal char in input");
5135                     *p++ = c; // store 4-bit char in buffer
5136                 }
5137                 break;
5138 
5139             case CSTS:
5140                 c &= 0xf;   // hack off all but lower 4 bits
5141 
5142                 if (n == N-1) // last had better be a sign ....
5143                 {
5144                     if (c < 012 || c > 017) //-V560
5145                          doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(5): illegal char in input");
5146                     if (c == 015)   // '-'
5147                         e->sign = -1;
5148                     e->srcTally -= 1;   // 1 less source char
5149                 }
5150                 else
5151                 {
5152                     if (c > 011)
5153                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(6): illegal char in input");
5154                     *p++ = c; // store 4-bit char in buffer
5155                 }
5156                 break;
5157 
5158             case CSNS:
5159                 c &= 0xf; // hack off all but lower 4 bits
5160 
5161                 *p++ = c; // the "easy" one
5162                 break;
5163         }
5164     }
5165     if_sim_debug (DBG_TRACEEXT, & cpu_dev)
5166       {
5167         sim_debug (DBG_TRACEEXT, & cpu_dev, "inBuffer:");
5168         for (word9 *q = e->inBuffer; q < p; q ++)
5169           sim_debug (DBG_TRACEEXT, & cpu_dev, " %02o", * q);
5170         sim_debug (DBG_TRACEEXT, & cpu_dev, "\n");
5171       }
5172 }
5173 
5174 /*
5175  * Load decimal unit input buffer with sending string characters. Data is read
5176  * from main memory in unaligned units (not modulo 8 boundary) of Y-block8
5177  * words. The number of characters loaded is the minimum of the remaining
5178  * sending string count, the remaining receiving string count, and 64.
5179  */
5180 
5181 static void EISloadInputBufferAlphnumeric (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5182   {
5183     EISstruct * e = & cpu.currentEISinstruction;
5184     // p points to position in inBuffer where 4-bit chars are stored
5185     word9 * p = e -> inBuffer;
5186     memset (e -> inBuffer, 0, sizeof (e -> inBuffer));// initialize to all 0's
5187 
5188     // minimum of the remaining sending string count, the remaining receiving
5189     // string count, and 64.
5190     // uint N = min3 (e -> N1, e -> N3, 64);
5191     // The above AL39 rule doesn't work with IGN and possibly other MOPs as
5192     // well. Workaround: Load all source, but max 63 characters (as RJ78
5193     // suggests).
5194     uint N = min (e-> N1, 63);
5195 
5196     for (uint n = 0 ; n < N ; n ++)
5197       {
5198         word9 c = EISget469 (k, n);
5199         * p ++ = c;
5200       }
5201 }
5202 
5203 static void EISwriteOutputBufferToMemory (int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5204   {
5205     EISstruct * e = & cpu.currentEISinstruction;
5206 
5207     for (uint n = 0 ; n < (uint) e -> dstTally; n ++)
5208       {
5209         word9 c49 = e -> outBuffer [n];
5210         EISput469 (k, n, c49);
5211       }
5212   }
5213 
5214 static void writeToOutputBuffer (word9 **dstAddr, int szSrc, int szDst, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
5215 {
5216     EISstruct * e = & cpu.currentEISinstruction;
5217     // 4. If an edit insertion table entry or MOP insertion character is to be
5218     // stored, ANDed, or ORed into a receiving string of 4- or 6-bit
5219     // characters, high-order truncate the character accordingly.
5220     // 5. (MVNE) If the receiving string is 9-bit characters, high-order fill
5221     // the (4-bit) digits from the input buffer with bits 0-4 of character 8 of
5222     // the edit insertion table. If the receiving string is 6-bit characters,
5223     // high-order fill the digits with "00"b.
5224 
5225     if (e -> mvne)
5226       {
5227         switch (szSrc)   // XXX according to rule 1 of Numeric Edit,
5228                          // input should be 4bits. this needs cleaning
5229           {
5230             case 4:
5231               switch (szDst)
5232                 {
5233                   case 4:
5234                     ** dstAddr = c49 & 0xf;
5235                     break;
5236                   case 6:
5237                     ** dstAddr = c49 & 077;   // high-order fill the digits with "00"b.
5238                     break;
5239                   case 9:
5240                     ** dstAddr = c49 | (e -> editInsertionTable [7] & 0760);
5241                     break;
5242                 }
5243               break;
5244             case 6:
5245               switch (szDst)
5246                 {
5247                   case 4:
5248                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5249                     break;
5250                   case 6:
5251                     ** dstAddr = c49; //-V1037 // XXX is this safe? shouldn't it be & 077 ???
5252                     break;
5253                   case 9:
5254                     ** dstAddr = c49; //-V1037
5255                     break;
5256                 }
5257               break;
5258             // Note: case szSrc == 9 is also used for writing edit table
5259             // entries and MOP insertion characters which shall NOT be
5260             // transformed by rule 5
5261             case 9:
5262               switch(szDst)
5263                 {
5264                   case 4:
5265                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5266                     break;
5267                   case 6:
5268                     ** dstAddr = c49 & 077;   // write only 6-bits
5269                     break;
5270                   case 9:
5271                     ** dstAddr = c49;
5272                     break;
5273                 }
5274               break;
5275           }
5276       }
5277     else // mve
5278       {
5279         switch(szDst)
5280           {
5281             case 4:
5282               ** dstAddr = c49 & 0xf;    // write only-4-bits
5283               break;
5284             case 6:
5285               ** dstAddr = c49 & 077;   // write only 6-bits
5286               break;
5287             case 9:
5288               ** dstAddr = c49;
5289               break;
5290           }
5291       }
5292     e->dstTally -= 1;
5293     *dstAddr += 1;
5294 }
5295 
5296 /*!
5297  * This is the Micro Operation Executor/Interpreter
5298  */
5299 
5300 static char* defaultEditInsertionTable = " *+-$,.0";
5301 
5302 // Edit Flags
5303 //
5304 // The processor provides the following four edit flags for use by the micro
5305 // operations.
5306 //
5307 // bool mopES = false; // End Suppression flag; initially OFF, set ON by a
5308 // micro operation when zero-suppression ends.
5309 //
5310 // bool mopSN = false;
5311 // Sign flag; initially set OFF if the sending string has an alphanumeric
5312 // descriptor or an unsigned numeric descriptor. If the sending string has a
5313 // signed numeric descriptor, the sign is initially read from the sending
5314 // string from the digit position defined by the sign and the decimal type
5315 // field (S); SN is set OFF if positive, ON if negative. If all digits are
5316 // zero, the data is assumed positive and the SN flag is set OFF, even when the
5317 // sign is negative.
5318 //
5319 //bool mopBZ = false; i
5320 // Blank-when-zero flag; initially set OFF and set ON by either the ENF or SES
5321 // micro operation. If, at the completion of a move (L1 exhausted), both the Z
5322 // and BZ flags are ON, the receiving string is filled with character 1 of the
5323 // edit insertion table.
5324 
5325 /*!
5326  * CHT Micro Operation - Change Table
5327  * EXPLANATION: The edit insertion table is replaced by the string of eight
5328  * 9-bit characters immediately following the CHT micro operation.
5329  * FLAGS: None affected
5330  * NOTE: C(IF) is not interpreted for this operation.
5331  */
5332 
5333 static int mopCHT (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5334 {
5335     EISstruct * e = & cpu.currentEISinstruction;
5336     memset(&e->editInsertionTable, 0, sizeof(e->editInsertionTable)); // XXX do we really need this?
5337     for(int i = 0 ; i < 8 ; i += 1)
5338     {
5339         if (e->mopTally == 0)
5340         {
5341             e->_faults |= FAULT_IPR;
5342             break;
5343         }
5344 #ifdef EIS_PTR2
5345         word9 entry = EISget49(&e->ADDR2, &e->mopPos, CTN9);  // get mop table entries
5346 #else
5347         word9 entry = EISget49(e->mopAddress, &e->mopPos, CTN9);  // get mop table entries
5348 #endif
5349         e->editInsertionTable[i] = entry & 0777;            // keep to 9-bits
5350         e->mopTally -= 1;
5351     }
5352     return 0;
5353 }
5354 
5355 /*!
5356  * ENF Micro Operation - End Floating Suppression
5357  * EXPLANATION:
5358  *  Bit 0 of IF, IF(0), specifies the nature of the floating suppression. Bit 1
5359  *  of IF, IF(1), specifies if blank when zero option is used.
5360  * For IF(0) = 0 (end floating-sign operation),
5361  * − If ES is OFF and SN is OFF, then edit insertion table entry 3 is moved to
5362  * the receiving field and ES is set ON.
5363  * − If ES is OFF and SN is ON, then edit insertion table entry 4 is moved to
5364  * the receiving field and ES is set ON.
5365  * − If ES is ON, no action is taken.
5366  * For IF(0) = 1 (end floating currency symbol operation),
5367  * − If ES is OFF, then edit insertion table entry 5 is moved to the receiving
5368  * field and ES is set ON.
5369  * − If ES is ON, no action is taken.
5370  * For IF(1) = 1 (blank when zero): the BZ flag is set ON. For IF(1) = 0 (no
5371  * blank when zero): no action is taken.
5372  * FLAGS: (Flags not listed are not affected)
5373  *      ES - If OFF, then set ON
5374  *      BZ - If bit 1 of C(IF) = 1, then set ON; otherwise, unchanged
5375  */
5376 
5377 static int mopENF (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5378 {
5379     EISstruct * e = & cpu.currentEISinstruction;
5380     // For IF(0) = 0 (end floating-sign operation),
5381     if (!(e->mopIF & 010))
5382     {
5383         // 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.
5384         if (!e->mopES && !e->mopSN)
5385         {
5386             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[2]);
5387             e->mopES = true;
5388         }
5389         // 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.
5390         if (!e->mopES && e->mopSN)
5391         {
5392             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[3]);
5393             e->mopES = true;
5394         }
5395         // If ES is ON, no action is taken.
5396     } else { // IF(0) = 1 (end floating currency symbol operation),
5397         if (!e->mopES)
5398         {
5399             // If ES is OFF, then edit insertion table entry 5 is moved to the receiving field and ES is set ON.
5400             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5401             e->mopES = true;
5402         }
5403         // If ES is ON, no action is taken.
5404     }
5405 
5406     // 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.
5407     if (e->mopIF & 04)
5408         e->mopBZ = true;
5409 
5410     return 0;
5411 }
5412 
5413 /*!
5414  * IGN Micro Operation - Ignore Source Characters
5415  * EXPLANATION:
5416  * IF specifies the number of characters to be ignored, where IF = 0 specifies
5417  * 16 characters.
5418  * The next IF characters in the source data field are ignored and the sending
5419  * tally is reduced accordingly.
5420  * FLAGS: None affected
5421  */
5422 
5423 static int mopIGN (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5424 {
5425     EISstruct * e = & cpu.currentEISinstruction;
5426 // AL-39 doesn't specify the == 0 test, but NovaScale does;
5427 // also ISOLTS ps830 test-04a seems to rely on it.
5428     if (e->mopIF == 0)
5429         e->mopIF = 16;
5430 
5431     for(int n = 0 ; n < e->mopIF ; n += 1)
5432     {
5433         if (e->dstTally == 0)
5434             break;
5435         if (e->srcTally == 0)
5436         {
5437             // IGN doesn't allow BZ, raise IPR straight away
5438             e->_faults |= FAULT_IPR;
5439             break;
5440         }
5441 
5442         e->srcTally -= 1;
5443         e->in += 1;
5444     }
5445     return 0;
5446 }
5447 
5448 /*!
5449  * INSA Micro Operation - Insert Asterisk on Suppression
5450  * EXPLANATION:
5451  * This MOP is the same as INSB except that if ES is OFF, then edit insertion
5452  * table entry 2 is moved to the receiving field.
5453  * FLAGS: None affected
5454  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5455  */
5456 
5457 static int mopINSA (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5458 {
5459     EISstruct * e = & cpu.currentEISinstruction;
5460     // If C(IF) = 9-15, an IPR fault occurs.
5461     if (e->mopIF >= 9 && e->mopIF <= 15)
5462     {
5463         e->_faults |= FAULT_IPR;
5464         return 0;
5465     }
5466 
5467 
5468     // If ES is OFF, then edit insertion table entry 1 is moved to the
5469     // receiving field. If IF = 0, then the next 9 bits are also skipped. If IF
5470     // is not 0, the next 9 bits are treated as a MOP.
5471 
5472     if (!e->mopES)
5473       {
5474         writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[1]);
5475 
5476         if (e->mopIF == 0)
5477           {
5478             if (e->mopTally == 0)
5479               {
5480                 e->_faults |= FAULT_IPR;
5481                 return 0;
5482               }
5483 # ifdef EIS_PTR2
5484             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5485 # else
5486             EISget49(e->mopAddress, &e->mopPos, CTN9);
5487 # endif
5488             e->mopTally -= 1;
5489           }
5490       }
5491 
5492     // If ES is ON and IF = 0, then the 9-bit character immediately following
5493     // the INSB micro-instruction is moved to the receiving field
5494     else
5495       {
5496         if (e->mopIF == 0)
5497           {
5498             if (e->mopTally == 0)
5499               {
5500                 e->_faults |= FAULT_IPR;
5501                 return 0;
5502               }
5503 # ifdef EIS_PTR2
5504             word9 c = EISget49(&e->ADDR2, &e->mopPos, CTN9);
5505 # else
5506             word9 c = EISget49(e->mopAddress, &e->mopPos, CTN9);
5507 # endif
5508             writeToOutputBuffer(&e->out, 9, e->dstSZ, c);
5509             e->mopTally -= 1;
5510           }
5511     // If ES is ON and IF<>0, then IF specifies which edit insertion table
5512     // entry (1-8) is to be moved to the receiving field.
5513         else
5514           {
5515             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF-1]);
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 
5567     return 0;
5568 }
5569 
5570 /*!
5571  * INSB Micro Operation - Insert Blank on Suppression
5572  * EXPLANATION:
5573  * IF specifies which edit insertion table entry is inserted.
5574  * If IF = 0, the 9 bits immediately following the INSB micro operation are
5575  * treated as a 9-bit character (not a MOP) and are moved or skipped according
5576  * to ES.
5577  * − If ES is OFF, then edit insertion table entry 1 is moved to the receiving
5578  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5579  * next 9 bits are treated as a MOP.
5580  * − If ES is ON and IF = 0, then the 9-bit character immediately following the
5581  * INSB micro-instruction is moved to the receiving field.
5582  * − If ES is ON and IF<>0, then IF specifies which edit insertion table entry
5583  * (1-8) is to be moved to the receiving field.
5584  * FLAGS: None affected
5585  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5586  */
5587 
5588 static int mopINSB (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5589 {
5590     EISstruct * e = & cpu.currentEISinstruction;
5591     // If C(IF) = 9-15, an IPR fault occurs.
5592     if (e->mopIF >= 9 && e->mopIF <= 15)
5593     {
5594         e->_faults |= FAULT_IPR;
5595         return 0;
5596     }
5597 
5598     if (!e->mopES)
5599     {
5600         // If ES is OFF, then edit insertion table entry 1 is moved to the
5601         // receiving field. If IF = 0, then the next 9 bits are also skipped.
5602         // If IF is not 0, the next 9 bits are treated as a MOP.
5603         writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5604 
5605         if (e->mopIF == 0)
5606         {
5607             if (e->mopTally == 0)
5608             {
5609                 e->_faults |= FAULT_IPR;
5610                 return 0;
5611             }
5612 #ifdef EIS_PTR2
5613             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5614 #else
5615             EISget49(e->mopAddress, &e->mopPos, CTN9);
5616 #endif
5617             e->mopTally -= 1;
5618         }
5619 
5620     } else {
5621 
5622         // ES is ON
5623 
5624         // If C(IF) != 0
5625         if (e->mopIF)
5626         {
5627             // If ES is ON and IF<>0, then IF specifies which edit
5628             // insertion table entry (1-8) is to be moved to the receiving
5629             // field.
5630             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5631         } else {
5632             // If ES is ON and IF = 0, then the 9-bit character immediately
5633             // following the INSB micro-instruction is moved to the
5634             // receiving field.
5635             if (e->mopTally == 0)
5636             {
5637                 e->_faults |= FAULT_IPR;
5638                 return 0;
5639             }
5640 #ifdef EIS_PTR2
5641             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(&e->ADDR2, &e->mopPos, CTN9));
5642             //EISget49(&e->ADDR2, &e->mopPos, CTN9);
5643 #else
5644             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(e->mopAddress, &e->mopPos, CTN9));
5645             //EISget49(e->mopAddress, &e->mopPos, CTN9);
5646 #endif
5647             e->mopTally -= 1;
5648 
5649         }
5650     }
5651     return 0;
5652 }
5653 
5654 /*!
5655  * INSM Micro Operation - Insert Table Entry One Multiple
5656  * EXPLANATION:
5657  * IF specifies the number of receiving characters affected, where IF = 0
5658  * specifies 16 characters.
5659  * Edit insertion table entry 1 is moved to the next IF (1-16) receiving field
5660  * characters.
5661  * FLAGS: None affected
5662  */
5663 
5664 static int mopINSM (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5665 {
5666     EISstruct * e = & cpu.currentEISinstruction;
5667     if (e->mopIF == 0)
5668         e->mopIF = 16;
5669     for(int n = 0 ; n < e->mopIF ; n += 1)
5670     {
5671         if (e->dstTally == 0)
5672           break;
5673         writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5674     }
5675     return 0;
5676 }
5677 
5678 /*!
5679  * INSN Micro Operation - Insert on Negative
5680  * EXPLANATION:
5681  * IF specifies which edit insertion table entry is inserted. If IF = 0, the 9
5682  * bits immediately following the INSN micro operation are treated as a 9-bit
5683  * character (not a MOP) and are moved or skipped according to SN.
5684  * − If SN is OFF, then edit insertion table entry 1 is moved to the receiving
5685  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5686  * next 9 bits are treated as a MOP.
5687  * − If SN is ON and IF = 0, then the 9-bit character immediately following the
5688  * INSN micro-instruction is moved to the receiving field.
5689  * − If SN is ON and IF <> 0, then IF specifies which edit insertion table
5690  * entry (1-8) is to be moved to the receiving field.
5691  * FLAGS: None affected
5692  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5693  */
5694 
5695 static int mopINSN (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5696 {
5697     EISstruct * e = & cpu.currentEISinstruction;
5698     // If C(IF) = 9-15, an IPR fault occurs.
5699     if (e->mopIF >= 9 && e->mopIF <= 15)
5700     {
5701         e->_faults |= FAULT_IPR;
5702         return 0;
5703     }
5704 
5705     // If IF = 0, the 9 bits immediately following the INSN micro operation are
5706     // treated as a 9-bit character (not a MOP) and are moved or skipped
5707     // according to SN.
5708 
5709     if (e->mopIF == 0)
5710     {
5711         if (e->mopTally == 0)
5712         {
5713             e->_faults |= FAULT_IPR;
5714             return 0;
5715         }
5716       if (!e->mopSN)
5717         {
5718             //If SN is OFF, then edit insertion table entry 1 is moved to the
5719             //receiving field. If IF = 0, then the next 9 bits are also
5720             //skipped. If IF is not 0, the next 9 bits are treated as a MOP.
5721 #ifdef EIS_PTR2
5722             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5723 #else
5724             EISget49(e->mopAddress, &e->mopPos, CTN9);
5725 #endif
5726             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5727             e->mopTally -= 1;
5728         } else {
5729             // If SN is ON and IF = 0, then the 9-bit character immediately
5730             // following the INSN micro-instruction is moved to the receiving
5731             // field.
5732 #ifdef EIS_PTR2
5733             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(&e->ADDR2, &e->mopPos, CTN9));
5734 #else
5735             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(e->mopAddress, &e->mopPos, CTN9));
5736 #endif
5737 
5738             e->mopTally -= 1;
5739         }
5740     }
5741     else
5742     {
5743         if (e->mopSN)
5744         {
5745             //If SN is ON and IF <> 0, then IF specifies which edit insertion
5746             //table entry (1-8) is to be moved to the receiving field.
5747             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5748         } else {
5749             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5750         }
5751     }
5752     return 0;
5753 }
5754 
5755 /*!
5756  * INSP Micro Operation - Insert on Positive
5757  * EXPLANATION:
5758  * INSP is the same as INSN except that the responses for the SN values are
5759  * reversed.
5760  * FLAGS: None affected
5761  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5762  */
5763 
5764 static int mopINSP (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5765 {
5766     EISstruct * e = & cpu.currentEISinstruction;
5767     // If C(IF) = 9-15, an IPR fault occurs.
5768     if (e->mopIF >= 9 && e->mopIF <= 15)
5769     {
5770         e->_faults |= FAULT_IPR;
5771         return 0;
5772     }
5773 
5774     if (e->mopIF == 0)
5775     {
5776         if (e->mopTally == 0)
5777         {
5778             e->_faults |= FAULT_IPR;
5779             return 0;
5780         }
5781         if (e->mopSN)
5782         {
5783 #ifdef EIS_PTR2
5784             EISget49(&e->ADDR2, &e->mopPos, CTN9);
5785 #else
5786             EISget49(e->mopAddress, &e->mopPos, CTN9);
5787 #endif
5788             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5789             e->mopTally -= 1;
5790         } else {
5791 #ifdef EIS_PTR2
5792             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(&e->ADDR2, &e->mopPos, CTN9));
5793 #else
5794             writeToOutputBuffer(&e->out, 9, e->dstSZ, EISget49(e->mopAddress, &e->mopPos, CTN9));
5795 #endif
5796             e->mopTally -= 1;
5797         }
5798     }
5799     else
5800     {
5801         if (!e->mopSN)
5802         {
5803             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5804         } else {
5805             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5806         }
5807     }
5808 
5809     return 0;
5810 }
5811 
5812 /*!
5813  * LTE Micro Operation - Load Table Entry
5814  * EXPLANATION:
5815  * IF specifies the edit insertion table entry to be replaced.
5816  * The edit insertion table entry specified by IF is replaced by the 9-bit
5817  * character immediately following the LTE microinstruction.
5818  * FLAGS: None affected
5819  * NOTE: If C(IF) = 0 or C(IF) = 9-15, an Illegal Procedure fault occurs.
5820  */
5821 
5822 static int mopLTE (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5823 {
5824     EISstruct * e = & cpu.currentEISinstruction;
5825     if (e->mopIF == 0 || (e->mopIF >= 9 && e->mopIF <= 15))
5826     {
5827         e->_faults |= FAULT_IPR;
5828         return 0;
5829     }
5830     if (e->mopTally == 0)
5831     {
5832         e->_faults |= FAULT_IPR;
5833         return 0;
5834     }
5835 #ifdef EIS_PTR2
5836     word9 next = EISget49(&e->ADDR2, &e->mopPos, CTN9);
5837 #else
5838     word9 next = EISget49(e->mopAddress, &e->mopPos, CTN9);
5839 #endif
5840     e->mopTally -= 1;
5841 
5842     e->editInsertionTable[e->mopIF - 1] = next;
5843     sim_debug (DBG_TRACEEXT, & cpu_dev, "LTE IT[%d]<=%d\n", e -> mopIF - 1, next);
5844     return 0;
5845 }
5846 
5847 /*!
5848  * MFLC Micro Operation - Move with Floating Currency Symbol Insertion
5849  * EXPLANATION:
5850  * IF specifies the number of characters of the sending field upon which the
5851  * operation is performed, where IF = 0 specifies 16 characters.
5852  * Starting with the next available sending field character, the next IF
5853  * characters are individually fetched and the following conditional actions
5854  * occur.
5855  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
5856  * moved to the receiving field in place of the character.
5857  * − If ES is OFF and the character is not zero, then edit insertion table
5858  * entry 5 is moved to the receiving field, the character is also moved to the
5859  * receiving field, and ES is set ON.
5860  * − If ES is ON, the character is moved to the receiving field.
5861  * The number of characters placed in the receiving field is data-dependent. If
5862  * the entire sending field is zero, IF characters are placed in the receiving
5863  * field. However, if the sending field contains a nonzero character, IF+1
5864  * characters (the insertion character plus the characters from the sending
5865  * field) are placed in the receiving field.
5866  * An IPR fault occurs when the sending field is exhausted before the receiving
5867  * field is filled. In order to provide space in the receiving field for an
5868  * inserted currency symbol, the receiving field must have a string length one
5869  * character longer than the sending field. When the sending field is all
5870  * zeros, no currency symbol is inserted by the MFLC micro operation and the
5871  * receiving field is not filled when the sending field is exhausted. The user
5872  * should provide an ENF (ENF,12) micro operation after a MFLC micro operation
5873  * that has as its character count the number of characters in the sending
5874  * field. The ENF micro operation is engaged only when the MFLC micro operation
5875  * fails to fill the receiving field. Then it supplies a currency symbol to
5876  * fill the receiving field and blanks out the entire field.
5877  * FLAGS: (Flags not listed are not affected.)
5878  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
5879  * is unchanged.
5880  * NOTE: Since the number of characters moved to the receiving string is
5881  * data-dependent, a possible IPR fault may be avoided by ensuring that the Z
5882  * and BZ flags are ON.
5883  */
5884 
5885 static int mopMFLC (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5886 {
5887     EISstruct * e = & cpu.currentEISinstruction;
5888     if (e->mopIF == 0)
5889         e->mopIF = 16;
5890 
5891     //  Starting with the next available sending field character, the next IF
5892     //  characters are individually fetched and the following conditional
5893     //  actions occur.
5894     sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC IF %d, srcTally %d, dstTally %d\n", e->mopIF, e->srcTally, e->dstTally);
5895     for(int n = 0 ; n < e->mopIF ; n += 1)
5896     {
5897         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC n %d, srcTally %d, dstTally %d\n", n, e->srcTally, e->dstTally);
5898         if (e->dstTally == 0)
5899             break;
5900         if (e->srcTally == 0)
5901             return -1;
5902         // If ES is OFF and the character is zero, edit insertion table entry 1
5903         // is moved to the receiving field in place of the character.
5904         // If ES is OFF and the character is not zero, then edit insertion
5905         // table entry 5 is moved to the receiving field, the character is also
5906         // moved to the receiving field, and ES is set ON.
5907 
5908         word9 c = *(e->in);
5909         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC c %d (0%o)\n", c, c);
5910         if (!e->mopES) { // e->mopES is OFF
5911 
5912             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES off\n");
5913             if (isDecimalZero (c)) {
5914                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is zero\n");
5915                 // edit insertion table entry 1 is moved to the receiving field
5916                 // in place of the character.
5917                 writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5918                 e->in += 1;
5919                 e->srcTally -= 1;
5920             } else {
5921                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is not zero\n");
5922                 // then edit insertion table entry 5 is moved to the receiving
5923                 // field, the character is also moved to the receiving field,
5924                 // and ES is set ON.
5925                 writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5926 
5927                 writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
5928                 e->mopZ = false; // iszero() tested above.
5929                 e->in += 1;
5930                 e->srcTally -= 1;
5931 
5932                 e->mopES = true;
5933             }
5934         } else {
5935             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES on\n");
5936             // If ES is ON, the character is moved to the receiving field.
5937             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
5938 
5939             if (! isDecimalZero (c))
5940                 e->mopZ = false;
5941             e->in += 1;
5942             e->srcTally -= 1;
5943         }
5944     }
5945 
5946     return 0;
5947 }
5948 
5949 /*!
5950  * MFLS Micro Operation - Move with Floating Sign Insertion
5951  * EXPLANATION:
5952  * IF specifies the number of characters of the sending field upon which the
5953  * operation is performed, where IF = 0 specifies 16 characters.
5954  * Starting with the next available sending field character, the next IF
5955  * characters are individually fetched and the following conditional actions
5956  * occur.
5957  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
5958  * moved to the receiving field in place of the character.
5959  * − If ES is OFF, the character is not zero, and SN is OFF; then edit
5960  * insertion table entry 3 is moved to the receiving field; the character is
5961  * also moved to the receiving field, and ES is set ON.
5962  * − If ES is OFF, the character is nonzero, and SN is ON; edit insertion table
5963  * entry 4 is moved to the receiving field; the character is also moved to the
5964  * receiving field, and ES is set ON.
5965  * − If ES is ON, the character is moved to the receiving field.
5966  * The number of characters placed in the receiving field is data-dependent. If
5967  * the entire sending field is zero, IF characters are placed in the receiving
5968  * field. However, if the sending field contains a nonzero character, IF+1
5969  * characters (the insertion character plus the characters from the sending
5970  * field) are placed in the receiving field.
5971  * An IPR fault occurs when the sending field is exhausted before the receiving
5972  * field is filled. In order to provide space in the receiving field for an
5973  * inserted sign, the receiving field must have a string length one character
5974  * longer than the sending field. When the sending field is all zeros, no sign
5975  * is inserted by the MFLS micro operation and the receiving field is not
5976  * filled when the sending field is exhausted. The user should provide an ENF
5977  * (ENF,4) micro operation after a MFLS micro operation that has as its
5978  * character count the number of characters in the sending field. The ENF micro
5979  * operation is engaged only when the MFLS micro operation fails to fill the
5980  * receiving field; then, it supplies a sign character to fill the receiving
5981  * field and blanks out the entire field.
5982  *
5983  * FLAGS: (Flags not listed are not affected.)
5984  *     ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
5985  *     it is unchanged.
5986  * NOTE: Since the number of characters moved to the receiving string is
5987  * data-dependent, a possible Illegal Procedure fault may be avoided by
5988  * ensuring that the Z and BZ flags are ON.
5989  */
5990 
5991 static int mopMFLS (void)
     /* [previous][next][first][last][top][bottom][index][help] */
5992 {
5993     EISstruct * e = & cpu.currentEISinstruction;
5994     if (e->mopIF == 0)
5995         e->mopIF = 16;
5996 
5997     for(int n = 0 ; n < e->mopIF; n += 1)
5998     {
5999         if (e->dstTally == 0)
6000             break;
6001         if (e->srcTally == 0)
6002             return -1;
6003 
6004         word9 c = *(e->in);
6005         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLS n %d c %o\n", n, c);
6006         if (!e->mopES) { // e->mopES is OFF
6007             if (isDecimalZero (c))
6008             {
6009                 // edit insertion table entry 1 is moved to the receiving field
6010                 // in place of the character.
6011                 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");
6012                 writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6013                 e->in += 1;
6014                 e->srcTally -= 1;
6015             } else {
6016                 // c is non-zero
6017                 if (!e->mopSN)
6018                 {
6019                     // then edit insertion table entry 3 is moved to the
6020                     // receiving field; the character is also moved to the
6021                     // receiving field, and ES is set ON.
6022                     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");
6023                     writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[2]);
6024 
6025                     e->in += 1;
6026                     e->srcTally -= 1;
6027                     e->mopZ = false; // iszero tested above
6028 
6029 
6030 
6031 
6032 
6033 
6034 
6035 
6036                     writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6037 
6038                     e->mopES = true;
6039                 } else {
6040                     //  SN is ON; edit insertion table entry 4 is moved to the
6041                     //  receiving field; the character is also moved to the
6042                     //  receiving field, and ES is set ON.
6043                     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");
6044                     writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[3]);
6045 
6046                     e->in += 1;
6047                     e->srcTally -= 1;
6048                     e->mopZ = false; // iszero tested above
6049 
6050                     writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6051 
6052                     e->mopES = true;
6053                 }
6054             }
6055         } else {
6056             // If ES is ON, the character is moved to the receiving field.
6057             sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is ON, the character is moved to the receiving field.\n");
6058             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6059 
6060             if (! isDecimalZero (c))
6061                 e->mopZ = false;
6062             e->in += 1;
6063             e->srcTally -= 1;
6064         }
6065     }
6066 
6067     // NOTE: Since the number of characters moved to the receiving string is
6068     // data-dependent, a possible Illegal Procedure fault may be avoided by
6069     // ensuring that the Z and BZ flags are ON.
6070 
6071     return 0;
6072 }
6073 
6074 /*!
6075  * MORS Micro Operation - Move and OR Sign
6076  * EXPLANATION:
6077  * IF specifies the number of characters of the sending field upon which the
6078  * operation is performed, where IF = 0 specifies 16 characters.
6079  * Starting with the next available sending field character, the next IF
6080  * characters are individually fetched and the following conditional actions
6081  * occur.
6082  * − If SN is OFF, the next IF characters in the source data field are moved to
6083  * the receiving data field and, during the move, edit insertion table entry 3
6084  * is ORed to each character.
6085  * − If SN is ON, the next IF characters in the source data field are moved to
6086  * the receiving data field and, during the move, edit insertion table entry 4
6087  * is ORed to each character.
6088  * MORS can be used to generate a negative overpunch for a receiving field to
6089  * be used later as a sending field.
6090  * FLAGS: None affected
6091  */
6092 
6093 static int mopMORS (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6094 {
6095     EISstruct * e = & cpu.currentEISinstruction;
6096     if (e->mopIF == 0)
6097         e->mopIF = 16;
6098 
6099     sim_debug (DBG_TRACEEXT, & cpu_dev, "MORS mopIF %d src %d dst %d\n", e->mopIF, e->srcTally, e->dstTally);
6100     for(int n = 0 ; n < e->mopIF ; n += 1)
6101     {
6102 // The micro operation sequence is terminated normally when the receiving
6103 // string length becomes exhausted. The micro operation sequence is terminated
6104 // abnormally (with an illegal procedure fault) if a move from an exhausted
6105 // sending string or the use of an exhausted MOP string is attempted.
6106 
6107         if (e->dstTally == 0)
6108             break;
6109         if (e->srcTally == 0)
6110             return -1;
6111 
6112         // XXX this is probably wrong regarding the ORing, but it's a start ....
6113         word9 c = (*e->in | (!e->mopSN ? e->editInsertionTable[2] : e->editInsertionTable[3]));
6114         if (! isDecimalZero (*e->in))
6115             e->mopZ = false;
6116         e->in += 1;
6117         e->srcTally -= 1;
6118 
6119         writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6120     }
6121 
6122     return 0;
6123 }
6124 
6125 /*!
6126  * MVC Micro Operation - Move Source Characters
6127  * EXPLANATION:
6128  * IF specifies the number of characters to be moved, where IF = 0 specifies 16
6129  * characters.
6130  * The next IF characters in the source data field are moved to the receiving
6131  * data field.
6132  * FLAGS: None affected
6133  */
6134 
6135 static int mopMVC (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6136 {
6137     EISstruct * e = & cpu.currentEISinstruction;
6138     if (e->mopIF == 0)
6139         e->mopIF = 16;
6140 
6141     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC mopIF %d\n", e->mopIF);
6142 
6143     for(int n = 0 ; n < e->mopIF ; n += 1)
6144     {
6145         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC n %d srcTally %d dstTally %d\n", n, e->srcTally, e->dstTally);
6146 // GD's test_float shows that data exhaustion is not a fault.
6147 //#if 0
6148         if (e->dstTally == 0)
6149             break;
6150         if (e->srcTally == 0)
6151             return -1;
6152 
6153         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC write to output buffer %o\n", *e->in);
6154         writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, *e->in);
6155         if (! isDecimalZero (*e->in))
6156             e->mopZ = false;
6157         e->in += 1;
6158 
6159         e->srcTally -= 1;
6160     }
6161 
6162     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC done\n");
6163     return 0;
6164 }
6165 
6166 /*!
6167  * MSES Micro Operation - Move and Set Sign
6168  * EXPLANATION:
6169  * IF specifies the number of characters of the sending field upon which the
6170  * operation is performed, where IF = 0 specifies 16 characters. For MVE,
6171  * starting with the next available sending field character, the next IF
6172  * characters are individually fetched and the following conditional actions
6173  * occur.
6174  * Starting with the first character during the move, a comparative AND is made
6175  * first with edit insertion table entry 3. If the result is nonzero, the first
6176  * character and the rest of the characters are moved without further
6177  * comparative ANDs. If the result is zero, a comparative AND is made between
6178  * the character being moved and edit insertion table entry 4 If that result is
6179  * nonzero, the SN indicator is set ON (indicating negative) and the first
6180  * character and the rest of the characters are moved without further
6181  * comparative ANDs. If the result is zero, the second character is treated
6182  * like the first. This process continues until one of the comparative AND
6183  * results is nonzero or until all characters are moved.
6184  * For MVNE instruction, the sign (SN) flag is already set and IF characters
6185  * are moved to the destination field (MSES is equivalent to the MVC
6186  * instruction).
6187  * FLAGS: (Flags not listed are not affected.)
6188  * SN If edit insertion table entry 4 is found in C(Y-1), then ON; otherwise,
6189  * it is unchanged.
6190  */
6191 
6192 static int mopMSES (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6193 {
6194     EISstruct * e = & cpu.currentEISinstruction;
6195     if (e->mvne == true)
6196         return mopMVC ();   // XXX I think!
6197 
6198     if (e->mopIF == 0)
6199         e->mopIF = 16;
6200 
6201     int overpunch = false;
6202 
6203     for(int n = 0 ; n < e->mopIF ; n += 1)
6204     {
6205         if (e->dstTally == 0)
6206             break;
6207         if (e->srcTally == 0)
6208             return -1;
6209 
6210         //Starting with the first character during the move, a comparative AND
6211         //is made first with edit insertion table entry 3. If the result is
6212         //nonzero, the first character and the rest of the characters are moved
6213         //without further comparative ANDs. If the result is zero, a
6214         //comparative AND is made between the character being moved and edit
6215         //insertion table entry 4 If that result is nonzero, the SN indicator
6216         //is set ON (indicating negative) and the first character and the rest
6217         //of the characters are moved without further comparative ANDs. If the
6218         //result is zero, the second character is treated like the first. This
6219         //process continues until one of the comparative AND results is nonzero
6220         //or until all characters are moved.
6221 
6222         word9 c = *(e->in);
6223 
6224         if (!overpunch) {
6225             if (c & e->editInsertionTable[2])  // XXX only lower 4-bits are considered
6226                 overpunch = true;
6227 
6228             else if (c & e->editInsertionTable[3])  // XXX only lower 4-bits are considered
6229             {
6230                 e->mopSN = true;
6231                 overpunch = true;
6232             }
6233         }
6234 
6235         e->in += 1;
6236         e->srcTally -= 1;   // XXX is this correct? No chars have been consumed, but ......
6237         if (! isDecimalZero (c))
6238             e->mopZ = false;
6239         writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6240     }
6241 
6242     return 0;
6243 }
6244 
6245 /*!
6246  * MVZA Micro Operation - Move with Zero Suppression and Asterisk Replacement
6247  * EXPLANATION:
6248  * MVZA is the same as MVZB except that if ES is OFF and the character is zero,
6249  * then edit insertion table entry 2 is moved to the receiving field.
6250  * FLAGS: (Flags not listed are not affected.)
6251  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
6252  * is unchanged.
6253  */
6254 
6255 static int mopMVZA (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6256 {
6257     EISstruct * e = & cpu.currentEISinstruction;
6258     if (e->mopIF == 0)
6259         e->mopIF = 16;
6260 
6261     for(int n = 0 ; n < e->mopIF ; n += 1)
6262     {
6263         if (e->dstTally == 0)
6264             break;
6265         if (e->srcTally == 0)
6266             return -1;
6267 
6268         word9 c = *e->in;
6269         e->in += 1;
6270         e->srcTally -= 1;
6271 
6272         //if (!e->mopES && c == 0)
6273         // XXX See srcTA comment in MVNE
6274         if (!e->mopES && isDecimalZero (c))
6275         {
6276             //If ES is OFF and the character is zero, then edit insertion table
6277             //entry 2 is moved to the receiving field in place of the
6278             //character.
6279             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[1]);
6280         //} else if (!e->mopES && c != 0)
6281         // XXX See srcTA comment in MVNE
6282         }
6283         else if ((! e->mopES) && (! isDecimalZero (c)))
6284         {
6285             //If ES is OFF and the character is not zero, then the character is
6286             //moved to the receiving field and ES is set ON.
6287             e->mopZ = false;
6288             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6289 
6290             e->mopES = true;
6291         } else if (e->mopES)
6292         {
6293             //If ES is ON, the character is moved to the receiving field.
6294             if (! isDecimalZero (c))
6295                 e->mopZ = false;
6296             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6297         }
6298     }
6299 
6300     return 0;
6301 }
6302 
6303 /*!
6304  * MVZB Micro Operation - Move with Zero Suppression and Blank Replacement
6305  * EXPLANATION:
6306  * IF specifies the number of characters of the sending field upon which the
6307  * operation is performed, where IF = 0 specifies 16 characters.
6308  * Starting with the next available sending field character, the next IF
6309  * characters are individually fetched and the following conditional actions
6310  * occur.
6311  * − If ES is OFF and the character is zero, then edit insertion table entry 1
6312  * is moved to the receiving field in place of the character.
6313  * − If ES is OFF and the character is not zero, then the character is moved to
6314  * the receiving field and ES is set ON.
6315  * − If ES is ON, the character is moved to the receiving field.
6316  * FLAGS: (Flags not listed are not affected.)
6317  *   ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6318  *   it is unchanged.
6319  */
6320 
6321 static int mopMVZB (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6322 {
6323     EISstruct * e = & cpu.currentEISinstruction;
6324     if (e->mopIF == 0)
6325         e->mopIF = 16;
6326 
6327     for(int n = 0 ; n < e->mopIF ; n += 1)
6328     {
6329         if (e->dstTally == 0)
6330             break;
6331         if (e->srcTally == 0)
6332           return -1;
6333 
6334         word9 c = *e->in;
6335         e->srcTally -= 1;
6336         e->in += 1;
6337 
6338         //if (!e->mopES && c == 0)
6339         // XXX See srcTA comment in MVNE
6340         if ((!e->mopES) && isDecimalZero (c))
6341         {
6342             //If ES is OFF and the character is zero, then edit insertion table
6343             //entry 1 is moved to the receiving field in place of the
6344             //character.
6345             writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6346         //} else if (!e->mopES && c != 0)
6347         // XXX See srcTA comment in MVNE
6348         }
6349         if ((! e->mopES) && (! isDecimalZero (c)))
6350         {
6351             //If ES is OFF and the character is not zero, then the character is
6352             //moved to the receiving field and ES is set ON.
6353             e->mopZ = false;
6354             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6355 
6356             e->mopES = true;
6357         } else if (e->mopES)
6358         {
6359             //If ES is ON, the character is moved to the receiving field.
6360             if (! isDecimalZero (c))
6361                 e->mopZ = false;
6362             writeToOutputBuffer(&e->out, e->srcSZ, e->dstSZ, c);
6363         }
6364     }
6365 
6366     return 0;
6367 }
6368 
6369 /*!
6370  * SES Micro Operation - Set End Suppression
6371  * EXPLANATION:
6372  * Bit 0 of IF (IF(0)) specifies the setting of the ES switch.
6373  * If IF(0) = 0, the ES flag is set OFF. If IF(0) = 1, the ES flag is set ON.
6374  * Bit 1 of IF (IF(1)) specifies the setting of the blank-when-zero option.
6375  * If IF(1) = 0, no action is taken.
6376  * If IF(1) = 1, the BZ flag is set ON.
6377  * FLAGS: (Flags not listed are not affected.)
6378  * ES set by this micro operation
6379  * BZ If bit 1 of C(IF) = 1, then ON; otherwise, it is unchanged.
6380  */
6381 
6382 static int mopSES (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6383 {
6384     EISstruct * e = & cpu.currentEISinstruction;
6385     if (e->mopIF & 010)
6386         e->mopES = true;
6387     else
6388         e->mopES = false;
6389 
6390     if (e->mopIF & 04)
6391         e->mopBZ = true;
6392 
6393     return 0;
6394 }
6395 
6396 // Table 4-9. Micro Operation Code Assignment Map
6397 #ifndef QUIET_UNUSED
6398 static char * mopCodes [040] =
6399   {
6400     //            0       1       2       3       4       5       6       7
6401     /* 00 */      0, "insm",  "enf",  "ses", "mvzb", "mvza", "mfls", "mflc",
6402     /* 10 */ "insb", "insa", "insn", "insp",  "ign",  "mvc", "mses", "mors",
6403     /* 20 */  "lte",  "cht",      0,      0,      0,      0,      0,      0,
6404     /* 30 */      0,      0,      0,      0,      0,      0,      0,      0
6405   };
6406 #endif
6407 
6408 static MOP_struct mopTab[040] = {
6409     {NULL, 0},
6410     {"insm", mopINSM },
6411     {"enf",  mopENF  },
6412     {"ses",  mopSES  },
6413     {"mvzb", mopMVZB },
6414     {"mvza", mopMVZA },
6415     {"mfls", mopMFLS },
6416     {"mflc", mopMFLC },
6417     {"insb", mopINSB },
6418     {"insa", mopINSA },
6419     {"insn", mopINSN },
6420     {"insp", mopINSP },
6421     {"ign",  mopIGN  },
6422     {"mvc",  mopMVC  },
6423     {"mses", mopMSES },
6424     {"mors", mopMORS },
6425     {"lte",  mopLTE  },
6426     {"cht",  mopCHT  },
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     {NULL, 0}
6441 };
6442 
6443 /*!
6444  * fetch MOP from e->mopAddr/e->mopPos ...
6445  */
6446 
6447 static MOP_struct* EISgetMop (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6448 {
6449     EISstruct * e = & cpu.currentEISinstruction;
6450     //static word18 lastAddress;  // try to keep memory access' down
6451     //static word36 data;
6452 
6453     if (e == NULL) //-V547
6454     //{
6455     //    p->lastAddress = -1;
6456     //    p->data = 0;
6457         return NULL;
6458     //}
6459 
6460 #ifdef EIS_PTR2
6461     EISaddr *p = &e->ADDR2;
6462 #else
6463     EISaddr *p = e->mopAddress;
6464 #endif
6465 
6466     //if (p->lastAddress != p->address)                 // read from memory if different address
6467         p->data = EISRead(p);   // read data word from memory
6468 
6469     if (e->mopPos > 3)   // overflows to next word?
6470     {   // yep....
6471         e->mopPos = 0;   // reset to 1st byte
6472 #ifdef EIS_PTR2
6473         cpu.du.Dk_PTR_W[KMOP] = (cpu.du.Dk_PTR_W[KMOP] + 1) & AMASK;     // bump source to next address
6474         p->data = EISRead(&e->ADDR2);   // read it from memory
6475 #else
6476         PNL (cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK);     // bump source to next address
6477         PNL (p->data = EISRead(e->mopAddress));   // read it from memory
6478 # ifdef EIS_PTR
6479         cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK;     // bump source to next address
6480         p->data = EISRead(e->mopAddress);   // read it from memory
6481 # else
6482         e->mopAddress->address = (e->mopAddress->address + 1) & AMASK;     // bump source to next address
6483         p->data = EISRead(e->mopAddress);   // read it from memory
6484 # endif
6485 #endif
6486     }
6487 
6488     word9 mop9  = (word9) get9 (p -> data, e -> mopPos); // get 9-bit mop
6489     word5 mop   = (mop9 >> 4) & 037;
6490     e->mopIF = mop9 & 0xf;
6491 
6492     MOP_struct *m = &mopTab[mop];
6493     sim_debug (DBG_TRACEEXT, & cpu_dev, "MOP %s(%o) %o\n", m -> mopName, mop, e->mopIF);
6494     e->m = m;
6495     if (e->m == NULL || e->m->f == NULL)
6496     {
6497         sim_debug (DBG_TRACEEXT, & cpu_dev, "getMop(e->m == NULL || e->m->f == NULL): mop:%d IF:%d\n", mop, e->mopIF);
6498         return NULL;
6499     }
6500 
6501     e->mopPos += 1;
6502     e->mopTally -= 1;
6503 
6504     //p->lastAddress = p->address;
6505 
6506     return m;
6507 }
6508 
6509 #ifdef EIS_PTR2
6510 static void mopExecutor (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6511 #else
6512 static void mopExecutor (int kMop)
6513 #endif
6514   {
6515     EISstruct * e = & cpu.currentEISinstruction;
6516     PNL (L68_ (DU_CYCLE_FEXOP;))
6517 #ifdef EIS_PTR2
6518     e->mopTally = (int) e->N[KMOP];        // number of micro-ops
6519     e->mopPos   = (int) e->CN[KMOP];        // starting at char pos CN
6520 #else
6521     e->mopAddress = &e->addr[kMop-1];
6522     e->mopTally = (int) e->N[kMop-1];        // number of micro-ops
6523     e->mopPos   = (int) e->CN[kMop-1];        // starting at char pos CN
6524 #endif
6525 
6526     word9 *p9 = e->editInsertionTable; // re-initialize edit insertion table
6527     char *q = defaultEditInsertionTable;
6528     while((*p9++ = (word9) (*q++)))
6529         ;
6530 
6531     e->in = e->inBuffer;    // reset input buffer pointer
6532     e->out = e->outBuffer;  // reset output buffer pointer
6533 
6534     e->_faults = 0; // No faults (yet!)
6535 
6536     // execute dstTally micro operations
6537     // The micro operation sequence is terminated normally when the receiving
6538     // string length becomes exhausted. The micro operation sequence is
6539     // terminated abnormally (with an illegal procedure fault) if a move from
6540     // an exhausted sending string or the use of an exhausted MOP string is
6541     // attempted.
6542 
6543     while (e->dstTally)
6544     {
6545         sim_debug (DBG_TRACEEXT, & cpu_dev, "mopExecutor srcTally %d dstTally %d mopTally %d\n", e->srcTally, e->dstTally, e->mopTally);
6546         MOP_struct *m = EISgetMop();
6547         if (! m)
6548           {
6549             sim_debug (DBG_TRACEEXT, & cpu_dev, "mopExecutor EISgetMop forced break\n");
6550             e->_faults |= FAULT_IPR;   // XXX ill proc fault
6551             break;
6552           }
6553         int mres = m->f();    // execute mop
6554 
6555         // PVS-Studio claims: Expression 'e->_faults & FAULT_IPR' is always false.
6556         if (e->_faults & FAULT_IPR) //-V547
6557             break; // hard IPR raised by a MOP
6558 
6559         // RJ78 specifies "if at completion of a move (L1 exhausted)", AL39
6560         // doesn't define "completion of a move".
6561         // But ISOLTS-845 asserts a case where L1 is NOT exhausted. Therefore I
6562         // assume "L2 exhausted" or "L1 or L2 exhausted" is the correct
6563         // interpretation. Both these options pass ISOLTS-845.
6564         // "L3 exhausted" is also an option but unlikely since that would fire
6565         // the BZ check even upon normal termination.
6566         // XXX DH03 7-295 suggests that there might be a difference between MVE
6567         // and MVNE. It might well be that DPS88/9000 behaves differently than
6568         // DPS8.
6569 
6570 
6571 
6572 
6573 
6574 
6575 
6576         // immediate (L1 or L2) srcTally test
6577         // perhaps more adherent to documentation
6578         if (e->mopTally == 0 || mres)
6579           {
6580             sim_debug (DBG_TRACEEXT, & cpu_dev,
6581                        "mopExecutor N1 or N2 exhausted\n");
6582 
6583             if (e->mopZ && e->mopBZ)
6584               {
6585                 e->out = e->outBuffer; //-V1048  // reset output buffer pointer
6586                 e->dstTally = (int) e->N3;       // number of chars in dst (max 63)
6587                 while (e->dstTally)
6588                   {
6589                     writeToOutputBuffer(&e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6590                   }
6591               }
6592             else if (mres || e->dstTally) //-V560
6593               { // N1 or N2 exhausted and BZ wasn't enabled
6594                 e->_faults |= FAULT_IPR;
6595               } // otherwise normal termination
6596             break;
6597           }
6598     }
6599 
6600     sim_debug (DBG_TRACEEXT, & cpu_dev, "mop faults %o src %d dst %d mop %d\n", e->_faults, e->srcTally, e->dstTally, e->mopTally);
6601 
6602 //"The micro-operation sequence is terminated normally when the receiving string
6603 // length is exhausted. The micro-operation sequence is terminated abnormally (with
6604 // an IPR fault) if an attempt is made to move from an exhausted sending string or to
6605 // use an exhausted MOP string.
6606 
6607 // ISOLTS 845 is happy with no check at all
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 
6646     if (e -> _faults)
6647       doFault (FAULT_IPR, fst_ill_proc, "mopExecutor");
6648 }
6649 
6650 void mve (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6651   {
6652     EISstruct * e = & cpu.currentEISinstruction;
6653 
6654     sim_debug(DBG_TRACEEXT, & cpu_dev, "mve\n");
6655 
6656     fault_ipr_subtype_ mod_fault = 0;
6657 
6658 #ifndef EIS_SETUP
6659     setupOperandDescriptor(1, &mod_fault);
6660     setupOperandDescriptor(2, &mod_fault);
6661     setupOperandDescriptor(3, &mod_fault);
6662 #endif
6663 
6664     parseAlphanumericOperandDescriptor(1, 1, false, &mod_fault);
6665     parseAlphanumericOperandDescriptor(2, 2, false, &mod_fault);
6666     parseAlphanumericOperandDescriptor(3, 3, false, &mod_fault);
6667 
6668     L68_ (
6669       // L68 raises it immediately
6670       if (mod_fault)
6671         {
6672           doFault (FAULT_IPR,
6673                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6674                    "Illegal modifier");
6675         }
6676     )
6677 
6678     // Bits 0, 1, 9, and 10 MBZ
6679     // According to RJ78, bit 9 is T, but is not mentioned in the text.
6680     if (IWB_IRODD & 0600600000000)
6681       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mve: 0, 1, 9, 10 MBZ");
6682 
6683     // Bit 23 of OP1 MBZ
6684     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
6685       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op1 23 MBZ");
6686 
6687 
6688 
6689 
6690 
6691 
6692     // only bit 23 according to RH03. this was fixed in DPS9000
6693     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
6694       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op2 23 MBZ");
6695 
6696     // Bit 23 of OP3 MBZ
6697     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6698       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op3 23 MBZ");
6699 
6700     DPS8M_ (
6701       // DPS8M raises it delayed
6702       if (mod_fault)
6703         {
6704           doFault (FAULT_IPR,
6705                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6706                    "Illegal modifier");
6707         }
6708     )
6709 
6710     // initialize mop flags. Probably best done elsewhere.
6711     e->mopES = false; // End Suppression flag
6712     e->mopSN = false; // Sign flag
6713     e->mopBZ = false; // Blank-when-zero flag
6714     e->mopZ  = true;  // Zero flag
6715 
6716     e->srcTally = (int) e->N1;  // number of chars in src (max 63)
6717     e->dstTally = (int) e->N3;  // number of chars in dst (max 63)
6718 
6719 #ifdef EIS_PTR3
6720     e->srcTA = (int) TA1;    // type of chars in src
6721 #else
6722     e->srcTA = (int) e->TA1;    // type of chars in src
6723 #endif
6724 
6725     switch (e -> srcTA)
6726       {
6727         case CTA4:
6728           e -> srcSZ = 4;
6729           break;
6730         case CTA6:
6731           e -> srcSZ = 6;
6732           break;
6733         case CTA9:
6734           e -> srcSZ = 9;
6735           break;
6736       }
6737 
6738 #ifdef EIS_PTR3
6739     uint dstTA = TA3;    // type of chars in dst
6740 #else
6741     uint dstTA = e -> TA3;    // type of chars in dst
6742 #endif
6743 
6744     switch (dstTA)
6745       {
6746         case CTA4:
6747           e -> dstSZ = 4;
6748           break;
6749         case CTA6:
6750           e -> dstSZ = 6;
6751           break;
6752         case CTA9:
6753           e -> dstSZ = 9;
6754           break;
6755       }
6756 
6757     // 1. load sending string into inputBuffer
6758     EISloadInputBufferAlphnumeric (1);   // according to MF1
6759 
6760     // 2. Execute micro operation string, starting with first (4-bit) digit.
6761     e -> mvne = false;
6762 
6763 #ifdef EIS_PTR2
6764     mopExecutor ();
6765 #else
6766     mopExecutor (2);
6767 #endif
6768 
6769     e -> dstTally = (int) e -> N3;  // restore dstTally for output
6770 
6771     EISwriteOutputBufferToMemory (3);
6772     cleanupOperandDescriptor (1);
6773     cleanupOperandDescriptor (2);
6774     cleanupOperandDescriptor (3);
6775   }
6776 
6777 void mvne (void)
     /* [previous][next][first][last][top][bottom][index][help] */
6778   {
6779     EISstruct * e = & cpu.currentEISinstruction;
6780 
6781     fault_ipr_subtype_ mod_fault = 0;
6782 
6783 #ifndef EIS_SETUP
6784     setupOperandDescriptor (1, &mod_fault);
6785     setupOperandDescriptor (2, &mod_fault);
6786     setupOperandDescriptor (3, &mod_fault);
6787 #endif
6788 
6789     parseNumericOperandDescriptor (1, &mod_fault);
6790     parseAlphanumericOperandDescriptor (2, 2, false, &mod_fault);
6791     parseAlphanumericOperandDescriptor (3, 3, false, &mod_fault);
6792 
6793     L68_ (
6794       // L68 raises it immediately
6795       if (mod_fault)
6796         {
6797           doFault (FAULT_IPR,
6798                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6799                    "Illegal modifier");
6800         }
6801     )
6802 
6803     // Bits 0, 1, 9, and 10 MBZ
6804     if (IWB_IRODD & 0600600000000)
6805       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvne: 0, 1, 9, 10 MBZ");
6806 
6807     // Bit 24-29 of OP1 MBZ
6808     // Multics has been observed to use 600162017511, cf RJ78
6809     //if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
6810       //doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op1 24-29 MBZ");
6811 
6812 
6813 
6814 
6815 
6816 
6817     // only bits 21-23 according to RJ78, maybe even less on DPS8
6818     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000070000)
6819       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op2 21-23 MBZ");
6820 
6821 
6822 
6823 
6824 
6825 
6826     // only bit 23 according to RJ78
6827     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6828       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op3 23 MBZ");
6829 
6830     DPS8M_ (
6831       // DPS8M raises it delayed
6832       if (mod_fault)
6833         {
6834           doFault (FAULT_IPR,
6835                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6836                    "Illegal modifier");
6837         }
6838     )
6839 
6840     uint srcTN = e -> TN1;    // type of chars in src
6841 
6842     int n1 = 0;
6843 
6844     /*
6845      * Here we need to distinguish between 4 type of numbers.
6846      *
6847      * CSFL - Floating-point, leading sign
6848      * CSLS - Scaled fixed-point, leading sign
6849      * CSTS - Scaled fixed-point, trailing sign
6850      * CSNS - Scaled fixed-point, unsigned
6851      */
6852 
6853     // determine precision
6854     switch(e->S1)
6855     {
6856         case CSFL:
6857             n1 = (int) e->N1 - 1; // need to account for the - sign
6858             if (srcTN == CTN4)
6859                 n1 -= 2;    // 2 4-bit digits exponent
6860             else
6861                 n1 -= 1;    // 1 9-bit digit exponent
6862             break;
6863 
6864         case CSLS:
6865         case CSTS:
6866             n1 = (int) e->N1 - 1; // only 1 sign
6867             break;
6868 
6869         case CSNS:
6870             n1 = (int) e->N1;     // no sign
6871             break;  // no sign wysiwyg
6872     }
6873 
6874     if (n1 < 1)
6875         doFault (FAULT_IPR, fst_ill_proc, "mvne adjusted n1<1");
6876 
6877     // Putting this check in pAOD breaks Multics boot
6878     // From DH03 it seems that DPS8 does not check this explicitly, but L2 exhaust occurs which raises IPR anyway
6879     // So we may as well keep it here.
6880     if (e->N[1] == 0)
6881       doFault (FAULT_IPR, fst_ill_proc, "mvne N2 0");
6882 
6883     // this is a flaw in DPS8/70 which was corrected in DPS88 and later
6884     // ISOLTS-841 07h, RH03 p.7-295
6885     if (e->N[2] == 0)
6886       doFault (FAULT_IPR, fst_ill_proc, "mvne N3 0");
6887 
6888 //if ((e -> op [0]  & 0000000007700) ||
6889 //    (e -> op [1]  & 0000000077700) ||
6890 //    (e -> op [2]  & 0000000017700))
6891 //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]);
6892 //if (e -> op [0]  & 0000000007700) sim_printf ("op1\n");
6893 //if (e -> op [1]  & 0000000077700) sim_printf ("op2\n");
6894 //if (e -> op [2]  & 0000000017700) sim_printf ("op3\n");
6895 //000140  aa  100 004 024 500   mvne      (pr),(ic),(pr)
6896 //000141  aa  6 00162 01 7511   desc9ls   pr6|114,9,-3
6897 //000142  aa   000236 00 0007   desc9a    158,7               000376 = 403040144040
6898 //000143  aa  6 00134 00 0012   desc9a    pr6|92,10           vcpu
6899 //
6900 // The desc8ls is sign-extending the -3.
6901 
6902     // initialize mop flags. Probably best done elsewhere.
6903     e->mopES = false; // End Suppression flag
6904     e->mopSN = false; // Sign flag
6905     e->mopBZ = false; // Blank-when-zero flag
6906     e->mopZ  = true;  // Zero flag
6907 
6908     e -> srcTally = (int) e -> N1;  // number of chars in src (max 63)
6909     e -> dstTally = (int) e -> N3;  // number of chars in dst (max 63)
6910 
6911 // XXX Temp hack to get MOP to work. Merge TA/TN?
6912 // The MOP operators look at srcTA to make 9bit/not 9-bit decisions about
6913 // the contents of inBuffer; parseNumericOperandDescriptor() always puts
6914 // 4 bit data in inBuffer, so signal the MOPS code of that.
6915     e->srcTA = CTA4;    // type of chars in src
6916 
6917     switch(srcTN)
6918     {
6919         case CTN4:
6920             //e->srcAddr = e->YChar41;
6921             e->srcSZ = 4; //-V1037  // stored as 4-bit decimals
6922             break;
6923         case CTN9:
6924             //e->srcAddr = e->YChar91;
6925             e->srcSZ = 4; //-V1037  // 'cause everything is stored as 4-bit decimals
6926             break;
6927     }
6928 
6929 #ifdef EIS_PTR3
6930     uint dstTA = TA3;     // type of chars in dst
6931 #else
6932     uint dstTA = e->TA3;  // type of chars in dst
6933 #endif
6934     switch(dstTA)
6935     {
6936         case CTA4:
6937             //e->dstAddr = e->YChar43;
6938             e->dstSZ = 4;
6939             break;
6940         case CTA6:
6941             //e->dstAddr = e->YChar63;
6942             e->dstSZ = 6;
6943             break;
6944         case CTA9:
6945             //e->dstAddr = e->YChar93;
6946             e->dstSZ = 9;
6947             break;
6948     }
6949 
6950 #ifdef EIS_PTR3
6951     sim_debug (DBG_TRACEEXT, & cpu_dev,
6952       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
6953       e->N1, e->N2, e->N3, e->TN1, e->CN1, TA3, e->CN3);
6954 #else
6955     sim_debug (DBG_TRACEEXT, & cpu_dev,
6956       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
6957       e->N1, e->N2, e->N3, e->TN1, e->CN1, e->TA3, e->CN3);
6958 #endif
6959 
6960     // 1. load sending string into inputBuffer
6961     EISloadInputBufferNumeric (1);   // according to MF1
6962 
6963     // 2. Test sign and, if required, set the SN flag. (Sign flag; initially
6964     // set OFF if the sending string has an alphanumeric descriptor or an
6965     // unsigned numeric descriptor. If the sending string has a signed numeric
6966     // descriptor, the sign is initially read from the sending string from the
6967     // digit position defined by the sign and the decimal type field (S); SN is
6968     // set OFF if positive, ON if negative. If all digits are zero, the data is
6969     // assumed positive and the SN flag is set OFF, even when the sign is
6970     // negative.)
6971 
6972     int sum = 0;
6973     for(int n = 0 ; n < e -> srcTally ; n ++)
6974         sum += e -> inBuffer [n];
6975     if ((e -> sign == -1) && sum)
6976         e -> mopSN = true;
6977 
6978     // 3. Execute micro operation string, starting with first (4-bit) digit.
6979     e -> mvne = true;
6980 
6981 #ifdef EIS_PTR2
6982     mopExecutor ();
6983 #else
6984     mopExecutor (2);
6985 #endif
6986 
6987     e -> dstTally = (int) e -> N3;  // restore dstTally for output
6988 
6989     EISwriteOutputBufferToMemory (3);
6990     cleanupOperandDescriptor (1);
6991     cleanupOperandDescriptor (2);
6992     cleanupOperandDescriptor (3);
6993   }
6994 
6995 /*
6996  * MVT - Move Alphanumeric with Translation
6997  */
6998 
6999 void mvt (void)
     /* [previous][next][first][last][top][bottom][index][help] */
7000   {
7001     EISstruct * e = & cpu.currentEISinstruction;
7002 
7003     // For i = 1, 2, ..., minimum (N1,N2)
7004     //    m = C(Y-charn1)i-1
7005     //    C(Y-char93)m → C(Y-charn2)i-1
7006     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7007     //    m = C(FILL)
7008     //    C(Y-char93)m → C(Y-charn2)i-1
7009 
7010     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
7011 
7012     fault_ipr_subtype_ mod_fault = 0;
7013 
7014 #ifndef EIS_SETUP
7015     setupOperandDescriptor (1, &mod_fault);
7016     setupOperandDescriptor (2, &mod_fault);
7017     setupOperandDescriptorCache (3);
7018 #endif
7019 
7020     parseAlphanumericOperandDescriptor (1, 1, false, &mod_fault);
7021     parseAlphanumericOperandDescriptor (2, 2, false, &mod_fault);
7022     parseArgOperandDescriptor (3, &mod_fault);
7023 
7024     L68_ (
7025       // L68 raises it immediately
7026       if (mod_fault)
7027         {
7028           doFault (FAULT_IPR,
7029                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7030                    "Illegal modifier");
7031         }
7032     )
7033 
7034 // ISOLTS 808 test-03b sets bit 0, 1
7035 // ISOLTS 808 test-03b sets bit 0, 1, 9
7036 
7037     // Bits 10 MBZ
7038     if (IWB_IRODD & 0000200000000)
7039       {
7040         //sim_printf ("mvt %012"PRIo64"\n", IWB_IRODD);
7041         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvt 10 MBZ");
7042       }
7043 
7044 
7045 
7046 
7047 
7048 
7049 
7050 
7051 
7052     // Bit 23 of OP1 MBZ
7053     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
7054       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op1 23 MBZ");
7055 
7056 // This breaks eis_tester mvt 110
7057 
7058 
7059 
7060 
7061 
7062 
7063     // Bits 18-28 of OP3 MBZ
7064     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777600)
7065       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op3 18-28 MBZ");
7066 
7067     DPS8M_ (
7068       // DPS8M raises it delayed
7069       if (mod_fault)
7070         {
7071           doFault (FAULT_IPR,
7072                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7073                    "Illegal modifier");
7074         }
7075     )
7076 
7077 #ifdef EIS_PTR3
7078     e->srcTA = (int) TA1;
7079     uint dstTA = TA2;
7080 
7081     switch (TA1)
7082 #else
7083     e->srcTA = (int) e->TA1;
7084     uint dstTA = e->TA2;
7085 
7086     switch (e -> TA1)
7087 #endif
7088       {
7089         case CTA4:
7090           e -> srcSZ = 4;
7091           break;
7092         case CTA6:
7093           e -> srcSZ = 6;
7094           break;
7095         case CTA9:
7096           e -> srcSZ = 9;
7097          break;
7098       }
7099 
7100 #ifdef EIS_PTR3
7101     switch (TA2)
7102 #else
7103     switch (e -> TA2)
7104 #endif
7105       {
7106         case CTA4:
7107           e -> dstSZ = 4;
7108           break;
7109         case CTA6:
7110           e -> dstSZ = 6;
7111           break;
7112         case CTA9:
7113           e -> dstSZ = 9;
7114           break;
7115       }
7116 
7117     //  Prepage Check in a Multiword Instruction
7118     //  The MVT, TCT, TCTR, and CMPCT instruction have a prepage check. The
7119     //  size of the translate table is determined by the TA1 data type as shown
7120     //  in the table below. Before the instruction is executed, a check is made
7121     //  for allocation in memory for the page for the translate table. If the
7122     //  page is not in memory, a Missing Page fault occurs before execution of
7123     //  the instruction. (Bull RJ78 p.7-75)
7124 
7125     // TA1              TRANSLATE TABLE SIZE
7126     // 4-BIT CHARACTER      4 WORDS
7127     // 6-BIT CHARACTER     16 WORDS
7128     // 9-BIT CHARACTER    128 WORDS
7129 
7130     uint xlatSize = 0;   // size of xlation table in words .....
7131 #ifdef EIS_PTR3
7132     switch(TA1)
7133 #else
7134     switch(e->TA1)
7135 #endif
7136     {
7137         case CTA4:
7138             xlatSize = 4;
7139             break;
7140         case CTA6:
7141             xlatSize = 16;
7142             break;
7143         case CTA9:
7144             xlatSize = 128;
7145             break;
7146     }
7147 
7148 
7149 
7150 
7151 
7152 
7153 
7154 
7155 
7156     // ISOLTS 878 01c - op1 and xlate table are prepaged, in that order
7157     // prepage op1
7158     int lastpageidx = ((int)e->N1 + (int)e->CN1 -1) / e->srcSZ;
7159     if (lastpageidx>0)
7160         EISReadIdx(&e->ADDR1, (uint)lastpageidx);
7161     // prepage xlate table
7162     EISReadIdx(&e->ADDR3, 0);
7163     EISReadIdx(&e->ADDR3, xlatSize-1);
7164 
7165     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7166 
7167     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
7168     word9 fillT = fill;  // possibly truncated fill pattern
7169     // play with fill if we need to use it
7170     switch(e->srcSZ)
7171     {
7172         case 4:
7173             fillT = fill & 017;    // truncate upper 5-bits
7174             break;
7175         case 6:
7176             fillT = fill & 077;    // truncate upper 3-bits
7177             break;
7178     }
7179 
7180     sim_debug (DBG_TRACEEXT, & cpu_dev,
7181       "%s srcCN:%d dstCN:%d srcSZ:%d dstSZ:%d T:%d fill:%03o/%03o N1:%d N2:%d\n",
7182       __func__, e -> CN1, e -> CN2, e -> srcSZ, e -> dstSZ, T,
7183       fill, fillT, e -> N1, e -> N2);
7184 
7185     PNL (L68_ (if (max (e->N1, e->N2) < 128)
7186       DU_CYCLE_FLEN_128;))
7187 
7188     for ( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY ++)
7189     {
7190         word9 c = EISget469(1, cpu.du.CHTALLY); // get src char
7191         int cidx = 0;
7192 
7193 #ifdef EIS_PTR3
7194         if (TA1 == TA2)
7195 #else
7196         if (e->TA1 == e->TA2)
7197 #endif
7198             EISput469(2, cpu.du.CHTALLY, xlate (&e->ADDR3, dstTA, c));
7199         else
7200         {
7201             // 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.
7202             cidx = c;
7203 
7204             word9 cout = xlate(&e->ADDR3, dstTA, (uint) cidx);
7205 
7206 //            switch(e->dstSZ)
7207 //            {
7208 //                case 4:
7209 //                    cout &= 017;    // truncate upper 5-bits
7210 //                    break;
7211 //                case 6:
7212 //                    cout &= 077;    // truncate upper 3-bits
7213 //                    break;
7214 //            }
7215 
7216             switch (e->srcSZ)
7217             {
7218                 case 6:
7219                     switch(e->dstSZ)
7220                     {
7221                         case 4:
7222                             cout &= 017;    // truncate upper 2-bits
7223                             break;
7224                         case 9:
7225                             break;              // should already be 0-filled
7226                     }
7227                     break;
7228                 case 9:
7229                     switch(e->dstSZ)
7230                     {
7231                         case 4:
7232                             cout &= 017;    // truncate upper 5-bits
7233                             break;
7234                         case 6:
7235                             cout &= 077;    // truncate upper 3-bits
7236                             break;
7237                     }
7238                     break;
7239             }
7240 
7241             EISput469 (2, cpu.du.CHTALLY, cout);
7242         }
7243     }
7244 
7245     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7246     //    m = C(FILL)
7247     //    C(Y-char93)m → C(Y-charn2)N2-i
7248 
7249     if (e->N1 < e->N2)
7250     {
7251         word9 cfill = xlate(&e->ADDR3, dstTA, fillT);
7252         switch (e->srcSZ)
7253         {
7254             case 6:
7255                 switch(e->dstSZ)
7256                 {
7257                     case 4:
7258                         cfill &= 017;    // truncate upper 2-bits
7259                         break;
7260                     case 9:
7261                         break;              // should already be 0-filled
7262                 }
7263                 break;
7264             case 9:
7265                 switch(e->dstSZ)
7266                 {
7267                     case 4:
7268                         cfill &= 017;    // truncate upper 5-bits
7269                         break;
7270                     case 6:
7271                         cfill &= 077;    // truncate upper 3-bits
7272                         break;
7273                 }
7274                 break;
7275         }
7276 
7277         for( ; cpu.du.CHTALLY < e->N2 ; cpu.du.CHTALLY ++)
7278             EISput469 (2, cpu.du.CHTALLY, cfill);
7279     }
7280 
7281     cleanupOperandDescriptor (1);
7282     cleanupOperandDescriptor (2);
7283     cleanupOperandDescriptor (3);
7284 
7285     if (e->N1 > e->N2)
7286       {
7287         SET_I_TRUNC;
7288         if (T && ! TST_I_OMASK)
7289           doFault(FAULT_OFL, fst_zero, "mvt truncation fault");
7290       }
7291     else
7292       CLR_I_TRUNC;
7293   }
7294 
7295 /*
7296  * cmpn - Compare Numeric
7297  */
7298 
7299 void cmpn (void)
     /* [previous][next][first][last][top][bottom][index][help] */
7300 {
7301     EISstruct * e = & cpu.currentEISinstruction;
7302 
7303     // C(Y-charn1) :: C(Y-charn2) as numeric values
7304 
7305     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7306     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7307     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7308 
7309     fault_ipr_subtype_ mod_fault = 0;
7310 
7311 #ifndef EIS_SETUP
7312     setupOperandDescriptor(1, &mod_fault);
7313     setupOperandDescriptor(2, &mod_fault);
7314 #endif
7315 
7316     parseNumericOperandDescriptor(1, &mod_fault);
7317     parseNumericOperandDescriptor(2, &mod_fault);
7318 
7319     L68_ (
7320       // L68 raises it immediately
7321       if (mod_fault)
7322         {
7323           doFault (FAULT_IPR,
7324                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7325                    "Illegal modifier");
7326         }
7327     )
7328 
7329     // Bits 0-10 MBZ
7330     if (IWB_IRODD & 0777600000000)
7331       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpn 0-10 MBZ");
7332 
7333     DPS8M_ (
7334       // DPS8M raises it delayed
7335       if (mod_fault)
7336         {
7337           doFault (FAULT_IPR,
7338                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7339                    "Illegal modifier");
7340         }
7341     )
7342 
7343     uint srcTN = e->TN1;    // type of chars in src
7344 
7345     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
7346 
7347     /*
7348      * Here we need to distinguish between 4 type of numbers.
7349      *
7350      * CSFL - Floating-point, leading sign
7351      * CSLS - Scaled fixed-point, leading sign
7352      * CSTS - Scaled fixed-point, trailing sign
7353      * CSNS - Scaled fixed-point, unsigned
7354      */
7355 
7356     // determine precision
7357     switch(e->S1)
7358     {
7359         case CSFL:
7360             n1 = (int) e->N1 - 1; // need to account for the - sign
7361             if (srcTN == CTN4)
7362                 n1 -= 2;    // 2 4-bit digits exponent
7363             else
7364                 n1 -= 1;    // 1 9-bit digit exponent
7365             sc1 = 0;        // no scaling factor
7366             break;
7367 
7368         case CSLS:
7369         case CSTS:
7370             n1 = (int) e->N1 - 1; // only 1 sign
7371             sc1 = -e->SF1;
7372             break;
7373 
7374         case CSNS:
7375             n1 = (int) e->N1;     // no sign
7376             sc1 = -e->SF1;
7377             break;  // no sign wysiwyg
7378     }
7379 
7380     if (n1 < 1)
7381         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n1<1");
7382 
7383     switch(e->S2)
7384     {
7385         case CSFL:
7386             n2 = (int) e->N2 - 1; // need to account for the sign
7387             if (e->TN2 == CTN4)
7388                 n2 -= 2;    // 2 4-bit digit exponent
7389             else
7390                 n2 -= 1;    // 1 9-bit digit exponent
7391             sc2 = 0;        // no scaling factor
7392             break;
7393 
7394         case CSLS:
7395         case CSTS:
7396             n2 = (int) e->N2 - 1; // 1 sign
7397             sc2 = -e->SF2;
7398             break;
7399 
7400         case CSNS:
7401             n2 = (int) e->N2;     // no sign
7402             sc2 = -e->SF2;
7403             break;  // no sign wysiwyg
7404     }
7405 
7406     if (n2 < 1)
7407         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n2<1");
7408 
7409     decContext set;
7410     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
7411     decContextDefaultDPS8(&set);
7412 
7413     set.traps=0;
7414 
7415     decNumber _1, _2, _3;
7416 
7417     EISloadInputBufferNumeric (1);   // according to MF1
7418 
7419     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
7420     if (e->sign == -1)
7421         op1->bits |= DECNEG;
7422     if (e->S1 == CSFL)
7423         op1->exponent = e->exponent;
7424 
7425     EISloadInputBufferNumeric (2);   // according to MF2
7426 
7427     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
7428     if (e->sign == -1)
7429         op2->bits |= DECNEG;
7430     if (e->S2 == CSFL)
7431         op2->exponent = e->exponent;
7432 
7433     // signed-compare
7434     decNumber *cmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7435     int cSigned = decNumberToInt32(cmp, &set);
7436 
7437     // take absolute value of operands
7438     op1 = decNumberAbs(op1, op1, &set);
7439     op2 = decNumberAbs(op2, op2, &set);
7440 
7441     // magnitude-compare
7442     decNumber *mcmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7443     int cMag = decNumberToInt32(mcmp, &set);
7444 
7445     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7446     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7447     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7448 
7449     SC_I_ZERO (cSigned == 0);
7450     SC_I_NEG (cSigned == 1);
7451     SC_I_CARRY (cMag != 1);
7452 
7453     cleanupOperandDescriptor (1);
7454     cleanupOperandDescriptor (2);
7455 
7456 }
7457 
7458 /*
7459  * mvn - move numeric (initial version was deleted by house gnomes)
7460  */
7461 
7462 /*
7463  * write 4-bit chars to memory @ pos ...
7464  */
7465 
7466 static void EISwrite4(EISaddr *p, int *pos, word4 char4)
     /* [previous][next][first][last][top][bottom][index][help] */
7467 {
7468     word36 w;
7469     if (*pos > 7)    // out-of-range?
7470     {
7471         *pos = 0;    // reset to 1st byte
7472 #ifdef EIS_PTR
7473         long eisaddr_idx = EISADDR_IDX (p);
7474 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7475         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7476 #else
7477         p->address = (p->address + 1) & AMASK;        // goto next dstAddr in memory
7478 #endif
7479     }
7480 
7481     w = EISRead(p);      // read dst memory into w
7482 
7483 // AL39, Figure 2-3
7484     switch (*pos)
7485     {
7486         case 0:
7487             //w = bitfieldInsert36(w, char4, 31, 5);
7488             w = setbits36_4 (w, 1, char4);
7489             break;
7490         case 1:
7491             //w = bitfieldInsert36(w, char4, 27, 4);
7492             w = setbits36_4 (w, 5, char4);
7493             break;
7494         case 2:
7495             //w = bitfieldInsert36(w, char4, 22, 5);
7496             w = setbits36_4 (w, 10, char4);
7497             break;
7498         case 3:
7499             //w = bitfieldInsert36(w, char4, 18, 4);
7500             w = setbits36_4 (w, 14, char4);
7501             break;
7502         case 4:
7503             //w = bitfieldInsert36(w, char4, 13, 5);
7504             w = setbits36_4 (w, 19, char4);
7505             break;
7506         case 5:
7507             //w = bitfieldInsert36(w, char4, 9, 4);
7508             w = setbits36_4 (w, 23, char4);
7509             break;
7510         case 6:
7511             //w = bitfieldInsert36(w, char4, 4, 5);
7512             w = setbits36_4 (w, 28, char4);
7513             break;
7514         case 7:
7515             //w = bitfieldInsert36(w, char4, 0, 4);
7516             w = setbits36_4 (w, 32, char4);
7517             break;
7518     }
7519 
7520     EISWriteIdx(p, 0, w, true); // XXX this is the inefficient part!
7521 
7522     *pos += 1;       // to next char.
7523 }
7524 
7525 /*
7526  * write 9-bit bytes to memory @ pos ...
7527  */
7528 
7529 static void EISwrite9(EISaddr *p, int *pos, word9 char9)
     /* [previous][next][first][last][top][bottom][index][help] */
7530 {
7531     word36 w;
7532     if (*pos > 3)    // out-of-range?
7533     {
7534         *pos = 0;    // reset to 1st byte
7535 #ifdef EIS_PTR
7536         long eisaddr_idx = EISADDR_IDX (p);
7537 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7538         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7539 #else
7540         p->address = (p->address + 1) & AMASK;       // goto next dstAddr in memory
7541 #endif
7542     }
7543 
7544     w = EISRead(p);      // read dst memory into w
7545 
7546 // AL39, Figure 2-5
7547     switch (*pos)
7548     {
7549         case 0:
7550             //w = bitfieldInsert36(w, char9, 27, 9);
7551             w = setbits36_9 (w, 0, char9);
7552             break;
7553         case 1:
7554             //w = bitfieldInsert36(w, char9, 18, 9);
7555             w = setbits36_9 (w, 9, char9);
7556             break;
7557         case 2:
7558             //w = bitfieldInsert36(w, char9, 9, 9);
7559             w = setbits36_9 (w, 18, char9);
7560             break;
7561         case 3:
7562             //w = bitfieldInsert36(w, char9, 0, 9);
7563             w = setbits36_9 (w, 27, char9);
7564             break;
7565     }
7566 
7567     EISWriteIdx (p, 0, w, true); // XXX this is the inefficient part!
7568 
7569     *pos += 1;       // to next byte.
7570 }
7571 
7572 /*
7573  * write a 4-, or 9-bit numeric char to dstAddr ....
7574  */
7575 
7576 static void EISwrite49(EISaddr *p, int *pos, int tn, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
7577 {
7578     switch(tn)
7579     {
7580         case CTN4:
7581             EISwrite4(p, pos, (word4) c49);
7582             return;
7583         case CTN9:
7584             EISwrite9(p, pos, c49);
7585             return;
7586     }
7587 }
7588 
7589 void mvn (void)
     /* [previous][next][first][last][top][bottom][index][help] */
7590 {
7591     /*
7592      * EXPLANATION:
7593      * Starting at location YC1, the decimal number of data type TN1 and sign
7594      * and decimal type S1 is moved, properly scaled, to the decimal number of
7595      * data type TN2 and sign and decimal type S2 that starts at location YC2.
7596      * If S2 indicates a fixed-point format, the results are stored as L2
7597      * digits using scale factor SF2, and thereby may cause
7598      * most-significant-digit overflow and/or least- significant-digit
7599      * truncation.
7600      * If P = 1, positive signed 4-bit results are stored using octal 13 as the
7601      * plus sign. Rounding is legal for both fixed-point and floating-point
7602      * formats. If P = 0, positive signed 4-bit results are stored using octal
7603      * 14 as the plus sign.
7604      * Provided that string 1 and string 2 are not overlapped, the contents of
7605      * the decimal number that starts in location YC1 remain unchanged.
7606      */
7607 
7608     EISstruct * e = & cpu.currentEISinstruction;
7609 
7610     fault_ipr_subtype_ mod_fault = 0;
7611 
7612 #ifndef EIS_SETUP
7613     setupOperandDescriptor(1, &mod_fault);
7614     setupOperandDescriptor(2, &mod_fault);
7615 #endif
7616 
7617     parseNumericOperandDescriptor(1, &mod_fault);
7618     parseNumericOperandDescriptor(2, &mod_fault);
7619 
7620     L68_ (
7621       // L68 raises it immediately
7622       if (mod_fault)
7623         {
7624           doFault (FAULT_IPR,
7625                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7626                    "Illegal modifier");
7627         }
7628     )
7629 
7630     // Bits 2-8 MBZ
7631     if (IWB_IRODD & 0377000000000)
7632      doFault (FAULT_IPR,
7633               (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault},
7634               "mvn 2-8 MBZ");
7635 
7636     DPS8M_ (
7637       // DPS8M raises it delayed
7638       if (mod_fault)
7639         {
7640           doFault (FAULT_IPR,
7641                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7642                    "Illegal modifier");
7643         }
7644     )
7645 
7646     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character
7647                                               //  control
7648     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7649     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
7650     PNL (L68_ (if (R)
7651       DU_CYCLE_FRND;))
7652 
7653     uint srcTN = e->TN1;    // type of chars in src
7654 
7655     uint dstTN = e->TN2;    // type of chars in dst
7656     uint dstCN = e->CN2;    // starting at char pos CN
7657 
7658     sim_debug (DBG_CAC, & cpu_dev,
7659                "mvn(1): TN1 %d CN1 %d N1 %d TN2 %d CN2 %d N2 %d\n",
7660                e->TN1, e->CN1, e->N1, e->TN2, e->CN2, e->N2);
7661     sim_debug (DBG_CAC, & cpu_dev,
7662                "mvn(2): SF1 %d              SF2 %d\n",
7663                e->SF1, e->SF2);
7664     sim_debug (DBG_CAC, & cpu_dev,
7665                "mvn(3): OP1 %012"PRIo64" OP2 %012"PRIo64"\n",
7666                e->OP1, e->OP2);
7667 
7668     int n1 = 0, n2 = 0, sc1 = 0;
7669 
7670     /*
7671      * Here we need to distinguish between 4 type of numbers.
7672      *
7673      * CSFL - Floating-point, leading sign
7674      * CSLS - Scaled fixed-point, leading sign
7675      * CSTS - Scaled fixed-point, trailing sign
7676      * CSNS - Scaled fixed-point, unsigned
7677      */
7678 
7679     // determine precision
7680     switch(e->S1)
7681     {
7682         case CSFL:
7683             n1 = (int) e->N1 - 1; // need to account for the - sign
7684             if (srcTN == CTN4)
7685                 n1 -= 2;    // 2 4-bit digits exponent
7686             else
7687                 n1 -= 1;    // 1 9-bit digit exponent
7688             sc1 = 0;        // no scaling factor
7689             break;
7690 
7691         case CSLS:
7692         case CSTS:
7693             n1 = (int) e->N1 - 1; // only 1 sign
7694             sc1 = -e->SF1;
7695             break;
7696 
7697         case CSNS:
7698             n1 = (int) e->N1;     // no sign
7699             sc1 = -e->SF1;
7700             break;  // no sign wysiwyg
7701     }
7702 
7703     sim_debug (DBG_CAC, & cpu_dev, "n1 %d sc1 %d\n", n1, sc1);
7704 
7705     // RJ78: An Illegal Procedure fault occurs if:
7706     // The values for the number of characters (N1 or N2) of the data
7707     // descriptors are not large enough to hold the number of characters
7708     // required for the specified sign and/or exponent, plus at least one
7709     // digit.
7710 
7711     if (n1 < 1)
7712         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n1<1");
7713 
7714     switch(e->S2)
7715     {
7716         case CSFL:
7717             n2 = (int) e->N2 - 1; // need to account for the sign
7718             if (dstTN == CTN4)
7719                 n2 -= 2;    // 2 4-bit digit exponent
7720             else
7721                 n2 -= 1;    // 1 9-bit digit exponent
7722             break;
7723 
7724         case CSLS:
7725         case CSTS:
7726             n2 = (int) e->N2 - 1; // 1 sign
7727             break;
7728 
7729         case CSNS:
7730             n2 = (int) e->N2;     // no sign
7731             break;          // no sign wysiwyg
7732     }
7733 
7734     sim_debug (DBG_CAC, & cpu_dev, "n2 %d\n", n2);
7735 
7736     if (n2 < 1)
7737         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n2<1");
7738 
7739     decContext set;
7740     decContextDefaultDPS8(&set);
7741     set.traps=0;
7742 
7743     decNumber _1;
7744 
7745     EISloadInputBufferNumeric (1);   // according to MF1
7746 
7747     decNumber *op1 = decBCD9ToNumber (e->inBuffer, n1, sc1, &_1);
7748 
7749     if (e->sign == -1)
7750         op1->bits |= DECNEG;
7751     if (e->S1 == CSFL)
7752         op1->exponent = e->exponent;
7753     if (decNumberIsZero (op1))
7754         op1->exponent = 127;
7755 
7756     if_sim_debug (DBG_CAC, & cpu_dev)
7757     {
7758         PRINTDEC ("mvn input (op1)", op1);
7759     }
7760 
7761     bool Ovr = false, EOvr = false, Trunc = false;
7762 
7763     uint8_t out [256];
7764     char * res = formatDecimal (out, & set, op1, n2, (int) e->S2, e->SF2, R,
7765                                 & Ovr, & Trunc);
7766 
7767     sim_debug (DBG_CAC, & cpu_dev, "mvn res: '%s'\n", res);
7768 
7769     // now write to memory in proper format.....
7770 
7771     //word18 dstAddr = e->dstAddr;
7772     int pos = (int) dstCN;
7773 
7774     // 1st, take care of any leading sign .......
7775     switch(e->S2)
7776     {
7777         case CSFL:  // floating-point, leading sign.
7778         case CSLS:  // fixed-point, leading sign
7779             switch(dstTN)
7780             {
7781                 case CTN4:
7782  // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7783  // sign character is placed appropriately if the result of the operation is
7784  // positive.
7785                     if (e->P)
7786                         // special +
7787                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7788                                    (decNumberIsNegative (op1) &&
7789                                     ! decNumberIsZero(op1)) ? 015 : 013);
7790                     else
7791                         // default +
7792                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7793                                     (decNumberIsNegative (op1) &&
7794                                      ! decNumberIsZero (op1)) ? 015 : 014);
7795                     break;
7796                 case CTN9:
7797                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7798                                 (decNumberIsNegative (op1) &&
7799                                  ! decNumberIsZero (op1)) ? '-' : '+');
7800                     break;
7801             }
7802             break;
7803 
7804         case CSTS:  // nuttin' to do here .....
7805         case CSNS:
7806             break;  // no sign wysiwyg
7807     }
7808 
7809     // 2nd, write the digits .....
7810     for (int i = 0 ; i < n2 ; i ++)
7811         switch (dstTN)
7812         {
7813             case CTN4:
7814                 EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7815                             (word9) (res[i] - '0'));
7816                 break;
7817             case CTN9:
7818                 EISwrite49 (& e->ADDR2, & pos, (int) dstTN, (word9) res[i]);
7819                 break;
7820         }
7821 
7822     // 3rd, take care of any trailing sign or exponent ...
7823     switch(e->S2)
7824     {
7825         case CSTS:  // write trailing sign ....
7826             switch(dstTN)
7827             {
7828                 case CTN4:
7829 // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7830 // sign character is placed appropriately if the result of the operation is
7831 // positive.
7832                     if (e->P)
7833                         // special +
7834                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7835                                     (decNumberIsNegative (op1) &&
7836                                      ! decNumberIsZero(op1)) ? 015 :  013);
7837                     else
7838                         // default +
7839                         EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7840                                     (decNumberIsNegative (op1) &&
7841                                      ! decNumberIsZero (op1)) ? 015 :  014);
7842                     break;
7843 
7844                 case CTN9:
7845                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7846                                 (decNumberIsNegative (op1) &&
7847                                  ! decNumberIsZero(op1)) ? '-' : '+');
7848                     break;
7849             }
7850             break;
7851 
7852         case CSFL:  // floating-point, leading sign.
7853             // write the exponent
7854             switch(dstTN)
7855             {
7856                 case CTN4:
7857                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7858                                 (op1->exponent >> 4) & 0xf); // upper 4-bits
7859                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7860                                 op1->exponent       & 0xf); // lower 4-bits
7861                     break;
7862                 case CTN9:
7863                     EISwrite49 (& e->ADDR2, & pos, (int) dstTN,
7864                                  op1->exponent & 0xff); // write 8-bit exponent
7865                 break;
7866             }
7867             break;
7868 
7869         case CSLS:  // fixed point, leading sign - already done
7870         case CSNS:  // fixed point, unsigned - nuttin' needed to do
7871             break;
7872     }
7873 
7874     // set flags, etc ...
7875     if (e->S2 == CSFL)
7876     {
7877         if (op1->exponent > 127)
7878         {
7879             SET_I_EOFL;
7880             EOvr = true;
7881         }
7882         if (op1->exponent < -128)
7883         {
7884             SET_I_EUFL;
7885             EOvr = true;
7886         }
7887     }
7888 
7889 sim_debug (DBG_CAC, & cpu_dev, "is neg %o\n", decNumberIsNegative(op1));
7890 sim_debug (DBG_CAC, & cpu_dev, "is zero %o\n", decNumberIsZero(op1));
7891 sim_debug (DBG_CAC, & cpu_dev, "R %o\n", R);
7892 sim_debug (DBG_CAC, & cpu_dev, "Trunc %o\n", Trunc);
7893 sim_debug (DBG_CAC, & cpu_dev, "TRUNC %o\n", TST_I_TRUNC);
7894 sim_debug (DBG_CAC, & cpu_dev, "OMASK %o\n", TST_I_OMASK);
7895 sim_debug (DBG_CAC, & cpu_dev, "tstOVFfault %o\n", tstOVFfault ());
7896 sim_debug (DBG_CAC, & cpu_dev, "T %o\n", T);
7897 sim_debug (DBG_CAC, & cpu_dev, "EOvr %o\n", EOvr);
7898 sim_debug (DBG_CAC, & cpu_dev, "Ovr %o\n", Ovr);
7899     // set negative indicator if op3 < 0
7900     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));
7901 
7902     // set zero indicator if op3 == 0
7903     SC_I_ZERO (decNumberIsZero(op1));
7904 
7905     // If the truncation condition exists without rounding, then ON;
7906     // otherwise OFF
7907     SC_I_TRUNC (!R && Trunc);
7908 
7909     cleanupOperandDescriptor (1);
7910     cleanupOperandDescriptor (2);
7911 
7912     if (TST_I_TRUNC && T && tstOVFfault ())
7913         doFault (FAULT_OFL, fst_zero, "mvn truncation(overflow) fault");
7914     if (EOvr && tstOVFfault ())
7915         doFault (FAULT_OFL, fst_zero, "mvn over/underflow fault");
7916     if (Ovr)
7917     {
7918         SET_I_OFLOW;
7919         if (tstOVFfault ())
7920           doFault (FAULT_OFL, fst_zero, "mvn overflow fault");
7921     }
7922 }
7923 
7924 void csl (void)
     /* [previous][next][first][last][top][bottom][index][help] */
7925   {
7926     EISstruct * e = & cpu.currentEISinstruction;
7927 
7928     // For i = bits 1, 2, ..., minimum (N1,N2)
7929     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
7930     //   C(BOLR)m → C(Y-bit2)i-1
7931     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
7932     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
7933     //   C(BOLR)m → C(Y-bit2)i-1
7934     //
7935     // INDICATORS: (Indicators not listed are not affected)
7936     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
7937     //     Truncation If N1 > N2, then ON; otherwise OFF
7938     //
7939     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
7940     // processed and the truncation indicator is set ON.
7941     //
7942     // If T = 1 and the truncation indicator is set ON by execution of the
7943     // instruction, then a truncation (overflow) fault occurs.
7944     //
7945     // BOLR
7946     // If first operand    and    second operand    then result
7947     // bit is:                    bit is:           is from bit:
7948     //        0                          0                      5
7949     //        0                          1                      6
7950     //        1                          0                      7
7951     //        1                          1                      8
7952     //
7953     // The Boolean operations most commonly used are
7954     //                  BOLR Field Bits
7955     // Operation        5      6      7      8
7956     //
7957     // MOVE             0      0      1      1
7958     // AND              0      0      0      1
7959     // OR               0      1      1      1
7960     // NAND             1      1      1      0
7961     // EXCLUSIVE OR     0      1      1      0
7962     // Clear            0      0      0      0
7963     // Invert           1      1      0      0
7964     //
7965 
7966 // 0 0 0 0  Clear
7967 // 0 0 0 1  a AND b
7968 // 0 0 1 0  a AND !b
7969 // 0 0 1 1  a
7970 // 0 1 0 0  !a AND b
7971 // 0 1 0 1  b
7972 // 0 1 1 0  a XOR b
7973 // 0 1 1 1  a OR b
7974 // 1 0 0 0  !a AND !b     !(a OR b)
7975 // 1 0 0 1  a == b        !(a XOR b)
7976 // 1 0 1 0  !b
7977 // 1 0 1 1  !b OR A
7978 // 1 1 0 0  !a
7979 // 1 1 0 1  !b AND a
7980 // 1 1 1 0  a NAND b
7981 // 1 1 1 1  Set
7982 
7983     fault_ipr_subtype_ mod_fault = 0;
7984 
7985 #ifndef EIS_SETUP
7986     setupOperandDescriptor (1, & mod_fault);
7987     setupOperandDescriptor (2, & mod_fault);
7988 #endif
7989 
7990     parseBitstringOperandDescriptor (1, & mod_fault);
7991     parseBitstringOperandDescriptor (2, & mod_fault);
7992 
7993     L68_ (
7994       // L68 raises it immediately
7995       if (mod_fault)
7996           doFault (FAULT_IPR,
7997                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7998                    "Illegal modifier");
7999     )
8000 
8001     // Bits 1-4 and 10 MBZ
8002     if (IWB_IRODD & 0360200000000)
8003       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8004 
8005     DPS8M_ (
8006       // DPS8M raises it delayed
8007       if (mod_fault)
8008           doFault (FAULT_IPR,
8009                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8010                    "Illegal modifier");
8011     )
8012 
8013     e->ADDR1.cPos = (int) e->C1;
8014     e->ADDR2.cPos = (int) e->C2;
8015 
8016     e->ADDR1.bPos = (int) e->B1;
8017     e->ADDR2.bPos = (int) e->B2;
8018 
8019     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8020     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8021 
8022     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8023     bool B5 = !! (BOLR & 8);
8024     bool B6 = !! (BOLR & 4);
8025     bool B7 = !! (BOLR & 2);
8026     bool B8 = !! (BOLR & 1);
8027 
8028     e->ADDR1.mode = eRWreadBit;
8029 
8030 #ifndef EIS_PTR
8031     sim_debug (DBG_TRACEEXT, & cpu_dev,
8032                "CSL N1 %d N2 %d\n"
8033                "CSL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8034                "CSL BOLR %u%u%u%u\n"
8035                "CSL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8036                "CSL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8037                e -> N1, e -> N2,
8038                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8039                B5, B6, B7, B8,
8040                e -> addr [0].SNR, e -> addr [0].address,
8041                e -> addr [0].cPos, e -> addr [0].bPos,
8042                e -> addr [1].SNR, e -> addr [1].address,
8043                e -> addr [1].cPos, e -> addr [1].bPos);
8044 #endif
8045 
8046     bool bR = false; // result bit
8047 
8048     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8049                  DU_CYCLE_FLEN_128;))
8050 
8051     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8052       {
8053         bool b1 = EISgetBitRWN(&e->ADDR1, true);
8054         e->ADDR2.mode = eRWreadBit;
8055         bool b2 = EISgetBitRWN(&e->ADDR2, true);
8056 
8057         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8058 
8059         if (bR)
8060           {
8061             //CLR_I_ZERO);
8062             cpu.du.Z = 0;
8063           }
8064 
8065         // write out modified bit
8066         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8067         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8068         // if ADDR1 is on a word boundary, it might fault on the next loop,
8069         // so we flush the write in case.
8070         EISgetBitRWN(&e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8071     }
8072 
8073     if (e->N1 < e->N2)
8074       {
8075         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8076           {
8077             bool b1 = F;
8078 
8079             e->ADDR2.mode = eRWreadBit;
8080             bool b2 = EISgetBitRWN(&e->ADDR2, true);
8081 
8082             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8083 
8084             if (bR)
8085               {
8086                 //CLR_I_ZERO;
8087                 cpu.du.Z = 0;
8088               }
8089 
8090             // write out modified bit
8091             e->ADDR2.bit = bR ? 1 : 0;
8092             e->ADDR2.mode = eRWwriteBit;
8093             // if ADDR1 is on a word boundary, it might fault on the next loop,
8094             // so we flush the write in case.
8095             EISgetBitRWN(&e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8096           }
8097       }
8098 
8099     EISWriteCache (&e->ADDR2);
8100 
8101     cleanupOperandDescriptor (1);
8102     cleanupOperandDescriptor (2);
8103 
8104     SC_I_ZERO (cpu.du.Z);
8105     if (e->N1 > e->N2)
8106       {
8107         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8108         // processed and the truncation indicator is set ON.
8109         //
8110         // If T = 1 and the truncation indicator is set ON by execution of the
8111         // instruction, then a truncation (overflow) fault occurs.
8112 
8113         SET_I_TRUNC;
8114         if (T && tstOVFfault ())
8115           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8116       }
8117     else
8118       {
8119         CLR_I_TRUNC;
8120       }
8121   }
8122 
8123 /*
8124  * return B (bit position), C (char position) and word offset given:
8125  *  'length' # of bits, etc ....
8126  *  'initC' initial char position (C)
8127  *  'initB' initial bit position
8128  */
8129 
8130 static void getBitOffsets(int length, int initC, int initB, int *nWords, int *newC, int *newB)
     /* [previous][next][first][last][top][bottom][index][help] */
8131 {
8132     if (length == 0)
8133         return;
8134 
8135     int endBit = (length + 9 * initC + initB - 1) % 36;
8136 
8137     //int numWords = (length + 35) / 36;  // how many additional words will the bits take up?
8138     int numWords = (length + 9 * initC + initB + 35) / 36;  // how many additional words will the bits take up?
8139     int lastWordOffset = numWords - 1;
8140 
8141     if (lastWordOffset > 0)          // more that the 1 word needed?
8142         *nWords = lastWordOffset;  // # of additional words
8143     else
8144         *nWords = 0;    // no additional words needed
8145 
8146     *newC = endBit / 9; // last character number
8147     *newB = endBit % 9; // last bit number
8148 }
8149 
8150 static bool EISgetBitRWNR (EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
8151   {
8152     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
8153     int baseBitPosn = baseCharPosn + p -> bPos;
8154     baseBitPosn -= (int) cpu.du.CHTALLY;
8155 
8156     int bitPosn = baseBitPosn % 36;
8157     int woff = baseBitPosn / 36;
8158     while (bitPosn < 0)
8159       {
8160         bitPosn += 36;
8161         woff -= 1;
8162       }
8163 
8164 /* if (bitPosn < 0) { */
8165 /* sim_printf ("cPos %d bPos %d\n", p->cPos, p->bPos); */
8166 /* sim_printf ("baseCharPosn %d baseBitPosn %d\n", baseCharPosn, baseBitPosn); */
8167 /* sim_printf ("CHTALLY %d baseBitPosn %d\n", cpu.du.CHTALLY, baseBitPosn); */
8168 /* sim_printf ("bitPosn %d woff %d\n", bitPosn, woff); */
8169 /* sim_warn ("EISgetBitRWNR oops\n"); */
8170 /* return false; */
8171 /* } */
8172 
8173 #ifdef EIS_PTR
8174     long eisaddr_idx = EISADDR_IDX (p);
8175 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8176     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
8177     cpu.du.Dk_PTR_W[eisaddr_idx] += (word18) woff;
8178     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8179 #else
8180     word18 saveAddr = p -> address;
8181     //p -> address += (word18) woff;
8182     //ubsan
8183     p->address = (word18) (((word18s) p->address) + (word18s) woff);
8184 #endif
8185 
8186     p -> data = EISRead (p); // read data word from memory
8187 
8188     if (p -> mode == eRWreadBit)
8189       {
8190         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
8191       }
8192     else if (p -> mode == eRWwriteBit)
8193       {
8194         //p -> data = bitfieldInsert36 (p -> data, p -> bit, bitPosn, 1);
8195         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
8196 
8197         EISWriteIdx (p, 0, p -> data, flush); // write data word to memory
8198       }
8199 
8200     p->last_bit_posn = bitPosn;
8201 
8202 #ifdef EIS_PTR
8203     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
8204 #else
8205     p -> address = saveAddr;
8206 #endif
8207     return p -> bit;
8208   }
8209 
8210 void csr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8211   {
8212     EISstruct * e = & cpu.currentEISinstruction;
8213 
8214     // For i = bits 1, 2, ..., minimum (N1,N2)
8215     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8216     //   C(BOLR)m → C( Y-bit2)N2-i
8217     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8218     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8219     //    C(BOLR)m → C( Y-bit2)N2-i
8220     // INDICATORS: (Indicators not listed are not affected)
8221     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8222     //     Truncation If N1 > N2, then ON; otherwise OFF
8223     //
8224     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8225     // processed and the truncation indicator is set ON.
8226     //
8227     // If T = 1 and the truncation indicator is set ON by execution of the
8228     // instruction, then a truncation (overflow) fault occurs.
8229     //
8230     // BOLR
8231     // If first operand    and    second operand    then result
8232     // bit is:                    bit is:           is from bit:
8233     //        0                          0                      5
8234     //        0                          1                      6
8235     //        1                          0                      7
8236     //        1                          1                      8
8237     //
8238     // The Boolean operations most commonly used are
8239     //                  BOLR Field Bits
8240     // Operation        5      6      7      8
8241     //
8242     // MOVE             0      0      1      1
8243     // AND              0      0      0      1
8244     // OR               0      1      1      1
8245     // NAND             1      1      1      0
8246     // EXCLUSIVE OR     0      1      1      0
8247     // Clear            0      0      0      0
8248     // Invert           1      1      0      0
8249     //
8250 
8251     fault_ipr_subtype_ mod_fault = 0;
8252 
8253 #ifndef EIS_SETUP
8254     setupOperandDescriptor(1, &mod_fault);
8255     setupOperandDescriptor(2, &mod_fault);
8256 #endif
8257 
8258     parseBitstringOperandDescriptor(1, &mod_fault);
8259     parseBitstringOperandDescriptor(2, &mod_fault);
8260 
8261     L68_ (
8262       // L68 raises it immediately
8263       if (mod_fault)
8264           doFault (FAULT_IPR,
8265                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8266                    "Illegal modifier");
8267     )
8268 
8269     // Bits 1-4 and 10 MBZ
8270     if (IWB_IRODD & 0360200000000)
8271       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8272 
8273     DPS8M_ (
8274       // DPS8M raises it delayed
8275       if (mod_fault)
8276           doFault (FAULT_IPR,
8277                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8278                    "Illegal modifier");
8279     )
8280 
8281     e->ADDR1.cPos = (int) e->C1;
8282     e->ADDR2.cPos = (int) e->C2;
8283 
8284     e->ADDR1.bPos = (int) e->B1;
8285     e->ADDR2.bPos = (int) e->B2;
8286 
8287     // get new char/bit offsets
8288     int numWords1=0, numWords2=0;
8289 
8290     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8291     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8292     PNL (cpu.du.D1_PTR_W &= AMASK);
8293 #ifdef EIS_PTR
8294     cpu.du.D1_PTR_W += (word18) numWords1;
8295     cpu.du.D1_PTR_W &= AMASK;
8296 #else
8297     e->ADDR1.address += (word18) numWords1;
8298 #endif
8299 
8300     sim_debug (DBG_TRACEEXT, & cpu_dev,
8301                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8302                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8303     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8304     sim_debug (DBG_TRACEEXT, & cpu_dev,
8305                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8306                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8307     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8308     PNL (cpu.du.D2_PTR_W &= AMASK);
8309 #ifdef EIS_PTR
8310     cpu.du.D2_PTR_W += (word18) numWords1;
8311     cpu.du.D2_PTR_W &= AMASK;
8312 #else
8313     e->ADDR2.address += (word18) numWords2;
8314 #endif
8315 
8316     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8317     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8318 
8319     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8320     bool B5 = !! (BOLR & 8);
8321     bool B6 = !! (BOLR & 4);
8322     bool B7 = !! (BOLR & 2);
8323     bool B8 = !! (BOLR & 1);
8324 
8325     e->ADDR1.mode = eRWreadBit;
8326 
8327     CLR_I_TRUNC;     // assume N1 <= N2
8328 
8329     bool bR = false; // result bit
8330 
8331     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8332                  DU_CYCLE_FLEN_128;))
8333 
8334     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8335       {
8336         bool b1 = EISgetBitRWNR(&e->ADDR1, true);
8337 
8338         e->ADDR2.mode = eRWreadBit;
8339         bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8340 
8341         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8342 
8343         if (bR)
8344           cpu.du.Z = 0;
8345 
8346         // write out modified bit
8347         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8348         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8349         // if ADDR1 is on a word boundary, it might fault on the next loop,
8350         // so we flush the write in case.
8351         EISgetBitRWNR(&e->ADDR2, e->ADDR1.last_bit_posn == 0);
8352       }
8353 
8354     if (e->N1 < e->N2)
8355       {
8356         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8357           {
8358             bool b1 = F;
8359 
8360             e->ADDR2.mode = eRWreadBit;
8361             bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8362 
8363             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8364 
8365             if (bR)
8366               {
8367                 //CLR_I_ZERO;
8368                 cpu.du.Z = 0;
8369               }
8370 
8371             // write out modified bit
8372             e->ADDR2.bit = bR ? 1 : 0;
8373             e->ADDR2.mode = eRWwriteBit;
8374             // if ADDR1 is on a word boundary, it might fault on the next loop,
8375             // so we flush the write in case.
8376             EISgetBitRWNR(&e->ADDR2, e->ADDR1.last_bit_posn == 0);
8377           }
8378       }
8379 
8380     EISWriteCache (&e->ADDR2);
8381 
8382     cleanupOperandDescriptor (1);
8383     cleanupOperandDescriptor (2);
8384 
8385     SC_I_ZERO (cpu.du.Z);
8386     if (e->N1 > e->N2)
8387       {
8388         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8389         // processed and the truncation indicator is set ON.
8390         //
8391         // If T = 1 and the truncation indicator is set ON by execution of the
8392         // instruction, then a truncation (overflow) fault occurs.
8393 
8394         SET_I_TRUNC;
8395         if (T && tstOVFfault ())
8396           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8397       }
8398     else
8399       {
8400         CLR_I_TRUNC;
8401       }
8402   }
8403 
8404 void sztl (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8405   {
8406 
8407     // The execution of this instruction is identical to the Combine
8408     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8409     // not placed into C(Y-bit2)i-1.
8410 
8411     EISstruct * e = & cpu.currentEISinstruction;
8412 
8413     // For i = bits 1, 2, ..., minimum (N1,N2)
8414     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
8415     //   C(BOLR)m → C(Y-bit2)i-1
8416     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
8417     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
8418     //   C(BOLR)m → C(Y-bit2)i-1
8419     //
8420     // INDICATORS: (Indicators not listed are not affected)
8421     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8422     //     Truncation If N1 > N2, then ON; otherwise OFF
8423     //
8424     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8425     // processed and the truncation indicator is set ON.
8426     //
8427     // If T = 1 and the truncation indicator is set ON by execution of the
8428     // instruction, then a truncation (overflow) fault occurs.
8429     //
8430     // BOLR
8431     // If first operand    and    second operand    then result
8432     // bit is:                    bit is:           is from bit:
8433     //        0                          0                      5
8434     //        0                          1                      6
8435     //        1                          0                      7
8436     //        1                          1                      8
8437     //
8438     // The Boolean operations most commonly used are
8439     //                  BOLR Field Bits
8440     // Operation        5      6      7      8
8441     //
8442     // MOVE             0      0      1      1
8443     // AND              0      0      0      1
8444     // OR               0      1      1      1
8445     // NAND             1      1      1      0
8446     // EXCLUSIVE OR     0      1      1      0
8447     // Clear            0      0      0      0
8448     // Invert           1      1      0      0
8449     //
8450 
8451 // 0 0 0 0  Clear
8452 // 0 0 0 1  a AND b
8453 // 0 0 1 0  a AND !b
8454 // 0 0 1 1  a
8455 // 0 1 0 0  !a AND b
8456 // 0 1 0 1  b
8457 // 0 1 1 0  a XOR b
8458 // 0 1 1 1  a OR b
8459 // 1 0 0 0  !a AND !b     !(a OR b)
8460 // 1 0 0 1  a == b        !(a XOR b)
8461 // 1 0 1 0  !b
8462 // 1 0 1 1  !b OR A
8463 // 1 1 0 0  !a
8464 // 1 1 0 1  !b AND a
8465 // 1 1 1 0  a NAND b
8466 // 1 1 1 1  Set
8467 
8468     fault_ipr_subtype_ mod_fault = 0;
8469 
8470 #ifndef EIS_SETUP
8471     setupOperandDescriptor (1, &mod_fault);
8472     setupOperandDescriptor (2, &mod_fault);
8473 #endif
8474 
8475     parseBitstringOperandDescriptor (1, &mod_fault);
8476     parseBitstringOperandDescriptor (2, &mod_fault);
8477 
8478     L68_ (
8479       // L68 raises it immediately
8480       if (mod_fault)
8481           doFault (FAULT_IPR,
8482                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8483                    "Illegal modifier");
8484     )
8485 
8486     // Bits 1-4 and 10 MBZ
8487     if (IWB_IRODD & 0360200000000)
8488       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8489 
8490     DPS8M_ (
8491       // DPS8M raises it delayed
8492       if (mod_fault)
8493           doFault (FAULT_IPR,
8494                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8495                    "Illegal modifier");
8496     )
8497 
8498     e->ADDR1.cPos = (int) e->C1;
8499     e->ADDR2.cPos = (int) e->C2;
8500 
8501     e->ADDR1.bPos = (int) e->B1;
8502     e->ADDR2.bPos = (int) e->B2;
8503 
8504     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8505     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8506 
8507     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8508     bool B5 = !! (BOLR & 8);
8509     bool B6 = !! (BOLR & 4);
8510     bool B7 = !! (BOLR & 2);
8511     bool B8 = !! (BOLR & 1);
8512 
8513     e->ADDR1.mode = eRWreadBit;
8514     e->ADDR2.mode = eRWreadBit;
8515 
8516 #ifndef EIS_PTR
8517     sim_debug (DBG_TRACEEXT, & cpu_dev,
8518                "SZTL N1 %d N2 %d\n"
8519                "SZTL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8520                "SZTL BOLR %u%u%u%u\n"
8521                "SZTL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8522                "SZTL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8523                e -> N1, e -> N2,
8524                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8525                B5, B6, B7, B8,
8526                e -> addr [0].SNR, e -> addr [0].address,
8527                e -> addr [0].cPos, e -> addr [0].bPos,
8528                e -> addr [1].SNR, e -> addr [1].address,
8529                e -> addr [1].cPos, e -> addr [1].bPos);
8530 #endif
8531 
8532     bool bR = false; // result bit
8533 
8534     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8535                  DU_CYCLE_FLEN_128;))
8536 
8537     for( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY += 1)
8538     {
8539         bool b1 = EISgetBitRWN (& e->ADDR1, true);
8540         bool b2 = EISgetBitRWN (& e->ADDR2, true);
8541 
8542         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8543 
8544         if (bR)
8545           {
8546             //CLR_I_ZERO);
8547             cpu.du.Z = 0;
8548             break;
8549           }
8550       }
8551 
8552     if (e->N1 < e->N2)
8553       {
8554         for (; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8555           {
8556             bool b1 = F;
8557             bool b2 = EISgetBitRWN (& e->ADDR2, true);
8558 
8559             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8560 
8561             if (bR)
8562               {
8563                 //CLR_I_ZERO;
8564                 cpu.du.Z = 0;
8565                 break;
8566               }
8567           }
8568       }
8569 
8570     cleanupOperandDescriptor (1);
8571     cleanupOperandDescriptor (2);
8572 
8573     SC_I_ZERO (cpu.du.Z);
8574     if (e->N1 > e->N2)
8575       {
8576         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8577         // processed and the truncation indicator is set ON.
8578         //
8579         // If T = 1 and the truncation indicator is set ON by execution of the
8580         // instruction, then a truncation (overflow) fault occurs.
8581 
8582         SET_I_TRUNC;
8583         if (T && tstOVFfault ())
8584           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8585       }
8586     else
8587       {
8588         CLR_I_TRUNC;
8589       }
8590   }
8591 
8592 void sztr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8593   {
8594 
8595     // The execution of this instruction is identical to the Combine
8596     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8597     // not placed into C(Y-bit2)i-1.
8598 
8599     EISstruct * e = & cpu.currentEISinstruction;
8600 
8601     // For i = bits 1, 2, ..., minimum (N1,N2)
8602     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8603     //   C(BOLR)m → C( Y-bit2)N2-i
8604     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8605     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8606     //    C(BOLR)m → C( Y-bit2)N2-i
8607     // INDICATORS: (Indicators not listed are not affected)
8608     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8609     //     Truncation If N1 > N2, then ON; otherwise OFF
8610     //
8611     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8612     // processed and the truncation indicator is set ON.
8613     //
8614     // If T = 1 and the truncation indicator is set ON by execution of the
8615     // instruction, then a truncation (overflow) fault occurs.
8616     //
8617     // BOLR
8618     // If first operand    and    second operand    then result
8619     // bit is:                    bit is:           is from bit:
8620     //        0                          0                      5
8621     //        0                          1                      6
8622     //        1                          0                      7
8623     //        1                          1                      8
8624     //
8625     // The Boolean operations most commonly used are
8626     //                  BOLR Field Bits
8627     // Operation        5      6      7      8
8628     //
8629     // MOVE             0      0      1      1
8630     // AND              0      0      0      1
8631     // OR               0      1      1      1
8632     // NAND             1      1      1      0
8633     // EXCLUSIVE OR     0      1      1      0
8634     // Clear            0      0      0      0
8635     // Invert           1      1      0      0
8636     //
8637 
8638     fault_ipr_subtype_ mod_fault = 0;
8639 
8640 #ifndef EIS_SETUP
8641     setupOperandDescriptor(1, &mod_fault);
8642     setupOperandDescriptor(2, &mod_fault);
8643 #endif
8644 
8645     parseBitstringOperandDescriptor(1, &mod_fault);
8646     parseBitstringOperandDescriptor(2, &mod_fault);
8647 
8648     L68_ (
8649       // L68 raises it immediately
8650       if (mod_fault)
8651           doFault (FAULT_IPR,
8652                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8653                    "Illegal modifier");
8654     )
8655 
8656     // Bits 1-4 and 10 MBZ
8657     if (IWB_IRODD & 0360200000000)
8658       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8659 
8660     DPS8M_ (
8661       // DPS8M raises it delayed
8662       if (mod_fault)
8663           doFault (FAULT_IPR,
8664                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8665                    "Illegal modifier");
8666     )
8667 
8668     e->ADDR1.cPos = (int) e->C1;
8669     e->ADDR2.cPos = (int) e->C2;
8670 
8671     e->ADDR1.bPos = (int) e->B1;
8672     e->ADDR2.bPos = (int) e->B2;
8673 
8674     // get new char/bit offsets
8675     int numWords1=0, numWords2=0;
8676 
8677     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8678     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8679     PNL (cpu.du.D1_PTR_W &= AMASK);
8680 #ifdef EIS_PTR
8681     cpu.du.D1_PTR_W += (word18) numWords1;
8682     cpu.du.D1_PTR_W &= AMASK;
8683 #else
8684     e->ADDR1.address += (word18) numWords1;
8685 #endif
8686 
8687     sim_debug (DBG_TRACEEXT, & cpu_dev,
8688                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8689                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8690     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8691     sim_debug (DBG_TRACEEXT, & cpu_dev,
8692                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8693                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8694     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8695     PNL (cpu.du.D2_PTR_W &= AMASK);
8696 #ifdef EIS_PTR
8697     cpu.du.D2_PTR_W += (word18) numWords1;
8698     cpu.du.D2_PTR_W &= AMASK;
8699 #else
8700     e->ADDR2.address += (word18) numWords2;
8701 #endif
8702 
8703     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8704     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8705 
8706     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8707     bool B5 = !! (BOLR & 8);
8708     bool B6 = !! (BOLR & 4);
8709     bool B7 = !! (BOLR & 2);
8710     bool B8 = !! (BOLR & 1);
8711 
8712     e->ADDR1.mode = eRWreadBit;
8713 
8714     CLR_I_TRUNC;     // assume N1 <= N2
8715 
8716     bool bR = false; // result bit
8717 
8718     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8719                  DU_CYCLE_FLEN_128;))
8720 
8721     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8722       {
8723         bool b1 = EISgetBitRWNR(&e->ADDR1, true);
8724 
8725         e->ADDR2.mode = eRWreadBit;
8726         bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8727 
8728         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8729 
8730         if (bR)
8731           {
8732             cpu.du.Z = 0;
8733             break;
8734           }
8735 
8736       }
8737 
8738     if (e->N1 < e->N2)
8739       {
8740         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8741           {
8742             bool b1 = F;
8743 
8744             e->ADDR2.mode = eRWreadBit;
8745             bool b2 = EISgetBitRWNR(&e->ADDR2, true);
8746 
8747             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8748 
8749             if (bR)
8750             {
8751                 //CLR_I_ZERO;
8752                 cpu.du.Z = 0;
8753                 break;
8754             }
8755 
8756           }
8757       }
8758 
8759     cleanupOperandDescriptor (1);
8760     cleanupOperandDescriptor (2);
8761 
8762     SC_I_ZERO (cpu.du.Z);
8763     if (e->N1 > e->N2)
8764       {
8765         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8766         // processed and the truncation indicator is set ON.
8767         //
8768         // If T = 1 and the truncation indicator is set ON by execution of the
8769         // instruction, then a truncation (overflow) fault occurs.
8770 
8771         SET_I_TRUNC;
8772         if (T && tstOVFfault ())
8773           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8774       }
8775     else
8776       {
8777         CLR_I_TRUNC;
8778       }
8779   }
8780 
8781 /*
8782  * CMPB - Compare Bit Strings
8783  */
8784 
8785 /*
8786  * get a bit from memory ....
8787  */
8788 // XXX this is terribly inefficient, but it'll do for now ......
8789 
8790 static bool EISgetBit(EISaddr *p, int *cpos, int *bpos)
     /* [previous][next][first][last][top][bottom][index][help] */
8791 {
8792 #ifdef EIS_PTR
8793     long eisaddr_idx = EISADDR_IDX (p);
8794 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8795 #endif
8796 
8797     if (!p)
8798     {
8799         //lastAddress = -1;
8800         return 0;
8801     }
8802 
8803     if (*bpos > 8)      // bits 0-8
8804     {
8805         *bpos = 0;
8806         *cpos += 1;
8807         if (*cpos > 3)  // chars 0-3
8808         {
8809             *cpos = 0;
8810 #ifdef EIS_PTR
8811             cpu.du.Dk_PTR_W[eisaddr_idx] += 1;
8812             cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8813 #else
8814             p->address += 1;
8815             p->address &= AMASK;
8816 #endif
8817         }
8818     }
8819 
8820     p->data = EISRead(p); // read data word from memory
8821 
8822     int charPosn = *cpos * 9;
8823     int bitPosn = charPosn + *bpos;
8824     bool b = getbits36_1 (p->data, (uint) bitPosn) != 0;
8825 
8826     *bpos += 1;
8827 
8828     return b;
8829 }
8830 
8831 void cmpb (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8832 {
8833     EISstruct * e = & cpu.currentEISinstruction;
8834 
8835     // For i = 1, 2, ..., minimum (N1,N2)
8836     //   C(Y-bit1)i-1 :: C(Y-bit2)i-1
8837     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
8838     //   C(FILL) :: C(Y-bit2)i-1
8839     // If N1 > N2, then for i = N2+l, N2+2, ..., N1
8840     //   C(Y-bit1)i-1 :: C(FILL)
8841     //
8842     // Indicators:
8843     //    Zero:  If C(Y-bit1)i = C(Y-bit2)i for all i, then ON; otherwise, OFF
8844     //    Carry: If C(Y-bit1)i < C(Y-bit2)i for any i, then OFF; otherwise ON
8845 
8846     fault_ipr_subtype_ mod_fault = 0;
8847 
8848 #ifndef EIS_SETUP
8849     setupOperandDescriptor(1, &mod_fault);
8850     setupOperandDescriptor(2, &mod_fault);
8851 #endif
8852 
8853     parseBitstringOperandDescriptor(1, &mod_fault);
8854     parseBitstringOperandDescriptor(2, &mod_fault);
8855 
8856     L68_ (
8857       // L68 raises it immediately
8858       if (mod_fault)
8859         {
8860           doFault (FAULT_IPR,
8861                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8862                    "Illegal modifier");
8863         }
8864     )
8865 
8866     // Bits 1-8 and 10 MBZ
8867     if (IWB_IRODD & 0377200000000)
8868       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpb 1-8,10 MBZ");
8869 
8870     DPS8M_ (
8871       // DPS8M raises it delayed
8872       if (mod_fault)
8873         {
8874           doFault (FAULT_IPR,
8875                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8876                    "Illegal modifier");
8877         }
8878     )
8879 
8880     int charPosn1 = (int) e->C1;
8881     int charPosn2 = (int) e->C2;
8882 
8883     int bitPosn1 = (int) e->B1;
8884     int bitPosn2 = (int) e->B2;
8885 
8886     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8887 
8888     SET_I_ZERO;  // assume all =
8889     SET_I_CARRY; // assume all >=
8890 
8891 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb N1 %d N2 %d\n", e -> N1, e -> N2);
8892 
8893 
8894 
8895 
8896 
8897 
8898 
8899 
8900 
8901 
8902 
8903 
8904 
8905 
8906 
8907 
8908 
8909     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8910       DU_CYCLE_FLEN_128;))
8911 
8912     uint i;
8913     for(i = 0 ; i < min(e->N1, e->N2) ; i += 1)
8914     {
8915         bool b1 = EISgetBit (&e->ADDR1, &charPosn1, &bitPosn1);
8916         bool b2 = EISgetBit (&e->ADDR2, &charPosn2, &bitPosn2);
8917 
8918 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(min(e->N1, e->N2)) i %d b1 %d b2 %d\n", i, b1, b2);
8919         if (b1 != b2)
8920         {
8921             CLR_I_ZERO;
8922             if (!b1 && b2)  // 0 < 1
8923                 CLR_I_CARRY;
8924 
8925             cleanupOperandDescriptor (1);
8926             cleanupOperandDescriptor (2);
8927 
8928             return;
8929         }
8930 
8931     }
8932     if (e->N1 < e->N2)
8933     {
8934         for(; i < e->N2 ; i += 1)
8935         {
8936             bool b1 = F;
8937             bool b2 = EISgetBit(&e->ADDR2, &charPosn2, &bitPosn2);
8938 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 < e->N2) i %d b1fill %d b2 %d\n", i, b1, b2);
8939 
8940             if (b1 != b2)
8941             {
8942                 CLR_I_ZERO;
8943                 if (!b1 && b2)  // 0 < 1
8944                     CLR_I_CARRY;
8945 
8946                 cleanupOperandDescriptor (1);
8947                 cleanupOperandDescriptor (2);
8948 
8949                 return;
8950             }
8951         }
8952     } else if (e->N1 > e->N2)
8953     {
8954         for(; i < e->N1 ; i += 1)
8955         {
8956             bool b1 = EISgetBit(&e->ADDR1, &charPosn1, &bitPosn1);
8957             bool b2 = F;
8958 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 > e->N2) i %d b1 %d b2fill %d\n", i, b1, b2);
8959 
8960             if (b1 != b2)
8961             {
8962                 CLR_I_ZERO;
8963                 if (!b1 && b2)  // 0 < 1
8964                     CLR_I_CARRY;
8965 
8966                 cleanupOperandDescriptor (1);
8967                 cleanupOperandDescriptor (2);
8968 
8969                 return;
8970             }
8971         }
8972     }
8973     cleanupOperandDescriptor (1);
8974     cleanupOperandDescriptor (2);
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 /*
9199  * determine sign of N*9-bit length word
9200  */
9201 static bool sign9n(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9202 {
9203 
9204     // sign bit of  9-bit is bit 8  (1 << 8)
9205     // sign bit of 18-bit is bit 17 (1 << 17)
9206     // .
9207     // .
9208     // .
9209     // sign bit of 72-bit is bit 71 (1 << 71)
9210 
9211     if (N < 1 || N > 8) // XXX largest int we'll play with is 72-bits? Makes sense
9212         return false;
9213 
9214 #ifdef NEED_128
9215     word72 sgnmask = lshift_128 (construct_128 (0, 1), (uint) (N * 9 - 1));
9216     return isnonzero_128 (and_128 (sgnmask, n128));
9217 #else
9218     word72 sgnmask = (word72)1 << ((N * 9) - 1);
9219 
9220     return (bool)(sgnmask & n128);
9221 #endif
9222 }
9223 
9224 /*
9225  * sign extend a N*9 length word to a (word72) 128-bit word
9226  */
9227 static word72s signExt9(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9228 {
9229     // ext mask for  9-bit = 037777777777777777777777777777777777777400  8 0's
9230     // ext mask for 18-bit = 037777777777777777777777777777777777400000 17 0's
9231     // ext mask for 36-bit = 037777777777777777777777777777400000000000 35 0's
9232     // etc...
9233 
9234     int bits = (N * 9) - 1;
9235     if (sign9n(n128, N))
9236     {
9237 #ifdef NEED_128
9238         uint128 extBits = lshift_128 (construct_128 (MASK64, MASK64), (uint) bits);
9239         uint128 or = or_128 (n128, extBits);
9240         return cast_s128 (or);
9241 #else
9242         uint128 extBits = ((uint128)-1 << bits);
9243         return (word72s) (n128 | extBits);
9244 #endif
9245     }
9246 #ifdef NEED_128
9247     uint128 zeroBits = complement_128 (lshift_128 (construct_128 (MASK64, MASK64), (uint) bits));
9248     uint128 and = and_128 (n128, zeroBits);
9249     return cast_s128 (and);
9250 #else
9251     uint128 zeroBits = ~((uint128)-1 << bits);
9252     return (word72s) (n128 & zeroBits);
9253 #endif
9254 }
9255 
9256 /*
9257  * load a 9*n bit integer into e->x ...
9258  */
9259 
9260 static void load9x(int n, EISaddr *addr, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
9261 {
9262     EISstruct * e = & cpu.currentEISinstruction;
9263 #ifdef NEED_128
9264     word72 x = construct_128 (0, 0);
9265 #else
9266     word72 x = 0;
9267 #endif
9268 #ifdef EIS_PTR
9269     long eisaddr_idx = EISADDR_IDX (addr);
9270 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
9271 #endif
9272 
9273     word36 data = EISRead(addr);
9274 
9275     int m = n;
9276     while (m)
9277     {
9278 #ifdef NEED_128
9279         x = lshift_128 (x, 9);
9280 #else
9281         x <<= 9;         // make room for next 9-bit byte
9282 #endif
9283 
9284         if (pos > 3)        // overflows to next word?
9285         {   // yep....
9286             pos = 0;        // reset to 1st byte
9287 #if EIS_PTR
9288             cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;          // bump source to next address
9289 #else
9290             addr->address = (addr->address + 1) & AMASK;          // bump source to next address
9291 #endif
9292             data = EISRead(addr);    // read it from memory
9293         }
9294 
9295 #ifdef NEED_128
9296         x = or_128 (x, construct_128 (0, GETBYTE (data, pos)));
9297 #else
9298         x |= GETBYTE(data, pos);   // fetch byte at position pos and 'or' it in
9299 #endif
9300 
9301         pos += 1;           // onto next position
9302 
9303         m -= 1;             // decrement byte counter
9304     }
9305     e->x = signExt9(x, n);  // form proper 2's-complement integer
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 
9428 void btd (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9429 {
9430     EISstruct * e = & cpu.currentEISinstruction;
9431 
9432     // C(Y-char91) converted to decimal → C(Y-charn2)
9433     /*!
9434      * C(Y-char91) contains a twos complement binary integer aligned on 9-bit
9435      * character boundaries with length 0 < N1 <= 8.
9436      *
9437      * If TN2 and S2 specify a 4-bit signed number and P = 1, then if
9438      * C(Y-char91) is positive (bit 0 of C(Y-char91)0 = 0), then the 13(8) plus
9439      * sign character is moved to C(Y-charn2) as appropriate.
9440      *
9441      *   The scaling factor of C(Y-charn2), SF2, must be 0.
9442      *
9443      *   If N2 is not large enough to hold the digits generated by conversion
9444      *   of C(Y-char91) an overflow condition exists; the overflow indicator is
9445      *   set ON and an overflow fault occurs. This implies that an unsigned
9446      *   fixed-point receiving field has a minimum length of 1 character and a
9447      *   signed fixed- point field, 2 characters.
9448      *
9449      * If MFk.RL = 1, then Nk does not contain the operand length; instead; it
9450      * contains a register code for a register holding the operand length.
9451      *
9452      * If MFk.ID = 1, then the kth word following the instruction word does not
9453      * contain an operand descriptor; instead, it contains an indirect pointer
9454      * to the operand descriptor.
9455      *
9456      * C(Y-char91) and C(Y-charn2) may be overlapping strings; no check is made.
9457      *
9458      * Attempted conversion to a floating-point number (S2 = 0) or attempted
9459      * use of a scaling factor (SF2 ≠ 0) causes an illegal procedure fault.
9460      *
9461      * If N1 = 0 or N1 > 8 an illegal procedure fault occurs.
9462      *
9463      * Attempted execution with the xed instruction causes an illegal procedure fault.
9464      *
9465      * Attempted repetition with the rpt, rpd, or rpl instructions causes an illegal procedure fault.
9466      *
9467      */
9468 
9469     // C(string 1) -> C(string 2) (converted)
9470 
9471     // The two's complement binary integer starting at location YC1 is
9472     // converted into a signed string of decimal characters of data type TN2,
9473     // sign and decimal type S2 (S2 = 00 is illegal) and scale factor 0; and is
9474     // stored, right-justified, as a string of length L2 starting at location
9475     // YC2. If the string generated is longer than L2, the high-order excess is
9476     // truncated and the overflow indicator is set. If strings 1 and 2 are not
9477     // overlapped, the contents of string 1 remain unchanged. The length of
9478     // string 1 (L1) is given as the number of 9-bit segments that make up the
9479     // string. L1 is equal to or is less than 8. Thus, the binary string to be
9480     // converted can be 9, 18, 27, 36, 45, 54, 63, or 72 bits long. CN1
9481     // designates a 9-bit character boundary. If P=1, positive signed 4-bit
9482     // results are stored using octal 13 as the plus sign. If P=0, positive
9483     // signed 4-bit results are stored with octal 14 as the plus sign.
9484 
9485     fault_ipr_subtype_ mod_fault = 0;
9486 
9487 #ifndef EIS_SETUP
9488     setupOperandDescriptor(1, &mod_fault);
9489     setupOperandDescriptor(2, &mod_fault);
9490 #endif
9491 
9492     parseNumericOperandDescriptor(1, &mod_fault);
9493     parseNumericOperandDescriptor(2, &mod_fault);
9494 
9495     L68_ (
9496       // L68 raises it immediately
9497       if (mod_fault)
9498         {
9499           doFault (FAULT_IPR,
9500                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9501                    "Illegal modifier");
9502         }
9503     )
9504 
9505     // Bits 1-10 MBZ
9506     if (IWB_IRODD & 0377600000000)
9507       {
9508         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
9509         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "btd 0-8 MBZ");
9510       }
9511 
9512     // Bits 21-29 of OP1 MBZ
9513     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000077700)
9514       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op1 21-29 MBZ");
9515 
9516     // Bits 24-29 of OP2 MBZ
9517     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000007700)
9518       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 24-29 MBZ");
9519 
9520     if (e->S[1] == 0)
9521       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 S=0");
9522 
9523     DPS8M_ (
9524       // DPS8 raises it delayed
9525       if (mod_fault)
9526         {
9527           doFault (FAULT_IPR,
9528                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9529                    "Illegal modifier");
9530         }
9531     )
9532 
9533     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
9534 
9535     if (e->N1 == 0 || e->N1 > 8)
9536         doFault(FAULT_IPR, fst_ill_proc, "btd(1): N1 == 0 || N1 > 8");
9537 
9538     uint dstTN = e->TN2;    // type of chars in dst
9539     uint dstCN = e->CN2;    // starting at char pos CN
9540 
9541     int n2 = 0;
9542 
9543     switch(e->S2)
9544     {
9545         case CSLS:
9546         case CSTS:
9547             n2 = (int) e->N2 - 1; // 1 sign
9548             break;
9549 
9550         case CSNS:
9551             n2 = (int) e->N2;     // no sign
9552             break;          // no sign wysiwyg
9553     }
9554 
9555     sim_debug (DBG_CAC, & cpu_dev,
9556       "n2 %d\n",
9557       n2);
9558 
9559     if (n2 < 1)
9560         doFault (FAULT_IPR, fst_ill_proc, "btd adjusted n2<1");
9561 
9562     decContext set;
9563     decContextDefaultDPS8(&set);
9564     set.traps=0;
9565 
9566     load9x((int) e->N1, &e->ADDR1, (int) e->CN1);
9567 
9568     // handle sign
9569     e->sign = 1;
9570 #ifdef NEED_128
9571     word72 x = cast_128 (e->x);
9572     if (islt_s128 (e->x, construct_s128 (0, 0)))
9573       {
9574         e->sign = -1;
9575         x = and_128 (negate_128 (x), MASK72);
9576 
9577       }
9578 
9579     // convert to decimal string, workaround missing sprintf uint128
9580     char tmp[32];
9581     tmp[31] = 0;
9582     int i;
9583     for (i=30;i>=0;i--) {
9584         //tmp[i] = x%10 + '0';
9585         //x /= 10;
9586         uint16_t r;
9587         x = divide_128_16 (x, 10, & r);
9588         tmp[i] = (char) r + '0';
9589         if (iszero_128 (x))
9590             break;
9591     }
9592 #else
9593     word72 x = (word72)e->x;
9594     if (e->x < 0) {
9595         e->sign = -1;
9596         //x = (-x) & MASK72;
9597         // ubsan
9598         x = ((word72) (- (word72s) x)) & MASK72;
9599     }
9600 
9601     // convert to decimal string, workaround missing sprintf uint128
9602     char tmp[32];
9603     tmp[31] = 0;
9604     int i;
9605     for (i=30;i>=0;i--) {
9606         tmp[i] = x%10 + '0';
9607         x /= 10;
9608         if (x == 0)
9609             break;
9610     }
9611 #endif
9612 
9613     decNumber _1;
9614     decNumber *op1 = decNumberFromString(&_1, tmp+i, &set);
9615     if (e->sign == -1)
9616         op1->bits |= DECNEG;
9617 
9618     bool Ovr = false, Trunc = false;
9619 
9620     uint8_t out [256];
9621     char * res = formatDecimal (out, &set, op1, n2, (int) e->S2, e->SF2, 0, &Ovr, &Trunc);
9622 
9623     // now write to memory in proper format.....
9624 
9625     //word18 dstAddr = e->dstAddr;
9626     int pos = (int) dstCN;
9627 
9628     // 1st, take care of any leading sign .......
9629     switch(e->S2)
9630     {
9631         case CSLS:  // fixed-point, leading sign
9632             switch(dstTN)
9633             {
9634                 case CTN4:
9635                     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.
9636                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 013);  // special +
9637                     else
9638                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 014);  // default +
9639                     break;
9640                 case CTN9:
9641                     EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9642                     break;
9643             }
9644             break;
9645 
9646         case CSTS:  // nuttin' to do here .....
9647         case CSNS:
9648             break;  // no sign wysiwyg
9649     }
9650 
9651     // 2nd, write the digits .....
9652     for(int i = 0 ; i < n2 ; i++)
9653         switch(dstTN)
9654         {
9655             case CTN4:
9656                 EISwrite49(&e->ADDR2, &pos, (int) dstTN, (word9) (res[i] - '0'));
9657                 break;
9658             case CTN9:
9659                 EISwrite49(&e->ADDR2, &pos, (int) dstTN, (word9) res[i]);
9660                 break;
9661         }
9662 
9663     // 3rd, take care of any trailing sign or exponent ...
9664     switch(e->S2)
9665     {
9666         case CSTS:  // write trailing sign ....
9667             switch(dstTN)
9668             {
9669                 case CTN4:
9670                     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.
9671                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  013);  // special +
9672                     else
9673                         EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  014);  // default +
9674                     break;
9675 
9676                 case CTN9:
9677                     EISwrite49(&e->ADDR2, &pos, (int) dstTN, (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9678                     break;
9679             }
9680             break;
9681 
9682         case CSLS:  // fixed point, leading sign - already done
9683         case CSNS:  // fixed point, unsigned - nuttin' needed to do
9684             break;
9685     }
9686 
9687     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));  // set negative indicator if op3 < 0
9688     SC_I_ZERO (decNumberIsZero(op1));     // set zero indicator if op3 == 0
9689 
9690     cleanupOperandDescriptor (1);
9691     cleanupOperandDescriptor (2);
9692 
9693     if (Ovr)
9694     {
9695         SET_I_OFLOW;
9696         if (tstOVFfault ())
9697           doFault(FAULT_OFL, fst_zero, "btd overflow fault");
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 
9907 void dtb (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9908 {
9909     EISstruct * e = & cpu.currentEISinstruction;
9910 
9911     fault_ipr_subtype_ mod_fault = 0;
9912 
9913 #ifndef EIS_SETUP
9914     setupOperandDescriptor(1, &mod_fault);
9915     setupOperandDescriptor(2, &mod_fault);
9916 #endif
9917 
9918     PNL (L68_ (DU_CYCLE_DGDB;))
9919 
9920     parseNumericOperandDescriptor(1, &mod_fault);
9921     parseNumericOperandDescriptor(2, &mod_fault);
9922 
9923     L68_ (
9924       // L68 raises it immediately
9925       if (mod_fault)
9926         {
9927           doFault (FAULT_IPR,
9928                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9929                    "Illegal modifier");
9930         }
9931     )
9932 
9933     // Bits 0 to 10 of the instruction Must Be Zero. So Say We ISOLTS.
9934     uint mbz = (uint) getbits36 (IWB_IRODD, 0, 11);
9935     if (mbz)
9936       {
9937         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dtb(): 0-10 MBZ");
9938       }
9939 
9940     // Bits 24-29 of OP1 MBZ
9941     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
9942       {
9943         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op1 24-29 MBZ");
9944       }
9945 
9946     // Bits 21-29 of OP2 MBZ
9947     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000077700)
9948       {
9949         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op2 21-29 MBZ");
9950        }
9951 
9952     // Attempted conversion of a floating-point number (S1 = 0) or attempted
9953     // use of a scaling factor (SF1 ≠ 0) causes an illegal procedure fault.
9954     if (e->S1 == 0 || e->SF1 != 0)
9955     {
9956         doFault(FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb():  S1=0 or SF1!=0");
9957     }
9958 
9959     DPS8M_ (
9960       // DPS8M raises it delayed
9961       if (mod_fault)
9962         {
9963           doFault (FAULT_IPR,
9964                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9965                    "Illegal modifier");
9966         }
9967     )
9968 
9969     // If N2 = 0 or N2 > 8 an illegal procedure fault occurs.
9970     if (e->N2 == 0 || e->N2 > 8)
9971     {
9972         doFault(FAULT_IPR, fst_ill_proc, "dtb():  N2 = 0 or N2 > 8 etc.");
9973     }
9974 
9975     int n1 = 0;
9976 
9977     /*
9978      * Here we need to distinguish between 4 type of numbers.
9979      *
9980      * CSFL - Floating-point, leading sign
9981      * CSLS - Scaled fixed-point, leading sign
9982      * CSTS - Scaled fixed-point, trailing sign
9983      * CSNS - Scaled fixed-point, unsigned
9984      */
9985 
9986     // determine precision
9987     switch(e->S1)
9988     {
9989         case CSLS:
9990         case CSTS:
9991             n1 = (int) e->N1 - 1; // only 1 sign
9992             break;
9993 
9994         case CSNS:
9995             n1 = (int) e->N1;     // no sign
9996             break;  // no sign wysiwyg
9997     }
9998     // RJ78: An Illegal Procedure fault occurs if:
9999     // N1 is not large enough to specify the number of characters required for the
10000     // specified sign and/or exponent, plus at least one digit.
10001 
10002     if (n1 < 1)
10003         doFault (FAULT_IPR, fst_ill_proc, "dtb adjusted n1<1");
10004 
10005     EISloadInputBufferNumeric (1);   // according to MF1
10006 
10007     // prepare output mask
10008 #ifdef NEED_128
10009     word72 msk = subtract_128 (lshift_128 (construct_128 (0, 1), (9*e->N2-1)),construct_128 (0, 1));
10010 #else
10011     word72 msk = ((word72)1<<(9*e->N2-1))-1; // excluding sign
10012 #endif
10013 
10014 
10015 
10016 
10017 
10018 
10019 
10020 
10021 
10022 
10023 
10024 
10025 
10026     // input is unscaled fixed point, so just get the digits
10027     bool Ovr = false;
10028 #ifdef NEED_128
10029     word72 x = construct_128 (0, 0);
10030     for (int i = 0; i < n1; i++) {
10031         //x *= 10;
10032         x = multiply_128 (x, construct_128 (0, 10));
10033         //x += e->inBuffer[i];
10034         x = add_128 (x, construct_128 (0, (uint) e->inBuffer[i]));
10035         //Ovr |= x>msk?1:0;
10036         Ovr |= isgt_128 (x, msk) ? 1 : 0;
10037         //x &= msk; // multiplication and addition mod msk+1
10038         x = and_128 (x, msk); // multiplication and addition mod msk+1
10039     }
10040     if (e->sign == -1)
10041         //x = -x; // no need to mask it
10042         x = negate_128 (x); // no need to mask it
10043 
10044 #else
10045     word72 x = 0;
10046     for (int i = 0; i < n1; i++) {
10047         x *= 10;
10048         x += e->inBuffer[i];
10049         //sim_printf("%d %012"PRIo64" %012"PRIo64"\n",e->inBuffer[i],(word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10050         Ovr |= x>msk?1:0;
10051         x &= msk; // multiplication and addition mod msk+1
10052     }
10053     if (e->sign == -1)
10054         //x = -x; // no need to mask it
10055         // ubsan
10056         x = (word72) (- (word72s) x); // no need to mask it
10057 
10058     //sim_printf ("dtb out %012"PRIo64" %012"PRIo64"\n", (word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10059 #endif
10060     int pos = (int)e->CN2;
10061 
10062     // now write to memory in proper format.....
10063 
10064     int shift = 9*((int)e->N2-1);
10065     for(int i = 0; i < (int)e->N2; i++) {
10066 #ifdef NEED_128
10067         EISwrite9(&e->ADDR2, &pos, (word9) rshift_128 (x, (uint) shift).l & 0777);
10068 #else
10069         EISwrite9(&e->ADDR2, &pos, (word9) (x >> shift )& 0777);
10070 #endif
10071         shift -= 9;
10072     }
10073 
10074     SC_I_NEG (e->sign == -1);  // set negative indicator
10075 #ifdef NEED_128
10076     SC_I_ZERO (iszero_128 (x)); // set zero indicator
10077 #else
10078     SC_I_ZERO (x==0);     // set zero indicator
10079 #endif
10080 
10081     cleanupOperandDescriptor (1);
10082     cleanupOperandDescriptor (2);
10083 
10084     if (Ovr)
10085     {
10086         SET_I_OFLOW;
10087         if (tstOVFfault ())
10088           doFault(FAULT_OFL, fst_zero, "dtb overflow fault");
10089     }
10090 }
10091 
10092 /*
10093  * decimal EIS instructions ...
10094  */
10095 
10096 #define ASC(x)  ((x) + '0')
10097 
10098 /*
10099  * ad2d - Add Using Two Decimal Operands
10100  */
10101 
10102 void ad2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
10103 {
10104     EISstruct * e = & cpu.currentEISinstruction;
10105 
10106     fault_ipr_subtype_ mod_fault = 0;
10107 
10108 #ifndef EIS_SETUP
10109     setupOperandDescriptor(1, &mod_fault);
10110     setupOperandDescriptor(2, &mod_fault);
10111     setupOperandDescriptorCache(3);
10112 #endif
10113 
10114     parseNumericOperandDescriptor(1, &mod_fault);
10115     parseNumericOperandDescriptor(2, &mod_fault);
10116 
10117     L68_ (
10118       // L68 raises it immediately
10119       if (mod_fault)
10120         {
10121           doFault (FAULT_IPR,
10122                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10123                    "Illegal modifier");
10124         }
10125     )
10126 
10127     // Bits 1-8 MBZ
10128     if (IWB_IRODD & 0377000000000)
10129       doFault (FAULT_IPR, fst_ill_op, "ad2d 1-8 MBZ");
10130 
10131     DPS8M_ (
10132       // DPS8M raises it delayed
10133       if (mod_fault)
10134         {
10135           doFault (FAULT_IPR,
10136                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10137                    "Illegal modifier");
10138         }
10139     )
10140 
10141     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10142     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10143     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10144 
10145     PNL (L68_ (if (R)
10146       DU_CYCLE_FRND;))
10147 
10148     uint srcTN = e->TN1;    // type of chars in src
10149 
10150     uint dstTN = e->TN2;    // type of chars in dst
10151     uint dstCN = e->CN2;    // starting at char pos CN
10152 
10153     e->ADDR3 = e->ADDR2;
10154 
10155     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10156 
10157     /*
10158      * Here we need to distinguish between 4 type of numbers.
10159      *
10160      * CSFL - Floating-point, leading sign
10161      * CSLS - Scaled fixed-point, leading sign
10162      * CSTS - Scaled fixed-point, trailing sign
10163      * CSNS - Scaled fixed-point, unsigned
10164      */
10165 
10166     // determine precision
10167     switch(e->S1)
10168     {
10169         case CSFL:
10170             n1 = (int) e->N1 - 1; // need to account for the - sign
10171             if (srcTN == CTN4)
10172                 n1 -= 2;    // 2 4-bit digits exponent
10173             else
10174                 n1 -= 1;    // 1 9-bit digit exponent
10175             sc1 = 0;        // no scaling factor
10176             break;
10177 
10178         case CSLS:
10179         case CSTS:
10180             n1 = (int) e->N1 - 1; // only 1 sign
10181             sc1 = -e->SF1;
10182             break;
10183 
10184         case CSNS:
10185             n1 = (int) e->N1;     // no sign
10186             sc1 = -e->SF1;
10187             break;  // no sign wysiwyg
10188     }
10189 
10190     if (n1 < 1)
10191         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n1<1");
10192 
10193     switch(e->S2)
10194     {
10195         case CSFL:
10196             n2 = (int) e->N2 - 1; // need to account for the sign
10197             if (e->TN2 == CTN4)
10198                 n2 -= 2;    // 2 4-bit digit exponent
10199             else
10200                 n2 -= 1;    // 1 9-bit digit exponent
10201             sc2 = 0;        // no scaling factor
10202             break;
10203 
10204         case CSLS:
10205         case CSTS:
10206             n2 = (int) e->N2 - 1; // 1 sign
10207             sc2 = -e->SF2;
10208             break;
10209 
10210         case CSNS:
10211             n2 = (int) e->N2;     // no sign
10212             sc2 = -e->SF2;
10213             break;  // no sign wysiwyg
10214     }
10215 
10216     if (n2 < 1)
10217         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n2<1");
10218 
10219     decContext set;
10220     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10221     decContextDefaultDPS8(&set);
10222 
10223     set.traps=0;
10224 
10225     decNumber _1, _2, _3;
10226 
10227     EISloadInputBufferNumeric (1);   // according to MF1
10228 
10229     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10230     if (e->sign == -1)
10231         op1->bits |= DECNEG;
10232     if (e->S1 == CSFL)
10233         op1->exponent = e->exponent;
10234 
10235     EISloadInputBufferNumeric (2);   // according to MF2
10236 
10237     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10238     if (e->sign == -1)
10239         op2->bits |= DECNEG;
10240     if (e->S2 == CSFL)
10241         op2->exponent = e->exponent;
10242 
10243     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10244 
10245     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
10246     bool iOvr = 0;
10247     if (op3->digits > 63) {
10248         uint8_t pr[256];
10249         // if sf<=0, trailing zeroes can't be shifted out
10250         // if sf> 0, (some of) trailing zeroes can be shifted out
10251         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10252 
10253         int ctz = 0;
10254         if (sf>0) {     // optimize: we don't care when sf>0
10255             decNumberGetBCD(op3,pr);
10256             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10257                  ctz ++;
10258         }
10259 
10260         if (op3->digits - min(max(sf,0),ctz) > 63) {
10261 
10262             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10263             int safe = set.digits;
10264             decNumber tmp;
10265 
10266             // discard MS digits
10267             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10268             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10269             decNumberPlus(&tmp, op3, &set);
10270             set.digits = safe;
10271 
10272             decNumberSubtract(op3, op3, &tmp, &set);
10273 
10274             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10275 
10276             decContextSetRounding(&set, safeR);
10277             iOvr = 1;
10278         }
10279     }
10280 
10281     bool Ovr = false, EOvr = false, Trunc = false;
10282 
10283     uint8_t out [256];
10284     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
10285 
10286     Ovr |= iOvr;
10287 
10288     if (decNumberIsZero(op3))
10289         op3->exponent = 127;
10290 
10291     //printf("%s\r\n", res);
10292 
10293     // now write to memory in proper format.....
10294 
10295     //word18 dstAddr = e->dstAddr;
10296     int pos = (int) dstCN;
10297 
10298     // 1st, take care of any leading sign .......
10299     switch(e->S2)
10300     {
10301         case CSFL:  // floating-point, leading sign.
10302         case CSLS:  // fixed-point, leading sign
10303             switch(dstTN)
10304             {
10305                 case CTN4:
10306                     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.
10307                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10308                     else
10309                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10310                     break;
10311                 case CTN9:
10312                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10313                     break;
10314             }
10315             break;
10316 
10317         case CSTS:  // nuttin' to do here .....
10318         case CSNS:
10319             break;  // no sign wysiwyg
10320     }
10321 
10322     // 2nd, write the digits .....
10323     for(int j = 0 ; j < n2 ; j++)
10324         switch(dstTN)
10325         {
10326             case CTN4:
10327                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[j] - '0'));
10328                 break;
10329             case CTN9:
10330                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[j]);
10331                 break;
10332         }
10333 
10334     // 3rd, take care of any trailing sign or exponent ...
10335     switch(e->S2)
10336     {
10337         case CSTS:  // write trailing sign ....
10338             switch(dstTN)
10339             {
10340                 case CTN4:
10341                     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.
10342                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10343                     else
10344                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10345                     break;
10346                 case CTN9:
10347                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10348                     break;
10349             }
10350             break;
10351 
10352         case CSFL:  // floating-point, leading sign.
10353             // write the exponent
10354             switch(dstTN)
10355             {
10356                 case CTN4:
10357                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10358                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10359                     break;
10360                 case CTN9:
10361                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10362                     break;
10363             }
10364             break;
10365 
10366         case CSLS:  // fixed point, leading sign - already done
10367         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10368             break;
10369     }
10370 
10371     // set flags, etc ...
10372     if (e->S2 == CSFL)
10373     {
10374         if (op3->exponent > 127)
10375         {
10376             SET_I_EOFL;
10377             EOvr = true;
10378         }
10379         if (op3->exponent < -128)
10380         {
10381             SET_I_EUFL;
10382             EOvr = true;
10383         }
10384     }
10385 
10386     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10387     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10388 
10389     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10390 
10391     cleanupOperandDescriptor (1);
10392     cleanupOperandDescriptor (2);
10393     cleanupOperandDescriptor (3);
10394 
10395     if (TST_I_TRUNC && T && tstOVFfault ())
10396       doFault(FAULT_OFL, fst_zero, "ad2d truncation(overflow) fault");
10397     if (EOvr && tstOVFfault ())
10398         doFault(FAULT_OFL, fst_zero, "ad2d over/underflow fault");
10399     if (Ovr)
10400     {
10401         SET_I_OFLOW;
10402         if (tstOVFfault ())
10403           doFault(FAULT_OFL, fst_zero, "ad2d overflow fault");
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 /*
10448  * ad3d - Add Using Three Decimal Operands
10449  */
10450 
10451 void ad3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
10452 {
10453     EISstruct * e = & cpu.currentEISinstruction;
10454 
10455     fault_ipr_subtype_ mod_fault = 0;
10456 
10457 #ifndef EIS_SETUP
10458     setupOperandDescriptor(1, &mod_fault);
10459     setupOperandDescriptor(2, &mod_fault);
10460     setupOperandDescriptor(3, &mod_fault);
10461 #endif
10462 
10463     parseNumericOperandDescriptor(1, &mod_fault);
10464     parseNumericOperandDescriptor(2, &mod_fault);
10465     parseNumericOperandDescriptor(3, &mod_fault);
10466 
10467     L68_ (
10468       // L68 raises it immediately
10469       if (mod_fault)
10470         {
10471           doFault (FAULT_IPR,
10472                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10473                    "Illegal modifier");
10474         }
10475     )
10476 
10477     // Bit 1 MBZ
10478     if (IWB_IRODD & 0200000000000)
10479       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "ad3d(): 1 MBZ");
10480 
10481     DPS8M_ (
10482       // DPS8M raises it delayed
10483       if (mod_fault)
10484         {
10485           doFault (FAULT_IPR,
10486                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10487                    "Illegal modifier");
10488         }
10489     )
10490 
10491     // initialize mop flags. Probably best done elsewhere.
10492     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10493     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10494     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10495 
10496     PNL (L68_ (if (R)
10497       DU_CYCLE_FRND;))
10498 
10499     uint srcTN = e->TN1;    // type of chars in src
10500 
10501     uint dstTN = e->TN3;    // type of chars in dst
10502     uint dstCN = e->CN3;    // starting at char pos CN
10503 
10504     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
10505 
10506     /*
10507      * Here we need to distinguish between 4 type of numbers.
10508      *
10509      * CSFL - Floating-point, leading sign
10510      * CSLS - Scaled fixed-point, leading sign
10511      * CSTS - Scaled fixed-point, trailing sign
10512      * CSNS - Scaled fixed-point, unsigned
10513      */
10514 
10515     // determine precision
10516     switch(e->S1)
10517     {
10518         case CSFL:
10519             n1 = (int) e->N1 - 1; // need to account for the - sign
10520             if (srcTN == CTN4)
10521                 n1 -= 2;    // 2 4-bit digits exponent
10522             else
10523                 n1 -= 1;    // 1 9-bit digit exponent
10524             sc1 = 0;        // no scaling factor
10525             break;
10526 
10527         case CSLS:
10528         case CSTS:
10529             n1 = (int) e->N1 - 1; // only 1 sign
10530             sc1 = -e->SF1;
10531             break;
10532 
10533         case CSNS:
10534             n1 = (int) e->N1;     // no sign
10535             sc1 = -e->SF1;
10536             break;  // no sign wysiwyg
10537     }
10538 
10539     if (n1 < 1)
10540         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n1<1");
10541 
10542     switch(e->S2)
10543     {
10544         case CSFL:
10545             n2 = (int) e->N2 - 1; // need to account for the sign
10546             if (e->TN2 == CTN4)
10547                 n2 -= 2;    // 2 4-bit digit exponent
10548             else
10549                 n2 -= 1;    // 1 9-bit digit exponent
10550             sc2 = 0;        // no scaling factor
10551             break;
10552 
10553         case CSLS:
10554         case CSTS:
10555             n2 = (int) e->N2 - 1; // 1 sign
10556             sc2 = -e->SF2;
10557             break;
10558 
10559         case CSNS:
10560             n2 = (int) e->N2;     // no sign
10561             sc2 = -e->SF2;
10562             break;  // no sign wysiwyg
10563     }
10564 
10565     if (n2 < 1)
10566         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n2<1");
10567 
10568     switch(e->S3)
10569     {
10570         case CSFL:
10571             n3 = (int) e->N3 - 1; // need to account for the sign
10572             if (dstTN == CTN4)
10573                 n3 -= 2;    // 2 4-bit digit exponent
10574             else
10575                 n3 -= 1;    // 1 9-bit digit exponent
10576             break;
10577 
10578         case CSLS:
10579         case CSTS:
10580             n3 = (int) e->N3 - 1; // 1 sign
10581             break;
10582 
10583         case CSNS:
10584             n3 = (int) e->N3;     // no sign
10585             break;  // no sign wysiwyg
10586     }
10587 
10588     if (n3 < 1)
10589         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n3<1");
10590 
10591     decContext set;
10592     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10593     decContextDefaultDPS8(&set);
10594     set.traps=0;
10595 
10596     decNumber _1, _2, _3;
10597 
10598     EISloadInputBufferNumeric (1);   // according to MF1
10599 
10600     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10601     if (e->sign == -1)
10602         op1->bits |= DECNEG;
10603     if (e->S1 == CSFL)
10604         op1->exponent = e->exponent;
10605 
10606     EISloadInputBufferNumeric (2);   // according to MF2
10607 
10608     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10609     if (e->sign == -1)
10610         op2->bits |= DECNEG;
10611     if (e->S2 == CSFL)
10612         op2->exponent = e->exponent;
10613 
10614     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10615 
10616     // RJ78: significant digits in the result may be lost if:
10617     // The difference between the scaling factors (exponents) of the source
10618     // operands is large enough to cause the expected length of the intermediate
10619     // result to exceed 63 digits after decimal point alignment of source operands, followed by addition.
10620     // ISOLTS 846 07c, 10a, 11b internal register overflow
10621     // trailing zeros are not counted towards the limit
10622 
10623     // XXX it is not clear which digits are lost, but I suppose it should be the most significant.
10624     // ISOLTS doesn't check for this.
10625 
10626     // XXX the algorithm should be similar/the same as dv3d NQ? It is to some extent already...
10627     bool iOvr = 0;
10628     if (op3->digits > 63) {
10629         uint8_t pr[256];
10630         // if sf<=0, trailing zeroes can't be shifted out
10631         // if sf> 0, (some of) trailing zeroes can be shifted out
10632         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10633 
10634         int ctz = 0;
10635         if (sf>0) {     // optimize: we don't care when sf>0
10636             decNumberGetBCD(op3,pr);
10637             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10638                  ctz ++;
10639         }
10640 
10641         if (op3->digits - min(max(sf,0),ctz) > 63) {
10642 
10643             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10644             int safe = set.digits;
10645             decNumber tmp;
10646 
10647             // discard MS digits
10648             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10649             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10650             decNumberPlus(&tmp, op3, &set);
10651             set.digits = safe;
10652 
10653             decNumberSubtract(op3, op3, &tmp, &set);
10654 
10655             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10656 
10657             decContextSetRounding(&set, safeR);
10658             iOvr = 1;
10659         }
10660     }
10661 
10662     bool Ovr = false, EOvr = false, Trunc = false;
10663 
10664     uint8_t out [256];
10665     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
10666 
10667     Ovr |= iOvr;
10668 
10669     if (decNumberIsZero(op3))
10670         op3->exponent = 127;
10671 
10672     //printf("%s\r\n", res);
10673 
10674     // now write to memory in proper format.....
10675 
10676     //word18 dstAddr = e->dstAddr;
10677     int pos = (int) dstCN;
10678 
10679     // 1st, take care of any leading sign .......
10680     switch(e->S3)
10681     {
10682         case CSFL:  // floating-point, leading sign.
10683         case CSLS:  // fixed-point, leading sign
10684             switch(dstTN)
10685             {
10686             case CTN4:
10687                 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.
10688                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10689                 else
10690                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10691                 break;
10692             case CTN9:
10693                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10694                 break;
10695             }
10696             break;
10697 
10698         case CSTS:  // nuttin' to do here .....
10699         case CSNS:
10700             break;  // no sign wysiwyg
10701     }
10702 
10703     // 2nd, write the digits .....
10704     for(int i = 0 ; i < n3 ; i++)
10705         switch(dstTN)
10706         {
10707         case CTN4:
10708             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
10709             break;
10710         case CTN9:
10711             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
10712             break;
10713         }
10714 
10715     // 3rd, take care of any trailing sign or exponent ...
10716     switch(e->S3)
10717     {
10718         case CSTS:  // write trailing sign ....
10719             switch(dstTN)
10720             {
10721             case CTN4:
10722                 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.
10723                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10724                 else
10725                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10726                 break;
10727             case CTN9:
10728                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10729                 break;
10730             }
10731             break;
10732 
10733         case CSFL:  // floating-point, leading sign.
10734             // write the exponent
10735             switch(dstTN)
10736             {
10737             case CTN4:
10738                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10739                 EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10740 
10741                     break;
10742             case CTN9:
10743                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10744                 break;
10745             }
10746             break;
10747 
10748         case CSLS:  // fixed point, leading sign - already done
10749         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10750             break;
10751     }
10752 
10753     // set flags, etc ...
10754     if (e->S3 == CSFL)
10755     {
10756         if (op3->exponent > 127)
10757         {
10758             SET_I_EOFL;
10759             EOvr = true;
10760         }
10761         if (op3->exponent < -128)
10762         {
10763             SET_I_EUFL;
10764             EOvr = true;
10765         }
10766     }
10767 
10768     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10769     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10770 
10771     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10772 
10773     cleanupOperandDescriptor (1);
10774     cleanupOperandDescriptor (2);
10775     cleanupOperandDescriptor (3);
10776 
10777     if (TST_I_TRUNC && T && tstOVFfault ())
10778       doFault(FAULT_OFL, fst_zero, "ad3d truncation(overflow) fault");
10779     if (EOvr && tstOVFfault ())
10780         doFault(FAULT_OFL, fst_zero, "ad3d over/underflow fault");
10781     if (Ovr)
10782     {
10783         SET_I_OFLOW;
10784         if (tstOVFfault ())
10785           doFault(FAULT_OFL, fst_zero, "ad3d overflow fault");
10786     }
10787 }
10788 
10789 /*
10790  * sb2d - Subtract Using Two Decimal Operands
10791  */
10792 
10793 void sb2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
10794 {
10795     EISstruct * e = & cpu.currentEISinstruction;
10796 
10797     fault_ipr_subtype_ mod_fault = 0;
10798 
10799 #ifndef EIS_SETUP
10800     setupOperandDescriptor(1, &mod_fault);
10801     setupOperandDescriptor(2, &mod_fault);
10802     setupOperandDescriptorCache(3);
10803 #endif
10804 
10805     parseNumericOperandDescriptor(1, &mod_fault);
10806     parseNumericOperandDescriptor(2, &mod_fault);
10807 
10808     L68_ (
10809       // L68 raises it immediately
10810       if (mod_fault)
10811         {
10812           doFault (FAULT_IPR,
10813                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10814                    "Illegal modifier");
10815         }
10816     )
10817 
10818     // Bits 1-8 MBZ
10819     if (IWB_IRODD & 0377000000000)
10820       {
10821         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
10822         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb2d 0-8 MBZ");
10823       }
10824 
10825     DPS8M_ (
10826       // DPS8M raises it delayed
10827       if (mod_fault)
10828         {
10829           doFault (FAULT_IPR,
10830                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10831                    "Illegal modifier");
10832         }
10833     )
10834 
10835     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10836     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10837     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10838 
10839     PNL (L68_ (if (R)
10840       DU_CYCLE_FRND;))
10841 
10842     uint srcTN = e->TN1;    // type of chars in src
10843 
10844     uint dstTN = e->TN2;    // type of chars in dst
10845     uint dstCN = e->CN2;    // starting at char pos CN
10846 
10847     e->ADDR3 = e->ADDR2;
10848 
10849     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10850 
10851     /*
10852      * Here we need to distinguish between 4 type of numbers.
10853      *
10854      * CSFL - Floating-point, leading sign
10855      * CSLS - Scaled fixed-point, leading sign
10856      * CSTS - Scaled fixed-point, trailing sign
10857      * CSNS - Scaled fixed-point, unsigned
10858      */
10859 
10860     // determine precision
10861     switch(e->S1)
10862     {
10863         case CSFL:
10864             n1 = (int) e->N1 - 1; // need to account for the - sign
10865             if (srcTN == CTN4)
10866                 n1 -= 2;    // 2 4-bit digits exponent
10867             else
10868                 n1 -= 1;    // 1 9-bit digit exponent
10869             sc1 = 0;        // no scaling factor
10870             break;
10871 
10872         case CSLS:
10873         case CSTS:
10874             n1 = (int) e->N1 - 1; // only 1 sign
10875             sc1 = -e->SF1;
10876             break;
10877 
10878         case CSNS:
10879             n1 = (int) e->N1;     // no sign
10880             sc1 = -e->SF1;
10881             break;  // no sign wysiwyg
10882     }
10883 
10884     if (n1 < 1)
10885         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n1<1");
10886 
10887     switch(e->S2)
10888     {
10889         case CSFL:
10890             n2 = (int) e->N2 - 1; // need to account for the sign
10891             if (e->TN2 == CTN4)
10892                 n2 -= 2;    // 2 4-bit digit exponent
10893             else
10894                 n2 -= 1;    // 1 9-bit digit exponent
10895             sc2 = 0;        // no scaling factor
10896             break;
10897 
10898         case CSLS:
10899         case CSTS:
10900             n2 = (int) e->N2 - 1; // 1 sign
10901             sc2 = -e->SF2;
10902             break;
10903 
10904         case CSNS:
10905             n2 = (int) e->N2;     // no sign
10906             sc2 = -e->SF2;
10907             break;  // no sign wysiwyg
10908     }
10909 
10910     if (n2 < 1)
10911         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n2<1");
10912 
10913     decContext set;
10914     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10915     decContextDefaultDPS8(&set);
10916     set.traps=0;
10917 
10918     decNumber _1, _2, _3;
10919 
10920     EISloadInputBufferNumeric (1);   // according to MF1
10921 
10922     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10923     if (e->sign == -1)
10924         op1->bits |= DECNEG;
10925     if (e->S1 == CSFL)
10926         op1->exponent = e->exponent;
10927 
10928     EISloadInputBufferNumeric (2);   // according to MF2
10929 
10930     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10931     if (e->sign == -1)
10932         op2->bits |= DECNEG;
10933     if (e->S2 == CSFL)
10934         op2->exponent = e->exponent;
10935 
10936     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
10937 
10938     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
10939     bool iOvr = 0;
10940     if (op3->digits > 63) {
10941         uint8_t pr[256];
10942         // if sf<=0, trailing zeroes can't be shifted out
10943         // if sf> 0, (some of) trailing zeroes can be shifted out
10944         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10945 
10946         int ctz = 0;
10947         if (sf>0) {     // optimize: we don't care when sf>0
10948             decNumberGetBCD(op3,pr);
10949             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10950                  ctz ++;
10951         }
10952 
10953         if (op3->digits - min(max(sf,0),ctz) > 63) {
10954 
10955             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10956             int safe = set.digits;
10957             decNumber tmp;
10958 
10959             // discard MS digits
10960             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10961             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10962             decNumberPlus(&tmp, op3, &set);
10963             set.digits = safe;
10964 
10965             decNumberSubtract(op3, op3, &tmp, &set);
10966 
10967             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10968 
10969             decContextSetRounding(&set, safeR);
10970             iOvr = 1;
10971         }
10972     }
10973 
10974     bool Ovr = false, EOvr = false, Trunc = false;
10975 
10976     uint8_t out [256];
10977     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
10978 
10979     Ovr |= iOvr;
10980 
10981     if (decNumberIsZero(op3))
10982         op3->exponent = 127;
10983 
10984     //printf("%s\r\n", res);
10985 
10986     // now write to memory in proper format.....
10987 
10988     //word18 dstAddr = e->dstAddr;
10989     int pos = (int) dstCN;
10990 
10991     // 1st, take care of any leading sign .......
10992     switch(e->S2)
10993     {
10994         case CSFL:  // floating-point, leading sign.
10995         case CSLS:  // fixed-point, leading sign
10996             switch(dstTN)
10997             {
10998                 case CTN4:
10999                     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.
11000                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11001                     else
11002                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11003                     break;
11004                 case CTN9:
11005                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11006                     break;
11007             }
11008             break;
11009 
11010         case CSTS:  // nuttin' to do here .....
11011         case CSNS:
11012             break;  // no sign wysiwyg
11013     }
11014 
11015     // 2nd, write the digits .....
11016     for(int i = 0 ; i < n2 ; i++)
11017         switch(dstTN)
11018         {
11019             case CTN4:
11020                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11021                 break;
11022             case CTN9:
11023                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11024                 break;
11025         }
11026 
11027     // 3rd, take care of any trailing sign or exponent ...
11028     switch(e->S2)
11029     {
11030         case CSTS:  // write trailing sign ....
11031             switch(dstTN)
11032             {
11033                 case CTN4:
11034                     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.
11035                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11036                     else
11037                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11038                     break;
11039                 case CTN9:
11040                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11041                     break;
11042             }
11043             break;
11044 
11045         case CSFL:  // floating-point, leading sign.
11046             // write the exponent
11047             switch(dstTN)
11048             {
11049                 case CTN4:
11050                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11051                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11052 
11053                     break;
11054                 case CTN9:
11055                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11056                     break;
11057             }
11058             break;
11059 
11060         case CSLS:  // fixed point, leading sign - already done
11061         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11062             break;
11063     }
11064 
11065     // set flags, etc ...
11066     if (e->S2 == CSFL)
11067     {
11068         if (op3->exponent > 127)
11069         {
11070             SET_I_EOFL;
11071             EOvr = true;
11072         }
11073         if (op3->exponent < -128)
11074         {
11075             SET_I_EUFL;
11076             EOvr = true;
11077         }
11078     }
11079 
11080     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11081     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11082 
11083     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11084 
11085     cleanupOperandDescriptor (1);
11086     cleanupOperandDescriptor (2);
11087     cleanupOperandDescriptor (3);
11088 
11089     if (TST_I_TRUNC && T && tstOVFfault ())
11090       doFault(FAULT_OFL, fst_zero, "sb2d truncation(overflow) fault");
11091     if (EOvr && tstOVFfault ())
11092         doFault(FAULT_OFL, fst_zero, "sb2d over/underflow fault");
11093     if (Ovr)
11094     {
11095         SET_I_OFLOW;
11096         if (tstOVFfault ())
11097           doFault(FAULT_OFL, fst_zero, "sb2d overflow fault");
11098     }
11099 }
11100 
11101 /*
11102  * sb3d - Subtract Using Three Decimal Operands
11103  */
11104 
11105 void sb3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
11106 {
11107     EISstruct * e = & cpu.currentEISinstruction;
11108 
11109     fault_ipr_subtype_ mod_fault = 0;
11110 
11111 #ifndef EIS_SETUP
11112     setupOperandDescriptor(1, &mod_fault);
11113     setupOperandDescriptor(2, &mod_fault);
11114     setupOperandDescriptor(3, &mod_fault);
11115 #endif
11116 
11117     parseNumericOperandDescriptor(1, &mod_fault);
11118     parseNumericOperandDescriptor(2, &mod_fault);
11119     parseNumericOperandDescriptor(3, &mod_fault);
11120 
11121     L68_ (
11122       // L68 raises it immediately
11123       if (mod_fault)
11124         {
11125           doFault (FAULT_IPR,
11126                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11127                    "Illegal modifier");
11128         }
11129     )
11130 
11131     // Bit 1 MBZ
11132     if (IWB_IRODD & 0200000000000)
11133       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb3d(): 1 MBZ");
11134 
11135     DPS8M_ (
11136       // DPS8M raises it delayed
11137       if (mod_fault)
11138         {
11139           doFault (FAULT_IPR,
11140                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11141                    "Illegal modifier");
11142         }
11143     )
11144 
11145     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11146     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11147     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11148 
11149     PNL (L68_ (if (R)
11150       DU_CYCLE_FRND;))
11151 
11152     uint srcTN = e->TN1;    // type of chars in src
11153 
11154     uint dstTN = e->TN3;    // type of chars in dst
11155     uint dstCN = e->CN3;    // starting at char pos CN
11156 
11157     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11158 
11159     /*
11160      * Here we need to distinguish between 4 type of numbers.
11161      *
11162      * CSFL - Floating-point, leading sign
11163      * CSLS - Scaled fixed-point, leading sign
11164      * CSTS - Scaled fixed-point, trailing sign
11165      * CSNS - Scaled fixed-point, unsigned
11166      */
11167 
11168     // determine precision
11169     switch(e->S1)
11170     {
11171         case CSFL:
11172             n1 = (int) e->N1 - 1; // need to account for the - sign
11173             if (srcTN == CTN4)
11174                 n1 -= 2;    // 2 4-bit digits exponent
11175             else
11176                 n1 -= 1;    // 1 9-bit digit exponent
11177             sc1 = 0;        // no scaling factor
11178             break;
11179 
11180         case CSLS:
11181         case CSTS:
11182             n1 = (int) e->N1 - 1; // only 1 sign
11183             sc1 = -e->SF1;
11184             break;
11185 
11186         case CSNS:
11187             n1 = (int) e->N1;     // no sign
11188             sc1 = -e->SF1;
11189             break;  // no sign wysiwyg
11190     }
11191 
11192     if (n1 < 1)
11193         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n1<1");
11194 
11195     switch(e->S2)
11196     {
11197         case CSFL:
11198             n2 = (int) e->N2 - 1; // need to account for the sign
11199             if (e->TN2 == CTN4)
11200                 n2 -= 2;    // 2 4-bit digit exponent
11201             else
11202                 n2 -= 1;    // 1 9-bit digit exponent
11203             sc2 = 0;        // no scaling factor
11204             break;
11205 
11206         case CSLS:
11207         case CSTS:
11208             n2 = (int) e->N2 - 1; // 1 sign
11209             sc2 = -e->SF2;
11210             break;
11211 
11212         case CSNS:
11213             n2 = (int) e->N2;     // no sign
11214             sc2 = -e->SF2;
11215             break;  // no sign wysiwyg
11216     }
11217 
11218     if (n2 < 1)
11219         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n2<1");
11220 
11221     switch(e->S3)
11222     {
11223         case CSFL:
11224             n3 = (int) e->N3 - 1; // need to account for the sign
11225             if (dstTN == CTN4)
11226                 n3 -= 2;    // 2 4-bit digit exponent
11227             else
11228                 n3 -= 1;    // 1 9-bit digit exponent
11229             break;
11230 
11231         case CSLS:
11232         case CSTS:
11233             n3 = (int) e->N3 - 1; // 1 sign
11234             break;
11235 
11236         case CSNS:
11237             n3 = (int) e->N3;     // no sign
11238             break;  // no sign wysiwyg
11239     }
11240 
11241     if (n3 < 1)
11242         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n3<1");
11243 
11244     decContext set;
11245     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11246     decContextDefaultDPS8(&set);
11247 
11248     set.traps=0;
11249 
11250     decNumber _1, _2, _3;
11251 
11252     EISloadInputBufferNumeric (1);   // according to MF1
11253 
11254     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11255     if (e->sign == -1)
11256         op1->bits |= DECNEG;
11257     if (e->S1 == CSFL)
11258         op1->exponent = e->exponent;
11259 
11260     EISloadInputBufferNumeric (2);   // according to MF2
11261 
11262     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11263     if (e->sign == -1)
11264         op2->bits |= DECNEG;
11265     if (e->S2 == CSFL)
11266         op2->exponent = e->exponent;
11267 
11268     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11269 
11270     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11271     bool iOvr = 0;
11272     if (op3->digits > 63) {
11273         uint8_t pr[256];
11274         // if sf<=0, trailing zeroes can't be shifted out
11275         // if sf> 0, (some of) trailing zeroes can be shifted out
11276         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11277 
11278         int ctz = 0;
11279         if (sf>0) {     // optimize: we don't care when sf>0
11280             decNumberGetBCD(op3,pr);
11281             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11282                  ctz ++;
11283         }
11284 
11285         if (op3->digits - min(max(sf,0),ctz) > 63) {
11286 
11287             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11288             int safe = set.digits;
11289             decNumber tmp;
11290 
11291             // discard MS digits
11292             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11293             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11294             decNumberPlus(&tmp, op3, &set);
11295             set.digits = safe;
11296 
11297             decNumberSubtract(op3, op3, &tmp, &set);
11298 
11299             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
11300 
11301             decContextSetRounding(&set, safeR);
11302             iOvr = 1;
11303         }
11304     }
11305 
11306     bool Ovr = false, EOvr = false, Trunc = false;
11307 
11308     uint8_t out [256];
11309     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11310 
11311     Ovr |= iOvr;
11312 
11313     if (decNumberIsZero(op3))
11314         op3->exponent = 127;
11315 
11316     // now write to memory in proper format.....
11317 
11318     //word18 dstAddr = e->dstAddr;
11319     int pos = (int) dstCN;
11320 
11321     // 1st, take care of any leading sign .......
11322     switch(e->S3)
11323     {
11324         case CSFL:  // floating-point, leading sign.
11325         case CSLS:  // fixed-point, leading sign
11326             switch(dstTN)
11327         {
11328             case CTN4:
11329                 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.
11330                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11331                 else
11332                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11333                 break;
11334             case CTN9:
11335                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11336                 break;
11337         }
11338             break;
11339 
11340         case CSTS:  // nuttin' to do here .....
11341         case CSNS:
11342             break;  // no sign wysiwyg
11343     }
11344 
11345     // 2nd, write the digits .....
11346     for(int i = 0 ; i < n3 ; i++)
11347         switch(dstTN)
11348     {
11349         case CTN4:
11350             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11351             break;
11352         case CTN9:
11353             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11354             break;
11355     }
11356 
11357     // 3rd, take care of any trailing sign or exponent ...
11358     switch(e->S3)
11359     {
11360         case CSTS:  // write trailing sign ....
11361             switch(dstTN)
11362             {
11363                 case CTN4:
11364                     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.
11365                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11366                     else
11367                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11368                     break;
11369                 case CTN9:
11370                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11371                     break;
11372             }
11373             break;
11374 
11375         case CSFL:  // floating-point, leading sign.
11376             // write the exponent
11377             switch(dstTN)
11378             {
11379                 case CTN4:
11380                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11381                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11382 
11383                     break;
11384                 case CTN9:
11385                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11386                     break;
11387             }
11388             break;
11389 
11390         case CSLS:  // fixed point, leading sign - already done
11391         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11392             break;
11393     }
11394 
11395     // set flags, etc ...
11396     if (e->S3 == CSFL)
11397     {
11398         if (op3->exponent > 127)
11399         {
11400             SET_I_EOFL;
11401             EOvr = true;
11402         }
11403         if (op3->exponent < -128)
11404         {
11405             SET_I_EUFL;
11406             EOvr = true;
11407         }
11408     }
11409 
11410     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11411     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11412 
11413     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11414 
11415     cleanupOperandDescriptor (1);
11416     cleanupOperandDescriptor (2);
11417     cleanupOperandDescriptor (3);
11418 
11419     if (TST_I_TRUNC && T && tstOVFfault ())
11420       doFault(FAULT_OFL, fst_zero, "sb3d truncation(overflow) fault");
11421     if (EOvr && tstOVFfault ())
11422         doFault(FAULT_OFL, fst_zero, "sb3d over/underflow fault");
11423     if (Ovr)
11424     {
11425         SET_I_OFLOW;
11426         if (tstOVFfault ())
11427           doFault(FAULT_OFL, fst_zero, "sb3d overflow fault");
11428     }
11429 }
11430 
11431 /*
11432  * mp2d - Multiply Using Two Decimal Operands
11433  */
11434 
11435 void mp2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
11436 {
11437     EISstruct * e = & cpu.currentEISinstruction;
11438 
11439     fault_ipr_subtype_ mod_fault = 0;
11440 
11441 #ifndef EIS_SETUP
11442     setupOperandDescriptor(1, &mod_fault);
11443     setupOperandDescriptor(2, &mod_fault);
11444     setupOperandDescriptorCache(3);
11445 #endif
11446 
11447     parseNumericOperandDescriptor(1, &mod_fault);
11448     parseNumericOperandDescriptor(2, &mod_fault);
11449 
11450     L68_ (
11451       // L68 raises it immediately
11452       if (mod_fault)
11453         {
11454           doFault (FAULT_IPR,
11455                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11456                    "Illegal modifier");
11457         }
11458     )
11459 
11460     // Bits 1-8 MBZ
11461     if (IWB_IRODD & 0377000000000)
11462       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp2d 1-8 MBZ");
11463 
11464     DPS8M_ (
11465       // DPS8M raises it delayed
11466       if (mod_fault)
11467         {
11468           doFault (FAULT_IPR,
11469                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11470                    "Illegal modifier");
11471         }
11472     )
11473 
11474     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11475     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11476     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11477 
11478     PNL (L68_ (if (R)
11479       DU_CYCLE_FRND;))
11480 
11481     uint srcTN = e->TN1;    // type of chars in src
11482 
11483     uint dstTN = e->TN2;    // type of chars in dst
11484     uint dstCN = e->CN2;    // starting at char pos CN
11485 
11486     e->ADDR3 = e->ADDR2;
11487 
11488     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
11489 
11490     /*
11491      * Here we need to distinguish between 4 type of numbers.
11492      *
11493      * CSFL - Floating-point, leading sign
11494      * CSLS - Scaled fixed-point, leading sign
11495      * CSTS - Scaled fixed-point, trailing sign
11496      * CSNS - Scaled fixed-point, unsigned
11497      */
11498 
11499     // determine precision
11500     switch(e->S1)
11501     {
11502         case CSFL:
11503             n1 = (int) e->N1 - 1; // need to account for the - sign
11504             if (srcTN == CTN4)
11505                 n1 -= 2;    // 2 4-bit digits exponent
11506             else
11507                 n1 -= 1;    // 1 9-bit digit exponent
11508             sc1 = 0;        // no scaling factor
11509             break;
11510 
11511         case CSLS:
11512         case CSTS:
11513             n1 = (int) e->N1 - 1; // only 1 sign
11514             sc1 = -e->SF1;
11515             break;
11516 
11517         case CSNS:
11518             n1 = (int) e->N1;     // no sign
11519             sc1 = -e->SF1;
11520             break;  // no sign wysiwyg
11521     }
11522 
11523     if (n1 < 1)
11524         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n1<1");
11525 
11526     switch(e->S2)
11527     {
11528         case CSFL:
11529             n2 = (int) e->N2 - 1; // need to account for the sign
11530             if (e->TN2 == CTN4)
11531                 n2 -= 2;    // 2 4-bit digit exponent
11532             else
11533                 n2 -= 1;    // 1 9-bit digit exponent
11534             sc2 = 0;        // no scaling factor
11535             break;
11536 
11537         case CSLS:
11538         case CSTS:
11539             n2 = (int) e->N2 - 1; // 1 sign
11540             sc2 = -e->SF2;
11541             break;
11542 
11543         case CSNS:
11544             n2 = (int) e->N2;     // no sign
11545             sc2 = -e->SF2;
11546             break;  // no sign wysiwyg
11547     }
11548 
11549     if (n2 < 1)
11550         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n2<1");
11551 
11552     decContext set;
11553     decContextDefaultDPS8Mul(&set); // 126 digits for multiply
11554 
11555     set.traps=0;
11556 
11557     decNumber _1, _2, _3;
11558 
11559     EISloadInputBufferNumeric (1);   // according to MF1
11560 
11561     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11562     if (e->sign == -1)
11563         op1->bits |= DECNEG;
11564     if (e->S1 == CSFL)
11565         op1->exponent = e->exponent;
11566 
11567     EISloadInputBufferNumeric (2);   // according to MF2
11568 
11569     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11570     if (e->sign == -1)
11571         op2->bits |= DECNEG;
11572     if (e->S2 == CSFL)
11573         op2->exponent = e->exponent;
11574 
11575     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11576 
11577     bool Ovr = false, EOvr = false, Trunc = false;
11578 
11579     uint8_t out [256];
11580     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11581 
11582     if (decNumberIsZero(op3))
11583         op3->exponent = 127;
11584 
11585     // now write to memory in proper format.....
11586 
11587     //word18 dstAddr = e->dstAddr;
11588     int pos = (int) dstCN;
11589 
11590     // 1st, take care of any leading sign .......
11591     switch(e->S2)
11592     {
11593         case CSFL:  // floating-point, leading sign.
11594         case CSLS:  // fixed-point, leading sign
11595             switch(dstTN)
11596         {
11597             case CTN4:
11598                 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.
11599                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11600                 else
11601                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11602                 break;
11603             case CTN9:
11604                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11605                 break;
11606         }
11607             break;
11608 
11609         case CSTS:  // nuttin' to do here .....
11610         case CSNS:
11611             break;  // no sign wysiwyg
11612     }
11613 
11614     // 2nd, write the digits .....
11615     for(int i = 0 ; i < n2 ; i++)
11616         switch(dstTN)
11617     {
11618         case CTN4:
11619             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11620             break;
11621         case CTN9:
11622             EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11623             break;
11624     }
11625 
11626     // 3rd, take care of any trailing sign or exponent ...
11627     switch(e->S2)
11628     {
11629         case CSTS:  // write trailing sign ....
11630             switch(dstTN)
11631         {
11632             case CTN4:
11633                 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.
11634                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11635                 else
11636                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11637                 break;
11638             case CTN9:
11639                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11640                 break;
11641         }
11642             break;
11643 
11644         case CSFL:  // floating-point, leading sign.
11645             // write the exponent
11646             switch(dstTN)
11647             {
11648                 case CTN4:
11649                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11650                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11651 
11652                     break;
11653                 case CTN9:
11654                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11655                     break;
11656             }
11657             break;
11658 
11659         case CSLS:  // fixed point, leading sign - already done
11660         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11661             break;
11662     }
11663 
11664     // set flags, etc ...
11665     if (e->S2 == CSFL)
11666     {
11667         if (op3->exponent > 127)
11668         {
11669             SET_I_EOFL;
11670             EOvr = true;
11671         }
11672         if (op3->exponent < -128)
11673         {
11674             SET_I_EUFL;
11675             EOvr = true;
11676         }
11677     }
11678 
11679     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11680     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11681 
11682     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11683 
11684     cleanupOperandDescriptor (1);
11685     cleanupOperandDescriptor (2);
11686     cleanupOperandDescriptor (3);
11687 
11688     if (TST_I_TRUNC && T && tstOVFfault ())
11689       doFault(FAULT_OFL, fst_zero, "mp2d truncation(overflow) fault");
11690     if (EOvr && tstOVFfault ())
11691         doFault(FAULT_OFL, fst_zero, "mp2d over/underflow fault");
11692     if (Ovr)
11693     {
11694         SET_I_OFLOW;
11695         if (tstOVFfault ())
11696           doFault(FAULT_OFL, fst_zero, "mp2d overflow fault");
11697     }
11698 }
11699 
11700 /*
11701  * mp3d - Multiply Using Three Decimal Operands
11702  */
11703 
11704 void mp3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
11705 {
11706     EISstruct * e = & cpu.currentEISinstruction;
11707 
11708     fault_ipr_subtype_ mod_fault = 0;
11709 
11710 #ifndef EIS_SETUP
11711     setupOperandDescriptor(1, &mod_fault);
11712     setupOperandDescriptor(2, &mod_fault);
11713     setupOperandDescriptor(3, &mod_fault);
11714 #endif
11715 
11716     parseNumericOperandDescriptor(1, &mod_fault);
11717     parseNumericOperandDescriptor(2, &mod_fault);
11718     parseNumericOperandDescriptor(3, &mod_fault);
11719 
11720     L68_ (
11721       // L68 raises it immediately
11722       if (mod_fault)
11723         {
11724           doFault (FAULT_IPR,
11725                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11726                    "Illegal modifier");
11727         }
11728     )
11729 
11730     // Bit 1 MBZ
11731     if (IWB_IRODD & 0200000000000)
11732       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp3d(): 1 MBZ");
11733 
11734     DPS8M_ (
11735       // DPS8M raises it delayed
11736       if (mod_fault)
11737         {
11738           doFault (FAULT_IPR,
11739                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11740                    "Illegal modifier");
11741         }
11742     )
11743 
11744     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11745     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11746     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11747 
11748     PNL (L68_ (if (R)
11749       DU_CYCLE_FRND;))
11750 
11751     uint srcTN = e->TN1;    // type of chars in src
11752 
11753     uint dstTN = e->TN3;    // type of chars in dst
11754     uint dstCN = e->CN3;    // starting at char pos CN
11755 
11756     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11757 
11758     /*
11759      * Here we need to distinguish between 4 type of numbers.
11760      *
11761      * CSFL - Floating-point, leading sign
11762      * CSLS - Scaled fixed-point, leading sign
11763      * CSTS - Scaled fixed-point, trailing sign
11764      * CSNS - Scaled fixed-point, unsigned
11765      */
11766 
11767     // determine precision
11768     switch(e->S1)
11769     {
11770         case CSFL:
11771             n1 = (int) e->N1 - 1; // need to account for the - sign
11772             if (srcTN == CTN4)
11773                 n1 -= 2;    // 2 4-bit digits exponent
11774             else
11775                 n1 -= 1;    // 1 9-bit digit exponent
11776             sc1 = 0;        // no scaling factor
11777             break;
11778 
11779         case CSLS:
11780         case CSTS:
11781             n1 = (int) e->N1 - 1; // only 1 sign
11782             sc1 = -e->SF1;
11783             break;
11784 
11785         case CSNS:
11786             n1 = (int) e->N1;     // no sign
11787             sc1 = -e->SF1;
11788             break;  // no sign wysiwyg
11789     }
11790 
11791     if (n1 < 1)
11792         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n1<1");
11793 
11794     switch(e->S2)
11795     {
11796         case CSFL:
11797             n2 = (int) e->N2 - 1; // need to account for the sign
11798             if (e->TN2 == CTN4)
11799                 n2 -= 2;    // 2 4-bit digit exponent
11800             else
11801                 n2 -= 1;    // 1 9-bit digit exponent
11802             sc2 = 0;        // no scaling factor
11803             break;
11804 
11805         case CSLS:
11806         case CSTS:
11807             n2 = (int) e->N2 - 1; // 1 sign
11808             sc2 = -e->SF2;
11809             break;
11810 
11811         case CSNS:
11812             n2 = (int) e->N2;     // no sign
11813             sc2 = -e->SF2;
11814             break;  // no sign wysiwyg
11815     }
11816 
11817     if (n2 < 1)
11818         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n2<1");
11819 
11820     switch(e->S3)
11821     {
11822         case CSFL:
11823             n3 = (int) e->N3 - 1; // need to account for the sign
11824             if (dstTN == CTN4)
11825                 n3 -= 2;    // 2 4-bit digit exponent
11826             else
11827                 n3 -= 1;    // 1 9-bit digit exponent
11828             break;
11829 
11830         case CSLS:
11831         case CSTS:
11832             n3 = (int) e->N3 - 1; // 1 sign
11833             break;
11834 
11835         case CSNS:
11836             n3 = (int) e->N3;     // no sign
11837             break;  // no sign wysiwyg
11838     }
11839 
11840     if (n3 < 1)
11841         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n3<1");
11842 
11843     decContext set;
11844     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11845     decContextDefaultDPS8Mul(&set);     // 126 digits for multiply
11846 
11847     set.traps=0;
11848 
11849     decNumber _1, _2, _3;
11850 
11851     EISloadInputBufferNumeric (1);   // according to MF1
11852 
11853     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11854     if (e->sign == -1)
11855         op1->bits |= DECNEG;
11856     if (e->S1 == CSFL)
11857         op1->exponent = e->exponent;
11858 
11859     EISloadInputBufferNumeric (2);   // according to MF2
11860 
11861     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11862     if (e->sign == -1)
11863         op2->bits |= DECNEG;
11864     if (e->S2 == CSFL)
11865         op2->exponent = e->exponent;
11866 
11867     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11868 
11869 //    char c1[1024];
11870 //    char c2[1024];
11871 //    char c3[1024];
11872 //
11873 //    decNumberToString(op1, c1);
11874 //    sim_printf("c1:%s\n", c1);
11875 //    decNumberToString(op2, c2);
11876 //    sim_printf("c2:%s\n", c2);
11877 //    decNumberToString(op3, c3);
11878 //    sim_printf("c3:%s\n", c3);
11879 
11880     bool Ovr = false, EOvr = false, Trunc = false;
11881 
11882     uint8_t out [256];
11883     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11884 
11885     if (decNumberIsZero(op3))
11886         op3->exponent = 127;
11887 
11888     // now write to memory in proper format.....
11889 
11890     //word18 dstAddr = e->dstAddr;
11891     int pos = (int) dstCN;
11892 
11893     // 1st, take care of any leading sign .......
11894     switch(e->S3)
11895     {
11896         case CSFL:  // floating-point, leading sign.
11897         case CSLS:  // fixed-point, leading sign
11898             switch(dstTN)
11899             {
11900             case CTN4:
11901               if (e->P) // If TN2 and S2 specify a 4-bit signed number and P
11902                           // = 1, then the 13(8) plus sign character is placed
11903                           // appropriately if the result of the operation is
11904                           // positive.
11905                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11906                 else
11907                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11908                 break;
11909             case CTN9:
11910                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11911                 break;
11912             }
11913             break;
11914 
11915         case CSTS:  // nuttin' to do here .....
11916         case CSNS:
11917             break;  // no sign wysiwyg
11918     }
11919 
11920     // 2nd, write the digits .....
11921     for(int i = 0 ; i < n3 ; i++)
11922         switch(dstTN)
11923         {
11924             case CTN4:
11925                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11926                 break;
11927             case CTN9:
11928                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11929                 break;
11930         }
11931 
11932         // 3rd, take care of any trailing sign or exponent ...
11933     switch(e->S3)
11934     {
11935         case CSTS:  // write trailing sign ....
11936             switch(dstTN)
11937             {
11938                 case CTN4:
11939                     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.
11940                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11941                     else
11942                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11943                     break;
11944                 case CTN9:
11945                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11946                     break;
11947             }
11948             break;
11949 
11950         case CSFL:  // floating-point, leading sign.
11951             // write the exponent
11952             switch(dstTN)
11953             {
11954                 case CTN4:
11955                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11956                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11957                     break;
11958                 case CTN9:
11959                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11960                     break;
11961             }
11962             break;
11963 
11964         case CSLS:  // fixed point, leading sign - already done
11965         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11966             break;
11967     }
11968 
11969     // set flags, etc ...
11970     if (e->S3 == CSFL)
11971     {
11972         if (op3->exponent > 127)
11973         {
11974             SET_I_EOFL;
11975             EOvr = true;
11976         }
11977         if (op3->exponent < -128)
11978         {
11979             SET_I_EUFL;
11980             EOvr = true;
11981         }
11982     }
11983 
11984     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11985     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11986 
11987     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11988 
11989     cleanupOperandDescriptor (1);
11990     cleanupOperandDescriptor (2);
11991     cleanupOperandDescriptor (3);
11992 
11993     if (TST_I_TRUNC && T && tstOVFfault ())
11994       doFault(FAULT_OFL, fst_zero, "mp3d truncation(overflow) fault");
11995     if (EOvr && tstOVFfault ())
11996         doFault(FAULT_OFL, fst_zero, "mp3d over/underflow fault");
11997     if (Ovr)
11998     {
11999         SET_I_OFLOW;
12000         if (tstOVFfault ())
12001           doFault(FAULT_OFL, fst_zero, "mp3d overflow fault");
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 /*
12754  * dv2d - Divide Using Two Decimal Operands
12755  */
12756 
12757 void dv2d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
12758 {
12759     EISstruct * e = & cpu.currentEISinstruction;
12760 
12761     fault_ipr_subtype_ mod_fault = 0;
12762 
12763 #ifndef EIS_SETUP
12764     setupOperandDescriptor(1, &mod_fault);
12765     setupOperandDescriptor(2, &mod_fault);
12766     setupOperandDescriptorCache(3);
12767 #endif
12768 
12769     parseNumericOperandDescriptor(1, &mod_fault);
12770     parseNumericOperandDescriptor(2, &mod_fault);
12771 
12772     L68_ (
12773       // L68 raises it immediately
12774       if (mod_fault)
12775         {
12776           doFault (FAULT_IPR,
12777                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12778                    "Illegal modifier");
12779         }
12780     )
12781 
12782     // Bits 1-8 MBZ
12783     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ as well
12784     if (IWB_IRODD & 0377400000000)
12785       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv2d 1-9 MBZ");
12786 
12787     DPS8M_ (
12788       // DPS8M raises it delayed
12789       if (mod_fault)
12790         {
12791           doFault (FAULT_IPR,
12792                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12793                    "Illegal modifier");
12794         }
12795     )
12796 
12797     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
12798     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
12799     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
12800 
12801     PNL (L68_ (if (R)
12802       DU_CYCLE_FRND;))
12803 
12804     uint srcTN = e->TN1;    // type of chars in src
12805 
12806     uint dstTN = e->TN2;    // type of chars in dst
12807     uint dstCN = e->CN2;    // starting at char pos CN
12808 
12809     e->ADDR3 = e->ADDR2;
12810 
12811     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
12812 
12813     /*
12814      * Here we need to distinguish between 4 type of numbers.
12815      *
12816      * CSFL - Floating-point, leading sign
12817      * CSLS - Scaled fixed-point, leading sign
12818      * CSTS - Scaled fixed-point, trailing sign
12819      * CSNS - Scaled fixed-point, unsigned
12820      */
12821 
12822     // determine precision
12823     switch(e->S1)
12824     {
12825         case CSFL:
12826             n1 = (int) e->N1 - 1; // need to account for the - sign
12827             if (srcTN == CTN4)
12828                 n1 -= 2;    // 2 4-bit digits exponent
12829             else
12830                 n1 -= 1;    // 1 9-bit digit exponent
12831             sc1 = 0;        // no scaling factor
12832             break;
12833 
12834         case CSLS:
12835         case CSTS:
12836             n1 = (int) e->N1 - 1; // only 1 sign
12837             sc1 = -e->SF1;
12838             break;
12839 
12840         case CSNS:
12841             n1 = (int) e->N1;     // no sign
12842             sc1 = -e->SF1;
12843             break;  // no sign wysiwyg
12844     }
12845 
12846     if (n1 < 1)
12847         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n1<1");
12848 
12849     switch(e->S2)
12850     {
12851         case CSFL:
12852             n2 = (int) e->N2 - 1; // need to account for the sign
12853             if (e->TN2 == CTN4)
12854                 n2 -= 2;    // 2 4-bit digit exponent
12855             else
12856                 n2 -= 1;    // 1 9-bit digit exponent
12857             sc2 = 0;        // no scaling factor
12858             break;
12859 
12860         case CSLS:
12861         case CSTS:
12862             n2 = (int) e->N2 - 1; // 1 sign
12863             sc2 = -e->SF2;
12864             break;
12865 
12866         case CSNS:
12867             n2 = (int) e->N2;     // no sign
12868             sc2 = -e->SF2;
12869             break;  // no sign wysiwyg
12870     }
12871 
12872     if (n2 < 1)
12873         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n2<1");
12874 
12875     decContext set;
12876     decContextDefaultDPS8(&set);
12877 
12878     set.traps=0;
12879 
12880     decNumber _1, _2, _3;
12881 
12882     EISloadInputBufferNumeric (1);   // according to MF1
12883 
12884     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);    // divisor
12885     if (e->sign == -1)
12886         op1->bits |= DECNEG;
12887     if (e->S1 == CSFL)
12888         op1->exponent = e->exponent;
12889 
12890     // check for divide by 0!
12891     if (decNumberIsZero(op1))
12892     {
12893         doFault(FAULT_DIV, fst_zero, "dv2d division by 0");
12894     }
12895 
12896     word9   inBufferop1 [64];
12897     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
12898 
12899     EISloadInputBufferNumeric (2);   // according to MF2
12900 
12901     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);    // dividend
12902     if (e->sign == -1)
12903         op2->bits |= DECNEG;
12904     if (e->S2 == CSFL)
12905         op2->exponent = e->exponent;
12906 
12907     int NQ;
12908     if (e->S2 == CSFL)
12909     {
12910         NQ = n2;
12911     }
12912     else
12913     {
12914         // count leading zeroes
12915         // TODO optimize - can these be somehow extracted from decNumbers?
12916         int clz1, clz2, i;
12917         for (i=0; i < op1->digits; i++)
12918             if (inBufferop1[i]!=0)
12919                 break;
12920         clz1 = i;
12921         for (i=0; i < op2->digits; i++)
12922             if (e->inBuffer[i]!=0) // this still holds op2 digits
12923                 break;
12924         clz2 = i;
12925         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: clz1 %d clz2 %d\n",clz1,clz2);
12926 
12927         // XXX are clz also valid for CSFL dividend / divisor? probably yes
12928         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
12929         NQ = (n2-clz2+1) - (n1-clz1) + (-(e->S1==CSFL?op1->exponent:(int)e->SF1));
12930 
12931 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);
12932     }
12933     if (NQ > 63)
12934         doFault(FAULT_DIV, fst_zero, "dv2d NQ>63");
12935     // Note: NQ is currently unused apart from this FAULT_DIV check. decNumber produces more digits than required, but they are then rounded/truncated
12936 
12937     // Yes, they're switched. op1=divisor
12938     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
12939     // Note DPS88 and DPS9000 are different when NQ <= 0
12940     // This is a flaw in the DPS8/70 hardware which was corrected in later models
12941     // ISOLTS-817 05b
12942 
12943     PRINTDEC("op2", op2);
12944     PRINTDEC("op1", op1);
12945     PRINTDEC("op3", op3);
12946 
12947     // let's check division results to see for anomalous conditions
12948     if (
12949         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
12950         (set.status & DEC_Invalid_operation) ||
12951         (set.status & DEC_Division_by_zero)
12952         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv2d anomalous results"); }      // divide by zero has already been checked before
12953 
12954     if (e->S2 == CSFL)
12955     {
12956         // justify CSFL left
12957         // This is a flaw in the DPS8/70 hardware which was corrected in later models
12958         // Note DPS88 and DPS9000 are different
12959         // ISOLTS-817 06c,06e
12960 
12961         decNumber _sf;
12962 
12963         if (n2 - op3->digits > 0)
12964         {
12965             decNumberFromInt32(&_sf, op3->exponent - (n2 - op3->digits));
12966             PRINTDEC("Value 1", op3)
12967             PRINTDEC("Value sf", &_sf)
12968             op3 = decNumberRescale(op3, op3, &_sf, &set);
12969             PRINTDEC("Value 2", op3)
12970         }
12971     }
12972 
12973     bool Ovr = false, EOvr = false, Trunc = false;
12974     uint8_t out[256];
12975 
12976     // CSFL: If the divisor is greater than the dividend after operand
12977     // alignment, the leading zero digit produced is counted and the effective
12978     // precision of the result is reduced by one.
12979     // This is a flaw in the DPS8/70 hardware which was corrected in later models
12980     // Note DPS88 and DPS9000 are different
12981     //
12982     // "greater after operand alignment" means scale until most-significant digits are nonzero, then compare magnitudes ignoring exponents
12983     // This passes ISOLTS-817 06e, ET 458,461,483,486
12984     char *res;
12985     if (e->S2 == CSFL) {
12986         decNumber _1a;
12987         decNumber _2a;
12988         decNumber _sf;
12989         if (op1->digits >= op2->digits) {
12990             // scale op2
12991             decNumberCopy(&_1a, op1);
12992             decNumberFromInt32(&_sf, op1->digits - op2->digits);
12993             decNumberShift(&_2a, op2, &_sf, &set);
12994         } else if (op1->digits < op2->digits) {
12995             // scale op1
12996             decNumberFromInt32(&_sf, op2->digits - op1->digits);
12997             decNumberShift(&_1a, op1, &_sf, &set);
12998             decNumberCopy(&_2a, op2);
12999         }
13000         _1a.exponent = 0;
13001         _2a.exponent = 0;
13002 
13003         PRINTDEC("dv2d: op1a", &_1a);
13004         PRINTDEC("dv2d: op2a", &_2a);
13005         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);
13006 
13007         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13008             // shorten the result field to get proper rounding
13009             res = formatDecimal(out, &set, op3, n2 -1, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13010 
13011             // prepend zero digit
13012             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13013             for (int i = n2; i > 0; i--) // incl.zero terminator
13014                  res[i] = res[i-1];
13015             res[0] = '0';
13016             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: addzero n2 %d %s exp %d\n",n2,res,op3->exponent);
13017         } else {
13018             // full n2 digits are returned
13019             res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13020         }
13021     } else {
13022         // same as all other decimal instructions
13023         res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13024     }
13025 
13026     if (decNumberIsZero(op3))
13027         op3->exponent = 127;
13028 
13029     // now write to memory in proper format.....
13030 
13031     int pos = (int) dstCN;
13032 
13033     // 1st, take care of any leading sign .......
13034     switch(e->S2)
13035     {
13036         case CSFL:  // floating-point, leading sign.
13037         case CSLS:  // fixed-point, leading sign
13038             switch(dstTN)
13039             {
13040                 case CTN4:
13041                     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.
13042                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13043                     else
13044                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13045                     break;
13046                 case CTN9:
13047                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13048                     break;
13049             }
13050             break;
13051 
13052         case CSTS:  // nuttin' to do here .....
13053         case CSNS:
13054             break;  // no sign wysiwyg
13055     }
13056 
13057     // 2nd, write the digits .....
13058     for(int i = 0 ; i < n2 ; i++)
13059         switch(dstTN)
13060         {
13061             case CTN4:
13062                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13063                 break;
13064             case CTN9:
13065                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13066                 break;
13067         }
13068 
13069     // 3rd, take care of any trailing sign or exponent ...
13070     switch(e->S2)
13071     {
13072         case CSTS:  // write trailing sign ....
13073             switch(dstTN)
13074             {
13075                 case CTN4:
13076                     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.
13077                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13078                     else
13079                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13080                     break;
13081                 case CTN9:
13082                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13083                     break;
13084             }
13085             break;
13086 
13087         case CSFL:  // floating-point, leading sign.
13088             // write the exponent
13089             switch(dstTN)
13090             {
13091                 case CTN4:
13092                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13093                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13094                     break;
13095                 case CTN9:
13096                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13097                     break;
13098             }
13099             break;
13100 
13101         case CSLS:  // fixed point, leading sign - already done
13102         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13103             break;
13104     }
13105 
13106     // set flags, etc ...
13107     if (e->S2 == CSFL)
13108     {
13109         if (op3->exponent > 127)
13110         {
13111             SET_I_EOFL;
13112             EOvr = true;
13113         }
13114         if (op3->exponent < -128)
13115         {
13116             SET_I_EUFL;
13117             EOvr = true;
13118         }
13119     }
13120 
13121     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13122     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13123 
13124     //SC_I_TRUNC (!R && Trunc); // no truncation flag for divide
13125 
13126     cleanupOperandDescriptor (1);
13127     cleanupOperandDescriptor (2);
13128     cleanupOperandDescriptor (3);
13129 
13130     //if (TST_I_TRUNC && T && tstOVFfault ())
13131     //  doFault(FAULT_OFL, fst_zero, "dv2d truncation(overflow) fault");
13132     if (EOvr && tstOVFfault ())
13133         doFault(FAULT_OFL, fst_zero, "dv2d over/underflow fault");
13134     if (Ovr)
13135     {
13136         SET_I_OFLOW;
13137         if (tstOVFfault ())
13138           doFault(FAULT_OFL, fst_zero, "dv2d overflow fault");
13139     }
13140 }
13141 
13142 /*
13143  * dv3d - Divide Using Three Decimal Operands
13144  */
13145 
13146 void dv3d (void)
     /* [previous][next][first][last][top][bottom][index][help] */
13147 
13148 {
13149     EISstruct * e = & cpu.currentEISinstruction;
13150 
13151     fault_ipr_subtype_ mod_fault = 0;
13152 
13153 #ifndef EIS_SETUP
13154     setupOperandDescriptor(1, &mod_fault);
13155     setupOperandDescriptor(2, &mod_fault);
13156     setupOperandDescriptor(3, &mod_fault);
13157 #endif
13158 
13159     parseNumericOperandDescriptor(1, &mod_fault);
13160     parseNumericOperandDescriptor(2, &mod_fault);
13161     parseNumericOperandDescriptor(3, &mod_fault);
13162 
13163     L68_ (
13164       // L68 raises it immediately
13165       if (mod_fault)
13166         {
13167           doFault (FAULT_IPR,
13168                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13169                    "Illegal modifier");
13170         }
13171     )
13172 
13173     // Bit 1 MBZ
13174     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ
13175     if (IWB_IRODD & 0200400000000)
13176       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv3d(): 1,9 MBZ");
13177 
13178     DPS8M_ (
13179       // DPS8M raises it delayed
13180       if (mod_fault)
13181         {
13182           doFault (FAULT_IPR,
13183                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13184                    "Illegal modifier");
13185         }
13186     )
13187 
13188     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
13189     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
13190     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
13191 
13192     PNL (L68_ (if (R)
13193       DU_CYCLE_FRND;))
13194 
13195     uint srcTN = e->TN1;    // type of chars in src
13196 
13197     uint dstTN = e->TN3;    // type of chars in dst
13198     uint dstCN = e->CN3;    // starting at char pos CN
13199 
13200     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
13201 
13202     /*
13203      * Here we need to distinguish between 4 type of numbers.
13204      *
13205      * CSFL - Floating-point, leading sign
13206      * CSLS - Scaled fixed-point, leading sign
13207      * CSTS - Scaled fixed-point, trailing sign
13208      * CSNS - Scaled fixed-point, unsigned
13209      */
13210 
13211     // determine precision
13212     switch(e->S1)
13213     {
13214         case CSFL:
13215             n1 = (int) e->N1 - 1; // need to account for the - sign
13216             if (srcTN == CTN4)
13217                 n1 -= 2;    // 2 4-bit digits exponent
13218             else
13219                 n1 -= 1;    // 1 9-bit digit exponent
13220             sc1 = 0;        // no scaling factor
13221             break;
13222 
13223         case CSLS:
13224         case CSTS:
13225             n1 = (int) e->N1 - 1; // only 1 sign
13226             sc1 = -e->SF1;
13227             break;
13228 
13229         case CSNS:
13230             n1 = (int) e->N1;     // no sign
13231             sc1 = -e->SF1;
13232             break;  // no sign wysiwyg
13233     }
13234 
13235     if (n1 < 1)
13236         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n1<1");
13237 
13238     switch(e->S2)
13239     {
13240         case CSFL:
13241             n2 = (int) e->N2 - 1; // need to account for the sign
13242             if (e->TN2 == CTN4)
13243                 n2 -= 2;    // 2 4-bit digit exponent
13244             else
13245                 n2 -= 1;    // 1 9-bit digit exponent
13246             sc2 = 0;        // no scaling factor
13247             break;
13248 
13249         case CSLS:
13250         case CSTS:
13251             n2 = (int) e->N2 - 1; // 1 sign
13252             sc2 = -e->SF2;
13253             break;
13254 
13255         case CSNS:
13256             n2 = (int) e->N2;     // no sign
13257             sc2 = -e->SF2;
13258             break;  // no sign wysiwyg
13259     }
13260 
13261     if (n2 < 1)
13262         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n2<1");
13263 
13264     switch(e->S3)
13265     {
13266         case CSFL:
13267             n3 = (int) e->N3 - 1; // need to account for the sign
13268             if (dstTN == CTN4)
13269                 n3 -= 2;    // 2 4-bit digit exponent
13270             else
13271                 n3 -= 1;    // 1 9-bit digit exponent
13272             break;
13273 
13274         case CSLS:
13275         case CSTS:
13276             n3 = (int) e->N3 - 1; // 1 sign
13277             break;
13278 
13279         case CSNS:
13280             n3 = (int) e->N3;     // no sign
13281             break;  // no sign wysiwyg
13282     }
13283     if (n3 < 1)
13284         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n3<1");
13285 
13286     decContext set;
13287     decContextDefaultDPS8(&set);
13288 
13289     set.traps=0;
13290 
13291     decNumber _1, _2, _3;
13292 
13293     EISloadInputBufferNumeric (1);   // according to MF1
13294 
13295     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
13296     //PRINTDEC("op1", op1);
13297     if (e->sign == -1)
13298         op1->bits |= DECNEG;
13299     if (e->S1 == CSFL)
13300         op1->exponent = e->exponent;
13301 
13302     // check for divide by 0!
13303     if (decNumberIsZero(op1))
13304     {
13305         doFault(FAULT_DIV, fst_zero, "dv3d division by 0");
13306     }
13307 
13308     word9   inBufferop1 [64];
13309     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13310 
13311     EISloadInputBufferNumeric (2);   // according to MF2
13312 
13313     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
13314     if (e->sign == -1)
13315         op2->bits |= DECNEG;
13316     if (e->S2 == CSFL)
13317         op2->exponent = e->exponent;
13318 
13319     // The number of required quotient digits, NQ, is determined before
13320     // division begins as follows:
13321     //  1) Floating-point quotient
13322     //      NQ = N3
13323     //  2) Fixed-point quotient
13324     //    NQ = (N2-LZ2+1) - (N1-LZ1) + (E2-E1-SF3)
13325     //    where: Nn = given operand field length
13326     //        LZn = leading zero count for operand n
13327     //        En = exponent of operand n
13328     //        SF3 = scaling factor of quotient
13329     // 3) Rounding
13330     //    If rounding is specified (R = 1), then one extra quotient digit is
13331     //    produced.
13332     // Note: rule 3 is already handled by formatDecimal rounding
13333     // Nn doesn't represent full field length, but length without sign and exponent (RJ78/DH03 seems like)
13334 
13335     int NQ;
13336     if (e->S3 == CSFL)
13337     {
13338         NQ = n3;
13339     }
13340     else
13341     {
13342         // count leading zeroes
13343         // TODO optimize - can these be somehow extracted from decNumbers?
13344         int clz1, clz2, i;
13345         for (i=0; i < op1->digits; i++)
13346             if (inBufferop1[i]!=0)
13347                 break;
13348         clz1 = i;
13349         for (i=0; i < op2->digits; i++)
13350             if (e->inBuffer[i]!=0) // this still holds op2 digits
13351                 break;
13352         clz2 = i;
13353         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: clz1 %d clz2 %d\n",clz1,clz2);
13354 
13355         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13356         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13357         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);
13358 
13359 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);
13360     }
13361     if (NQ > 63)
13362         doFault(FAULT_DIV, fst_zero, "dv3d NQ>63");
13363     // Note: NQ is currently unused apart from this FAULT_DIV check. decNumber produces more digits than required, but they are then rounded/truncated
13364 
13365     // Yes, they're switched. op1=divisor
13366     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13367     // Note DPS88 and DPS9000 are different when NQ <= 0
13368     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13369     // ISOLTS-817 05b
13370 
13371     PRINTDEC("op2", op2);
13372     PRINTDEC("op1", op1);
13373     PRINTDEC("op3", op3);
13374 
13375     // let's check division results to see for anomalous conditions
13376     if (
13377         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13378         (set.status & DEC_Invalid_operation) ||
13379         (set.status & DEC_Division_by_zero)
13380         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv3d anomalous results"); }      // divide by zero has already been checked before
13381 
13382     if (e->S3 == CSFL)
13383     {
13384         // justify CSFL left
13385         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13386         // Note DPS88 and DPS9000 are different
13387         // ISOLTS-817 06c,06e
13388 
13389         decNumber _sf;
13390 
13391         if (n3 - op3->digits > 0)
13392         {
13393             decNumberFromInt32(&_sf, op3->exponent - (n3 - op3->digits));
13394             PRINTDEC("Value 1", op3)
13395             PRINTDEC("Value sf", &_sf)
13396             op3 = decNumberRescale(op3, op3, &_sf, &set);
13397             PRINTDEC("Value 2", op3)
13398         }
13399     }
13400 
13401     bool Ovr = false, EOvr = false, Trunc = false;
13402     uint8_t out[256];
13403 
13404     // CSFL: If the divisor is greater than the dividend after operand
13405     // alignment, the leading zero digit produced is counted and the effective
13406     // precision of the result is reduced by one.
13407     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13408     // Note DPS88 and DPS9000 are different
13409     //
13410     // "greater after operand alignment" means scale until most-significant digits are nonzero, then compare magnitudes ignoring exponents
13411     // This passes ISOLTS-817 06e, ET 458,461,483,486
13412     char *res;
13413     if (e->S3 == CSFL) {
13414         decNumber _1a;
13415         decNumber _2a;
13416         decNumber _sf;
13417         if (op1->digits >= op2->digits) {
13418             // scale op2
13419             decNumberCopy(&_1a, op1);
13420             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13421             decNumberShift(&_2a, op2, &_sf, &set);
13422         } else if (op1->digits < op2->digits) {
13423             // scale op1
13424             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13425             decNumberShift(&_1a, op1, &_sf, &set);
13426             decNumberCopy(&_2a, op2);
13427         }
13428         _1a.exponent = 0;
13429         _2a.exponent = 0;
13430 
13431         PRINTDEC("dv3d: op1a", &_1a);
13432         PRINTDEC("dv3d: op2a", &_2a);
13433         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);
13434 
13435         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13436             // shorten the result field to get proper rounding
13437             res = formatDecimal(out, &set, op3, n3 -1, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13438 
13439             // prepend zero digit
13440             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13441             for (int i = n3; i > 0; i--) // incl.zero terminator
13442                  res[i] = res[i-1];
13443             res[0] = '0';
13444             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: addzero n3 %d %s exp %d\n",n3,res,op3->exponent);
13445         } else {
13446             // full n3 digits are returned
13447             res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13448         }
13449     } else {
13450         // same as all other decimal instructions
13451         res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13452     }
13453 
13454     if (decNumberIsZero(op3))
13455         op3->exponent = 127;
13456 
13457     //printf("%s\r\n", res);
13458 
13459     // now write to memory in proper format.....
13460 
13461     int pos = (int) dstCN;
13462 
13463     // 1st, take care of any leading sign .......
13464     switch(e->S3)
13465     {
13466         case CSFL:  // floating-point, leading sign.
13467         case CSLS:  // fixed-point, leading sign
13468             switch(dstTN)
13469             {
13470                 case CTN4:
13471                     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.
13472                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13473                     else
13474                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13475                     break;
13476                 case CTN9:
13477                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13478                     break;
13479             }
13480             break;
13481 
13482         case CSTS:  // nuttin' to do here .....
13483         case CSNS:
13484             break;  // no sign wysiwyg
13485     }
13486 
13487     // 2nd, write the digits .....
13488     for(int i = 0 ; i < n3 ; i++)
13489         switch(dstTN)
13490         {
13491             case CTN4:
13492                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13493                 break;
13494             case CTN9:
13495                 EISwrite49(&e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13496                 break;
13497             }
13498 
13499     // 3rd, take care of any trailing sign or exponent ...
13500     switch(e->S3)
13501     {
13502         case CSTS:  // write trailing sign ....
13503             switch(dstTN)
13504             {
13505                 case CTN4:
13506                     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.
13507                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13508                     else
13509                         EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13510                     break;
13511                 case CTN9:
13512                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13513                 break;
13514             }
13515             break;
13516 
13517         case CSFL:  // floating-point, leading sign.
13518             // write the exponent
13519             switch(dstTN)
13520             {
13521                 case CTN4:
13522                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13523                     EISwrite49(&e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13524                     break;
13525                 case CTN9:
13526                     EISwrite49(&e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13527                     break;
13528             }
13529             break;
13530 
13531         case CSLS:  // fixed point, leading sign - already done
13532         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13533             break;
13534     }
13535 
13536     // set flags, etc ...
13537     if (e->S3 == CSFL)
13538     {
13539         if (op3->exponent > 127)
13540         {
13541             SET_I_EOFL;
13542             EOvr = true;
13543         }
13544         if (op3->exponent < -128)
13545         {
13546             SET_I_EUFL;
13547             EOvr = true;
13548         }
13549     }
13550 
13551     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13552     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13553 
13554     // SC_I_TRUNC(!R && Trunc); // no truncation flag for divide
13555 
13556     cleanupOperandDescriptor (1);
13557     cleanupOperandDescriptor (2);
13558     cleanupOperandDescriptor (3);
13559 
13560     //if (TST_I_TRUNC && T && tstOVFfault ())
13561     //  doFault(FAULT_OFL, fst_zero, "dv3d truncation(overflow) fault");
13562     if (EOvr && tstOVFfault ())
13563         doFault(FAULT_OFL, fst_zero, "dv3d over/underflow fault");
13564     if (Ovr)
13565     {
13566         SET_I_OFLOW;
13567         if (tstOVFfault ())
13568           doFault(FAULT_OFL, fst_zero, "dv3d overflow fault");
13569     }
13570 }

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