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-2024 The DPS8M Development Team
  15  *
  16  * This software is made available under the terms of the ICU License.
  17  * See the LICENSE.md file at the top-level directory of this distribution.
  18  *
  19  * ---------------------------------------------------------------------------
  20  *
  21  * This source file may contain code comments that adapt, include, and/or
  22  * incorporate Multics program code and/or documentation distributed under
  23  * the Multics License.  In the event of any discrepancy between code
  24  * comments herein and the original Multics materials, the original Multics
  25  * materials should be considered authoritative unless otherwise noted.
  26  * For more details and historical background, see the LICENSE.md file at
  27  * the top-level directory of this distribution.
  28  *
  29  * ---------------------------------------------------------------------------
  30  */
  31 
  32 #if defined(EIS_PTR)
  33 // Cached operand data...
  34 //  Alphanumeric Operand
  35 //    Address 18 bits  --> DkW
  36 //    CN 3 bits --> DkB
  37 //    TA 2 bits
  38 //    Length 12 bits
  39 //  Numeric Operand
  40 //    Address 18 bits  --> DkW
  41 //    CN 3 bits --> DkB
  42 //    TN 1 bits
  43 //    S  2 bits
  44 //    SF 6 bits
  45 //    Length 6 bits
  46 //  Bit-string Operand
  47 //    Address 18 bits  --> DkW
  48 //    C  2 bits --> DkB
  49 //    B  4 bits --> DkB
  50 //    Length 12 bits
  51 #endif /* defined(EIS_PTR) */
  52 
  53 #include <ctype.h>
  54 
  55 #include "dps8.h"
  56 #include "dps8_sys.h"
  57 #include "dps8_iom.h"
  58 #include "dps8_cable.h"
  59 #include "dps8_cpu.h"
  60 #include "dps8_faults.h"
  61 #include "dps8_scu.h"
  62 #include "dps8_iefp.h"
  63 #include "dps8_decimal.h"
  64 #include "dps8_ins.h"
  65 #include "dps8_eis.h"
  66 #include "dps8_utils.h"
  67 
  68 #define DBG_CTR cpu.cycleCnt
  69 
  70 //  Restart status
  71 //
  72 //  a6bd   n/a
  73 //  a4bd   n/a
  74 //  a9bd   n/a
  75 //  abd    n/a
  76 //  awd    n/a
  77 //  s4bd   n/a
  78 //  s6bd   n/a
  79 //  s9bd   n/a
  80 //  sbd    n/a
  81 //  swd    n/a
  82 //  cmpc   done
  83 //  scd    done
  84 //  scdr   done
  85 //  scm    done
  86 //  scmr   done
  87 //  tct    done
  88 //  tctr   done
  89 //  mlr    done
  90 //  mrl    done
  91 //  mve
  92 //  mvne
  93 //  mvt    done
  94 //  cmpn
  95 //  mvn
  96 //  csl    done
  97 //  csr    done
  98 //  cmpb
  99 //  btd
 100 //  dtb
 101 //  ad2d
 102 //  ad3d
 103 //  sb2d
 104 //  sb3d
 105 //  mp2d
 106 //  mp3d
 107 //  dv2d
 108 //  dv3d
 109 
 110 // Local optimization
 111 #define ABD_BITS
 112 
 113 // Enable EIS operand setup refactoring code -- crashes Multics late in boot.
 114 //#define EIS_SETUP
 115 
 116 //  EISWriteCache  -- flush the cache
 117 //
 118 //
 119 //  EISWriteIdx (cpup, p, n, data, flush); -- write to cache at p->addr [n];
 120 //  EISRead (cpup, p) -- read to cache from p->addr
 121 //  EISReadIdx (cpup, p, n)  -- read to cache from p->addr[n];
 122 //  EISReadN (p, n, dst) -- read N words to dst;
 123 
 124 //  EISget469 (cpup, k, i)
 125 //  EISput469 (cpup, k, i, c)
 126 
 127 //  EISget49 (cpup, k, *pos, tn) get p->addr[*pos++]
 128 
 129 // AL39, Figure 2-3
 130 static word4 get4 (word36 w, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
 131   {
 132     switch (pos)
 133       {
 134         case 0:
 135           return getbits36_4 (w, 1);
 136 
 137         case 1:
 138           return getbits36_4 (w, 5);
 139 
 140         case 2:
 141           return getbits36_4 (w, 10);
 142 
 143         case 3:
 144           return getbits36_4 (w, 14);
 145 
 146         case 4:
 147           return getbits36_4 (w, 19);
 148 
 149         case 5:
 150           return getbits36_4 (w, 23);
 151 
 152         case 6:
 153           return getbits36_4 (w, 28);
 154 
 155         case 7:
 156           return getbits36_4 (w, 32);
 157 
 158       }
 159     sim_printf ("get4(): How'd we get here?\n");
 160     return 0;
 161 }
 162 
 163 // AL39, Figure 2-4
 164 static word4 get6 (word36 w, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
 165   {
 166     switch (pos)
 167       {
 168         case 0:
 169          return getbits36_6 (w, 0);
 170 
 171         case 1:
 172          return getbits36_6 (w, 6);
 173 
 174         case 2:
 175          return getbits36_6 (w, 12);
 176 
 177         case 3:
 178          return getbits36_6 (w, 18);
 179 
 180         case 4:
 181          return getbits36_6 (w, 24);
 182 
 183         case 5:
 184          return getbits36_6 (w, 30);
 185 
 186       }
 187     sim_printf ("get6(): How'd we get here?\n");
 188     return 0;
 189   }
 190 
 191 // AL39, Figure 2-5
 192 static word9 get9(word36 w, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
 193   {
 194     switch (pos)
 195       {
 196         case 0:
 197          return getbits36_9 (w, 0);
 198 
 199         case 1:
 200          return getbits36_9 (w, 9);
 201 
 202         case 2:
 203          return getbits36_9 (w, 18);
 204 
 205         case 3:
 206          return getbits36_9 (w, 27);
 207 
 208       }
 209     sim_printf ("get9(): How'd we get here?\n");
 210     return 0;
 211   }
 212 
 213 // AL39, Figure 2-3
 214 static word36 put4 (word36 w, int pos, word4 c)
     /* [previous][next][first][last][top][bottom][index][help] */
 215   {
 216 // AL-39 pg 13: "The 0 bits at it positions 0, 9, 18, and 27 are forced to be 0
 217 // by the processor on data transfers to main memory ..."
 218 //
 219 // The code uses 5 bit sets for the even bytes to force the 0 writes.
 220 
 221     c &= MASK4;
 222     switch (pos)
 223       {
 224         case 0:
 225           //return setbits36_4 (w, 1, c);
 226           return setbits36_5 (w, 0, c);
 227 
 228         case 1:
 229           return setbits36_4 (w, 5, c);
 230 
 231         case 2:
 232           //return setbits36_4 (w, 10, c);
 233           return setbits36_5 (w, 9, c);
 234 
 235         case 3:
 236           return setbits36_4 (w, 14, c);
 237 
 238         case 4:
 239           //return setbits36_4 (w, 19, c);
 240           return setbits36_5 (w, 18, c);
 241 
 242         case 5:
 243           return setbits36_4 (w, 23, c);
 244 
 245         case 6:
 246           //return setbits36_4 (w, 28, c);
 247           return setbits36_5 (w, 27, c);
 248 
 249         case 7:
 250           return setbits36_4 (w, 32, c);
 251       }
 252     sim_printf ("put4(): How'd we get here?\n");
 253     return 0;
 254   }
 255 
 256 // AL39, Figure 2-4
 257 static word36 put6 (word36 w, int pos, word6 c)
     /* [previous][next][first][last][top][bottom][index][help] */
 258   {
 259     switch (pos)
 260       {
 261         case 0:
 262           //return bitfieldInsert36 (w, c, 30, 6);
 263           return setbits36_6 (w, 0, c);
 264 
 265         case 1:
 266           //`return bitfieldInsert36 (w, c, 24, 6);
 267           return setbits36_6 (w, 6, c);
 268 
 269         case 2:
 270           //return bitfieldInsert36 (w, c, 18, 6);
 271           return setbits36_6 (w, 12, c);
 272 
 273         case 3:
 274           //return bitfieldInsert36 (w, c, 12, 6);
 275           return setbits36_6 (w, 18, c);
 276 
 277         case 4:
 278           //return bitfieldInsert36 (w, c, 6, 6);
 279           return setbits36_6 (w, 24, c);
 280 
 281         case 5:
 282           //return bitfieldInsert36 (w, c, 0, 6);
 283           return setbits36_6 (w, 30, c);
 284 
 285       }
 286     sim_printf ("put6(): How'd we get here?\n");
 287     return 0;
 288   }
 289 
 290 // AL39, Figure 2-5
 291 static word36 put9 (word36 w, int pos, word9 c)
     /* [previous][next][first][last][top][bottom][index][help] */
 292   {
 293     switch (pos)
 294       {
 295         case 0:
 296           //return bitfieldInsert36 (w, c, 27, 9);
 297           return setbits36_9 (w, 0, c);
 298 
 299         case 1:
 300           //return bitfieldInsert36 (w, c, 18, 9);
 301           return setbits36_9 (w, 9, c);
 302 
 303         case 2:
 304           //return bitfieldInsert36 (w, c, 9, 9);
 305           return setbits36_9 (w, 18, c);
 306 
 307         case 3:
 308           //return bitfieldInsert36 (w, c, 0, 9);
 309           return setbits36_9 (w, 27, c);
 310 
 311       }
 312     sim_printf ("put9(): How'd we get here?\n");
 313     return 0;
 314   }
 315 
 316 /*
 317  * get register value indicated by reg for Address Register operations
 318  * (not for use with address modifications)
 319  */
 320 
 321 static word36 getCrAR (cpu_state_t * cpup, word4 reg)
     /* [previous][next][first][last][top][bottom][index][help] */
 322   {
 323     if (reg == 0)
 324       return 0;
 325 
 326     if (reg & 010) /* Xn */
 327       return cpu.rX [X (reg)];
 328 
 329     switch (reg)
 330       {
 331         case TD_N:
 332           return 0;
 333 
 334         case TD_AU: // C(A)0,17
 335 #if defined(TESTING)
 336           HDBGRegAR ("au");
 337 #endif
 338           return GETHI (cpu.rA);
 339 
 340         case TD_QU: //  C(Q)0,17
 341 #if defined(TESTING)
 342           HDBGRegAR ("qu");
 343 #endif
 344           return GETHI (cpu.rQ);
 345 
 346         case TD_IC: // C(PPR.IC)
 347           return cpu.PPR.IC;
 348 
 349         case TD_AL: // C(A)18,35
 350 #if defined(TESTING)
 351           HDBGRegAR ("al");
 352 #endif
 353           return cpu.rA; // See AL36, Table 4-1
 354 
 355         case TD_QL: // C(Q)18,35
 356 #if defined(TESTING)
 357           HDBGRegAR ("ql");
 358 #endif
 359           return cpu.rQ; // See AL36, Table 4-1
 360       }
 361     return 0;
 362   }
 363 
 364 // getMFReg
 365 //  RType reflects the AL-39 R-type and C(op. desc.)32,35 columns
 366 //
 367 //  Table 4-1. R-type Modifiers for REG Fields
 368 //
 369 //                   Meaning as used in:
 370 //
 371 //  Octal  R-type  MF.REG   Indirect operand    C(operand descriptor)32,35
 372 //  Code                    descriptor-pointer
 373 //  00         n       n          n                      IPR
 374 //  01        au      au          au                      au
 375 //  02        qu      qu          qu                      qu
 376 //  03        du     IPR         IPR                      du (a)
 377 //  04        ic      ic          ic                      ic (b)
 378 //  05        al       a (c)      al                       a (c)
 379 //  06        ql       q (c)      ql                       a (c)
 380 //  07        dl     IPR         IPR                     IPR
 381 //  1n        xn      xn          xn                      xn
 382 //
 383 
 384 static word18 getMFReg18 (cpu_state_t * cpup, uint n, bool allowDU, bool allowNIC, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
 385   {
 386     switch (n)
 387       {
 388         case 0: // n
 389           if (! allowNIC)
 390             {
 391               //sim_printf ("getMFReg18 n\n");
 392               *mod_fault |= FR_ILL_MOD;
 393               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 n");
 394             }
 395           return 0;
 396 
 397         case 1: // au
 398 #if defined(TESTING)
 399           HDBGRegAR ("au");
 400 #endif
 401           return GETHI (cpu.rA);
 402 
 403         case 2: // qu
 404 #if defined(TESTING)
 405           HDBGRegAR ("qu");
 406 #endif
 407           return GETHI (cpu.rQ);
 408 
 409         case 3: // du
 410           // du is a special case for SCD, SCDR, SCM, and SCMR
 411 // XXX needs attention; doesn't work with old code; triggered by
 412 // XXX parseOperandDescriptor;
 413           if (! allowDU)
 414             {
 415 
 416 
 417 
 418 
 419 
 420 
 421 
 422 
 423 
 424 
 425 
 426 
 427               //sim_printf ("getMFReg18 du\n");
 428               *mod_fault |= FR_ILL_MOD;
 429               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 du");
 430             }
 431           return 0;
 432 
 433         case 4: // ic - The ic modifier is permitted in
 434                 // C (od)32,35 only if MFk.RL = 0, that is, if the contents of
 435                 // the register is an address offset, not the designation of
 436                 // a register containing the operand length.
 437                 // 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
 438           if (! allowNIC)
 439             {
 440               //sim_printf ("getMFReg18 n\n");
 441               *mod_fault |= FR_ILL_MOD;
 442               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 ic");
 443             }
 444           return cpu.PPR.IC;
 445 
 446         case 5: // al / a
 447 #if defined(TESTING)
 448           HDBGRegAR ("al/a");
 449 #endif
 450           return GETLO (cpu.rA);
 451 
 452         case 6: // ql / a
 453 #if defined(TESTING)
 454           HDBGRegAR ("ql/a");
 455 #endif
 456           return GETLO (cpu.rQ);
 457 
 458         case 7: // dl
 459           *mod_fault |= FR_ILL_MOD;
 460           //doFault (FAULT_IPR, fst_ill_mod, "getMFReg18 dl");
 461           return 0;
 462 
 463         case 8:
 464         case 9:
 465         case 10:
 466         case 11:
 467         case 12:
 468         case 13:
 469         case 14:
 470         case 15:
 471           return cpu.rX [n - 8];
 472       }
 473     sim_printf ("getMFReg18(cpup, ): How'd we get here? n=%d\n", n);
 474     return 0;
 475   }
 476 
 477 static word36 getMFReg36 (cpu_state_t * cpup, uint n, bool allowDU, bool allowNIC, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
 478   {
 479     switch (n)
 480       {
 481         case 0: // n
 482          if (! allowNIC)
 483            {
 484              //sim_printf ("getMFReg36 n\n");
 485              *mod_fault |= FR_ILL_MOD;
 486              //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 n");
 487            }
 488           return 0;
 489         case 1: // au
 490 #if defined(TESTING)
 491           HDBGRegAR ("au");
 492 #endif
 493           return GETHI (cpu.rA);
 494 
 495         case 2: // qu
 496 #if defined(TESTING)
 497           HDBGRegAR ("qu");
 498 #endif
 499           return GETHI (cpu.rQ);
 500 
 501         case 3: // du
 502           // du is a special case for SCD, SCDR, SCM, and SCMR
 503           if (! allowDU)
 504            *mod_fault |= FR_ILL_MOD;
 505            //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 du");
 506           return 0;
 507 
 508         case 4: // ic - The ic modifier is permitted in MFk.REG and
 509                 // C (od)32,35 only if MFk.RL = 0, that is, if the contents of
 510                 // the register is an address offset, not the designation of
 511                 // a register containing the operand length.
 512                 // 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
 513           if (! allowNIC)
 514             {
 515               //sim_printf ("getMFReg36 n\n");
 516               *mod_fault |= FR_ILL_MOD;
 517               //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 ic");
 518             }
 519           return cpu.PPR.IC;
 520 
 521         case 5: // al / a
 522 #if defined(TESTING)
 523           HDBGRegAR ("al/a");
 524 #endif
 525           return cpu.rA;
 526 
 527         case 6: // ql / a
 528 #if defined(TESTING)
 529           HDBGRegAR ("ql/a");
 530 #endif
 531             return cpu.rQ;
 532 
 533         case 7: // dl
 534              *mod_fault |= FR_ILL_MOD;
 535              //doFault (FAULT_IPR, fst_ill_mod, "getMFReg36 dl");
 536              return 0;
 537 
 538         case 8:
 539         case 9:
 540         case 10:
 541         case 11:
 542         case 12:
 543         case 13:
 544         case 14:
 545         case 15:
 546             return cpu.rX [n - 8];
 547       }
 548     sim_printf ("getMFReg36(cpup, ): How'd we get here? n=%d\n", n);
 549     return 0;
 550   }
 551 
 552 #define EISADDR_IDX(p) ((p) - cpu.currentEISinstruction.addr)
 553 
 554 static void EISWriteCache (cpu_state_t * cpup, EISaddr * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 555   {
 556     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISWriteCache addr %06o\n", p->cachedAddr);
 557     word3 saveTRR = cpu.TPR.TRR;
 558 
 559     if (p -> cacheValid && p -> cacheDirty)
 560       {
 561         if (p -> mat == viaPR)
 562           {
 563             cpu.TPR.TRR = p -> RNR;
 564             cpu.TPR.TSR = p -> SNR;
 565             cpu.cu.XSF = 0;
 566             if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 567               {
 568                 for (uint i = 0; i < 8; i ++)
 569                   if (p->wordDirty[i])
 570                     {
 571                   sim_debug (DBG_TRACEEXT, & cpu_dev,
 572                              "%s: writeCache (PR) %012"PRIo64"@%o:%06o\n",
 573                              __func__, p -> cachedParagraph [i], p -> SNR, p -> cachedAddr + i);
 574                    }
 575               }
 576 { long eisaddr_idx = EISADDR_IDX (p);
 577 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Write8 TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 578             for (uint i = 0; i < 8; i ++)
 579               if (p->wordDirty[i])
 580                 {
 581                   Write1 (cpup, p->cachedAddr+i, p -> cachedParagraph[i], true);
 582                   p->wordDirty[i] = false;
 583                 }
 584           }
 585         else
 586           {
 587             //if (get_addr_mode() == APPEND_mode)
 588               //{
 589             cpu.TPR.TRR = cpu.PPR.PRR;
 590             cpu.TPR.TSR = cpu.PPR.PSR;
 591             cpu.cu.XSF = 0;
 592               //}
 593 
 594             if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 595               {
 596                 for (uint i = 0; i < 8; i ++)
 597                   if (p->wordDirty[i])
 598                     {
 599                   sim_debug (DBG_TRACEEXT, & cpu_dev,
 600                              "%s: writeCache %012"PRIo64"@%o:%06o\n",
 601                              __func__, p -> cachedParagraph [i], cpu.TPR.TSR, p -> cachedAddr + i);
 602                      }
 603               }
 604 { long eisaddr_idx = EISADDR_IDX (p);
 605 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Write8 NO PR TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 606             for (uint i = 0; i < 8; i ++)
 607               if (p->wordDirty[i])
 608                 {
 609                   Write1 (cpup, p->cachedAddr+i, p -> cachedParagraph[i], false);
 610                   p->wordDirty[i] = false;
 611                 }
 612           }
 613       }
 614     p -> cacheDirty = false;
 615     cpu.TPR.TRR = saveTRR;
 616   }
 617 
 618 static void EISReadCache (cpu_state_t * cpup, EISaddr * p, word18 address)
     /* [previous][next][first][last][top][bottom][index][help] */
 619   {
 620     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadCache addr %06o\n", address);
 621     word3 saveTRR = cpu.TPR.TRR;
 622 
 623     address &= AMASK;
 624 
 625     word18 paragraphAddress = address & paragraphMask;
 626     //word3 paragraphOffset = address & paragraphOffsetMask;
 627 
 628     if (p -> cacheValid && p -> cachedAddr == paragraphAddress)
 629       {
 630         return;
 631       }
 632 
 633     if (p -> cacheValid && p -> cacheDirty && p -> cachedAddr != paragraphAddress)
 634       {
 635         EISWriteCache (cpup, p);
 636       }
 637 
 638     if (p -> mat == viaPR)
 639       {
 640         cpu.TPR.TRR = p -> RNR;
 641         cpu.TPR.TSR = p -> SNR;
 642         cpu.cu.XSF = 0;
 643 { long eisaddr_idx = EISADDR_IDX (p);
 644 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Read8 TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 645         Read8 (cpup, paragraphAddress, p -> cachedParagraph, true);
 646 
 647         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 648           {
 649             for (uint i = 0; i < 8; i ++)
 650               sim_debug (DBG_TRACEEXT, & cpu_dev,
 651                          "%s: readCache (PR) %012"PRIo64"@%o:%06o\n",
 652                            __func__, p -> cachedParagraph [i], p -> SNR, paragraphAddress + i);
 653           }
 654       }
 655     else
 656       {
 657         //if (get_addr_mode() == APPEND_mode)
 658           //{
 659         cpu.TPR.TRR = cpu.PPR.PRR;
 660         cpu.TPR.TSR = cpu.PPR.PSR;
 661         cpu.cu.XSF = 0;
 662           //}
 663 
 664 { long eisaddr_idx = EISADDR_IDX (p);
 665 sim_debug (DBG_TRACEEXT, & cpu_dev, "EIS %ld Read8 NO PR TRR %o TSR %05o\n", eisaddr_idx, cpu.TPR.TRR, cpu.TPR.TSR); }
 666         Read8 (cpup, paragraphAddress, p -> cachedParagraph, false);
 667         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 668           {
 669             for (uint i = 0; i < 8; i ++)
 670               sim_debug (DBG_TRACEEXT, & cpu_dev,
 671                          "%s: readCache %012"PRIo64"@%o:%06o\n",
 672                          __func__, p -> cachedParagraph [i], cpu.TPR.TSR, paragraphAddress + i);
 673           }
 674       }
 675     p -> cacheValid = true;
 676     p -> cacheDirty = false;
 677     for (uint i = 0; i < 8; i ++)
 678       p->wordDirty[i] = false;
 679     p -> cachedAddr = paragraphAddress;
 680     cpu.TPR.TRR = saveTRR;
 681   }
 682 
 683 static void EISWriteIdx (cpu_state_t * cpup, EISaddr *p, uint n, word36 data, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
 684 {
 685 #if defined(EIS_PTR)
 686     long eisaddr_idx = EISADDR_IDX (p);
 687 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 688     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISWriteIdx addr %06o n %u\n", cpu.du.Dk_PTR_W[eisaddr_idx], n);
 689     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 690 #else
 691     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISWriteIdx addr %06o n %u\n", p->address, n);
 692     word18 addressN = p -> address + n;
 693 #endif
 694     addressN &= AMASK;
 695 
 696     word18 paragraphAddress = addressN & paragraphMask;
 697     word3 paragraphOffset = addressN & paragraphOffsetMask;
 698 
 699     if (p -> cacheValid && p -> cacheDirty && p -> cachedAddr != paragraphAddress)
 700       {
 701         EISWriteCache (cpup, p);
 702       }
 703     if ((! p -> cacheValid) || p -> cachedAddr != paragraphAddress)
 704       {
 705         EISReadCache (cpup, p, paragraphAddress);
 706       }
 707     p -> cacheDirty = true;
 708     p -> wordDirty[paragraphOffset] = true;
 709     p -> cachedParagraph [paragraphOffset] = data;
 710     p -> cachedAddr = paragraphAddress;
 711     // This a little brute force; if we fault on the next read, the cached value
 712     // is lost. There might be a way to logic it up so that when the next read
 713     // word offset changes, then we write the cache before doing the read. For
 714     // right now, be pessimistic.
 715     if (flush)
 716       {
 717         EISWriteCache (cpup, p);
 718       }
 719 }
 720 
 721 static word36 EISReadIdx (cpu_state_t * cpup, EISaddr * p, uint n)
     /* [previous][next][first][last][top][bottom][index][help] */
 722   {
 723 #if defined(EIS_PTR)
 724     long eisaddr_idx = EISADDR_IDX (p);
 725 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 726 
 727     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadIdx addr %06o n %u\n", cpu.du.Dk_PTR_W[eisaddr_idx], n);
 728     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 729 #else
 730     long eisaddr_idx = EISADDR_IDX (p);
 731     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISReadIdx %ld addr %06o n %u\n", eisaddr_idx, p->address, n);
 732     word18 addressN = p -> address + n;
 733 #endif
 734     addressN &= AMASK;
 735 
 736     word18 paragraphAddress = addressN & paragraphMask;
 737     word3 paragraphOffset = addressN & paragraphOffsetMask;
 738 
 739     if (p -> cacheValid && p -> cachedAddr == paragraphAddress)
 740       {
 741         return p -> cachedParagraph [paragraphOffset];
 742       }
 743     if (p -> cacheValid && p -> cacheDirty)
 744       {
 745         EISWriteCache (cpup, p);
 746       }
 747     EISReadCache (cpup, p, paragraphAddress);
 748     return p -> cachedParagraph [paragraphOffset];
 749   }
 750 
 751 static word36 EISRead (cpu_state_t * cpup, EISaddr * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 752   {
 753 #if defined(EIS_PTR)
 754     long eisaddr_idx = EISADDR_IDX (p);
 755 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 756 
 757     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISRead addr %06o\n", cpu.du.Dk_PTR_W[eisaddr_idx]);
 758 #else
 759     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISRead addr %06o\n", p->address);
 760 #endif
 761     return EISReadIdx (cpup, p, 0);
 762   }
 763 
 764 
 765 
 766 
 767 
 768 
 769 
 770 
 771 
 772 
 773 
 774 
 775 
 776 
 777 
 778 
 779 
 780 
 781 static void EISReadPage (cpu_state_t * cpup, EISaddr * p, uint n, word36 * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 782   {
 783 #if defined(EIS_PTR)
 784     long eisaddr_idx = EISADDR_IDX (p);
 785 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 786     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 787 #else
 788     word18 addressN = p -> address + n;
 789 #endif
 790     addressN &= AMASK;
 791 
 792     sim_debug (DBG_TRACEEXT, & cpu_dev, "%s addr %06o\n", __func__, addressN);
 793     if ((addressN & PGMK) != 0)
 794       {
 795         sim_warn ("EISReadPage not aligned %06o\n", addressN);
 796         addressN &= (word18) ~PGMK;
 797       }
 798 
 799     word3 saveTRR = cpu.TPR.TRR;
 800 
 801     if (p -> mat == viaPR)
 802       {
 803         cpu.TPR.TRR = p -> RNR;
 804         cpu.TPR.TSR = p -> SNR;
 805         cpu.cu.XSF = 0;
 806         ReadPage (cpup, addressN, data, true);
 807 
 808         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 809           {
 810             for (uint i = 0; i < PGSZ; i ++)
 811 #if defined(EIS_PTR)
 812               sim_debug (DBG_TRACEEXT, & cpu_dev,
 813                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 814                            __func__, data [i], cpu.TPR.TSR, addressN + i);
 815 #else
 816               sim_debug (DBG_TRACEEXT, & cpu_dev,
 817                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 818                            __func__, data [i], p -> SNR, addressN + i);
 819 #endif
 820           }
 821       }
 822     else
 823       {
 824         //if (get_addr_mode() == APPEND_mode)
 825           //{
 826         cpu.TPR.TRR = cpu.PPR.PRR;
 827         cpu.TPR.TSR = cpu.PPR.PSR;
 828         cpu.cu.XSF = 0;
 829           //}
 830 
 831         ReadPage (cpup, addressN, data, false);
 832         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 833           {
 834             for (uint i = 0; i < PGSZ; i ++)
 835               sim_debug (DBG_TRACEEXT, & cpu_dev,
 836                          "%s: %012"PRIo64"@%o:%06o\n",
 837                          __func__, data [i], cpu.TPR.TSR, addressN + i);
 838           }
 839       }
 840     cpu.TPR.TRR = saveTRR;
 841   }
 842 
 843 static void EISWritePage (cpu_state_t * cpup, EISaddr * p, uint n, word36 * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 844   {
 845 #if defined(EIS_PTR)
 846     long eisaddr_idx = EISADDR_IDX (p);
 847 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
 848     word18 addressN = (cpu.du.Dk_PTR_W[eisaddr_idx] + n) & AMASK;
 849 #else
 850     word18 addressN = p -> address + n;
 851 #endif
 852     addressN &= AMASK;
 853 
 854     sim_debug (DBG_TRACEEXT, & cpu_dev, "%s addr %06o\n", __func__, addressN);
 855     if ((addressN & PGMK) != 0)
 856       {
 857         sim_warn ("EISWritePage not aligned %06o\n", addressN);
 858         addressN &= (uint) ~PGMK;
 859       }
 860 
 861     word3 saveTRR = cpu.TPR.TRR;
 862 
 863     if (p -> mat == viaPR)
 864       {
 865         cpu.TPR.TRR = p -> RNR;
 866         cpu.TPR.TSR = p -> SNR;
 867         cpu.cu.XSF = 0;
 868         WritePage (cpup, addressN, data, true);
 869 
 870         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 871           {
 872             for (uint i = 0; i < PGSZ; i ++)
 873 #if defined(EIS_PTR)
 874               sim_debug (DBG_TRACEEXT, & cpu_dev,
 875                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 876                            __func__, data [i], cpu.TPR.TSR, addressN + i);
 877 #else
 878               sim_debug (DBG_TRACEEXT, & cpu_dev,
 879                          "%s: (PR) %012"PRIo64"@%o:%06o\n",
 880                            __func__, data [i], p -> SNR, addressN + i);
 881 #endif
 882           }
 883       }
 884     else
 885       {
 886         //if (get_addr_mode() == APPEND_mode)
 887           //{
 888         cpu.TPR.TRR = cpu.PPR.PRR;
 889         cpu.TPR.TSR = cpu.PPR.PSR;
 890         cpu.cu.XSF = 0;
 891           //}
 892 
 893         WritePage (cpup, addressN, data, false);
 894         if_sim_debug (DBG_TRACEEXT, & cpu_dev)
 895           {
 896             for (uint i = 0; i < PGSZ; i ++)
 897               sim_debug (DBG_TRACEEXT, & cpu_dev,
 898                          "%s: %012"PRIo64"@%o:%06o\n",
 899                          __func__, data [i], cpu.TPR.TSR, addressN + i);
 900           }
 901       }
 902     cpu.TPR.TRR = saveTRR;
 903   }
 904 
 905 static word9 EISget469 (cpu_state_t * cpup, int k, uint i)
     /* [previous][next][first][last][top][bottom][index][help] */
 906   {
 907     EISstruct * e = & cpu.currentEISinstruction;
 908 
 909     uint nPos = 4; // CTA9
 910 #if defined(EIS_PTR3)
 911     switch (cpu.du.TAk[k-1])
 912 #else
 913     switch (e -> TA [k - 1])
 914 #endif
 915       {
 916         case CTA4:
 917             nPos = 8;
 918             break;
 919 
 920         case CTA6:
 921             nPos = 6;
 922             break;
 923       }
 924 
 925     word18 address = e -> WN [k - 1];
 926     uint nChars = i + e -> CN [k - 1];
 927 
 928     address += nChars / nPos;
 929     uint residue = nChars % nPos;
 930 
 931     PNL (cpu.du.Dk_PTR_W[k-1] = address);
 932 #if defined(EIS_PTR)
 933     cpu.du.Dk_PTR_W[k-1] = address;
 934 #else
 935     e -> addr [k - 1].address = address;
 936 #endif
 937     word36 data = EISRead (cpup, & e -> addr [k - 1]);    // read it from memory
 938 
 939     word9 c = 0;
 940 #if defined(EIS_PTR3)
 941     switch (cpu.du.TAk[k-1])
 942 #else
 943     switch (e -> TA [k - 1])
 944 #endif
 945       {
 946         case CTA4:
 947           c = (word9) get4 (data, (int) residue);
 948           break;
 949 
 950         case CTA6:
 951           c = (word9) get6 (data, (int) residue);
 952           break;
 953 
 954         case CTA9:
 955           c = get9 (data, (int) residue);
 956           break;
 957       }
 958 #if defined(EIS_PTR3)
 959     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISGet469 : k: %u TAk %u coffset %u c %o \n", k, cpu.du.TAk[k - 1], residue, c);
 960 #else
 961     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISGet469 : k: %u TAk %u coffset %u c %o \n", k, e -> TA [k - 1], residue, c);
 962 #endif
 963 
 964     return c;
 965   }
 966 
 967 static void EISput469 (cpu_state_t * cpup, int k, uint i, word9 c469)
     /* [previous][next][first][last][top][bottom][index][help] */
 968   {
 969     EISstruct * e = & cpu.currentEISinstruction;
 970 
 971     uint nPos = 4; // CTA9
 972 #if defined(EIS_PTR3)
 973     switch (cpu.du.TAk[k-1])
 974 #else
 975     switch (e -> TA [k - 1])
 976 #endif
 977       {
 978         case CTA4:
 979           nPos = 8;
 980           break;
 981 
 982         case CTA6:
 983           nPos = 6;
 984           break;
 985       }
 986 
 987     word18 address = e -> WN [k - 1];
 988     uint nChars = i + e -> CN [k - 1];
 989 
 990     address += nChars / nPos;
 991     uint residue = nChars % nPos;
 992 
 993     PNL (cpu.du.Dk_PTR_W[k-1] = address);
 994 #if defined(EIS_PTR)
 995     cpu.du.Dk_PTR_W[k-1] = address;
 996 #else
 997     e -> addr [k - 1].address = address;
 998 #endif
 999     word36 data = EISRead (cpup, & e -> addr [k - 1]);    // read it from memory
1000 
1001     word36 w = 0;
1002 #if defined(EIS_PTR3)
1003     switch (cpu.du.TAk[k-1])
1004 #else
1005     switch (e -> TA [k - 1])
1006 #endif
1007       {
1008         case CTA4:
1009           w = put4 (data, (int) residue, (word4) c469);
1010           break;
1011 
1012         case CTA6:
1013           w = put6 (data, (int) residue, (word6) c469);
1014           break;
1015 
1016         case CTA9:
1017           w = put9 (data, (int) residue, c469);
1018           break;
1019       }
1020     EISWriteIdx (cpup, & e -> addr [k - 1], 0, w, true);
1021   }
1022 
1023 /*
1024  * return a 4- or 9-bit character at memory "*address" and position "*pos".
1025  * Increment pos (and address if necessary)
1026  */
1027 
1028 static word9 EISget49 (cpu_state_t * cpup, EISaddr * p, int * pos, int tn)
     /* [previous][next][first][last][top][bottom][index][help] */
1029   {
1030     int maxPos = tn == CTN4 ? 7 : 3;
1031 
1032     if (* pos > maxPos)        // overflows to next word?
1033       {   // yep....
1034         * pos = 0;        // reset to 1st byte
1035         // bump source to next address
1036 #if defined(EIS_PTR)
1037         long eisaddr_idx = EISADDR_IDX (p);
1038 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
1039         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;
1040 #else
1041         p -> address = (p -> address + 1) & AMASK;
1042 #endif
1043         p -> data = EISRead (cpup, p);    // read it from memory
1044       }
1045     else
1046       {
1047         p -> data = EISRead (cpup, p);   // read data word from memory
1048       }
1049 
1050     word9 c = 0;
1051     switch (tn)
1052       {
1053         case CTN4:
1054           c = get4 (p -> data, * pos);
1055           break;
1056         case CTN9:
1057           c = get9 (p -> data, * pos);
1058           break;
1059       }
1060 
1061     (* pos) ++;
1062     return c;
1063   }
1064 
1065 static bool EISgetBitRWN (cpu_state_t * cpup, EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
1066   {
1067 #if defined(EIS_PTR)
1068     long eisaddr_idx = EISADDR_IDX (p);
1069 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
1070 
1071 #endif
1072     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
1073     int baseBitPosn = baseCharPosn + p -> bPos;
1074     baseBitPosn += (int) cpu.du.CHTALLY;
1075 
1076     int bitPosn = baseBitPosn % 36;
1077     int woff = baseBitPosn / 36;
1078 
1079 #if defined(EIS_PTR)
1080     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
1081     cpu.du.Dk_PTR_W[eisaddr_idx] += (uint) woff;
1082     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
1083 #else
1084     word18 saveAddr = p -> address;
1085     p -> address += (uint) woff;
1086 #endif
1087 
1088     p -> data = EISRead (cpup, p); // read data word from memory
1089 
1090     if (p -> mode == eRWreadBit)
1091       {
1092         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
1093       }
1094     else if (p -> mode == eRWwriteBit)
1095       {
1096         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
1097 
1098         EISWriteIdx (cpup, p, 0, p -> data, flush); // write data word to memory
1099       }
1100 
1101     p->last_bit_posn = bitPosn;
1102 
1103 #if defined(EIS_PTR)
1104     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
1105 #else
1106     p -> address = saveAddr;
1107 #endif
1108     return p -> bit;
1109   }
1110 
1111 static void setupOperandDescriptorCache (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
1112   {
1113     EISstruct * e = & cpu.currentEISinstruction;
1114     e -> addr [k - 1]. cacheValid = false;
1115   }
1116 
1117 //
1118 // 5.2.10.5  Operand Descriptor Address Preparation Flowchart
1119 //
1120 // A flowchart of the operations involved in operand descriptor address
1121 // preparation is shown in Figure 5-2. The chart depicts the address
1122 // preparation for operand descriptor 1 of a multiword instruction as described
1123 // by modification field 1 (MF1). A similar type address preparation would be
1124 // carried out for each operand descriptor as specified by its MF code.
1125 //    (Bull Nova 9000 pg 5-40  67 A2 RJ78 REV02)
1126 //
1127 // 1. The multiword instruction is obtained from memory.
1128 //
1129 // 2. The indirect (ID) bit of MF1 is queried to determine if the descriptor
1130 // for operand 1 is present or is an indirect word.
1131 //
1132 // 3. This step is reached only if an indirect word was in the operand
1133 // descriptor location. Address modification for the indirect word is now
1134 // performed. If the AR bit of the indirect word is 1, address register
1135 // modification step 4 is performed.
1136 //
1137 // 4. The y field of the indirect word is added to the contents of the
1138 // specified address register.
1139 //
1140 // 5. A check is now made to determine if the REG field of the indirect word
1141 // specifies that a register type modification be performed.
1142 //
1143 // 6. The indirect address as modified by the address register is now modified
1144 // by the contents of the specified register, producing the effective address
1145 // of the operand descriptor.
1146 //
1147 // 7. The operand descriptor is obtained from the location determined by the
1148 // generated effective address in item 6.
1149 //
1150 
1151 static void setupOperandDescriptor (cpu_state_t * cpup, int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1152   {
1153     EISstruct * e = & cpu.currentEISinstruction;
1154     switch (k)
1155       {
1156         case 1:
1157           PNL (L68_ (DU_CYCLE_FA_I1;))
1158           PNL (L68_ (DU_CYCLE_GDLDA;))
1159           e -> MF1 = getbits36_7 (cpu.cu.IWB, 29);
1160           break;
1161         case 2:
1162           PNL (L68_ (DU_CYCLE_FA_I2;))
1163           PNL (L68_ (DU_CYCLE_GDLDB;))
1164           e -> MF2 = getbits36_7 (cpu.cu.IWB, 11);
1165           break;
1166         case 3:
1167           PNL (L68_ (DU_CYCLE_FA_I3;))
1168           PNL (L68_ (DU_CYCLE_GDLDC;))
1169           e -> MF3 = getbits36_7 (cpu.cu.IWB,  2);
1170           break;
1171       }
1172 
1173     word18 MFk = e -> MF [k - 1];
1174 
1175     if (MFk & MFkID)
1176     {
1177         PNL (L68_ (if (k == 1)
1178                      DU_CYCLE_LDWRT1;
1179                    if (k == 2)
1180                      DU_CYCLE_LDWRT2;))
1181 
1182         word36 opDesc = e -> op [k - 1];
1183 
1184 // 18-28 MBZ check breaks Multics; line 161 of sys_trouble.alm contains
1185 //
1186 // 000103 aa 040100 1006 20    160   mlr     (id),(pr),fill(040) copy error message
1187 // 000104 0a 000126 0002 05    161   arg     trouble_messages-1,al
1188 // 000105 aa 300063 200063     162   desc9a  bb|fgbx.message+3(1),64-13
1189 //
1190 // bit 28 of 000104 is set
1191 //
1192 
1193 
1194 
1195 
1196 
1197 
1198 
1199 
1200 
1201 
1202 
1203 
1204 
1205 
1206 
1207 
1208 
1209 
1210 
1211 
1212 
1213 
1214         // Bits 30, 31 MBZ
1215         // RJ78 p. 5-39, ISOLTS 840 07a,07b
1216         if (opDesc & 060)
1217           {
1218             *mod_fault |= FR_ILL_MOD;
1219             //doFault (FAULT_IPR, fst_ill_mod, "setupOperandDescriptor 30,31 MBZ");
1220           }
1221 
1222         // fill operand according to MFk....
1223         word18 address = GETHI (opDesc);
1224         PNL (cpu.du.Dk_PTR_W[k-1] = address);
1225 #if defined(EIS_PTR)
1226         cpu.du.Dk_PTR_W[k-1] = address;
1227 #else
1228         e -> addr [k - 1].address = address;
1229 #endif
1230 
1231         // Indirect descriptor control. If ID = 1 for Mfk, then the kth word
1232         // following the instruction word is an indirect pointer to the operand
1233         // descriptor for the kth operand; otherwise, that word is the operand
1234         // descriptor.
1235         //
1236         // If MFk.ID = 1, then the kth word following an EIS multiword
1237         // instruction word is not an operand descriptor, but is an indirect
1238         // pointer to an operand descriptor and is interpreted as shown in
1239         // Figure 4-5.
1240 
1241         // Mike Mondy michael.mondy@coffeebird.net sez' ...
1242         // EIS indirect pointers to operand descriptors use PR registers.
1243         // However, operand descriptors use AR registers according to the
1244         // description of the AR registers and the description of EIS operand
1245         // descriptors. However, the description of the MF field
1246         // claims that operands use PR registers. The AR doesn't have a
1247         // segment field. Emulation confirms that operand descriptors
1248         // need to be fetched via segments given in PR registers.
1249 
1250         bool a = opDesc & (1 << 6);
1251         if (a)
1252           {
1253             // A 3-bit pointer register number (n) and a 15-bit offset relative
1254             // to C(PRn.WORDNO) if A = 1 (all modes)
1255             word3 n = (word3) getbits18 (address, 0, 3);
1256             CPTUR (cptUsePRn + n);
1257             word15 offset = address & MASK15;  // 15-bit signed number
1258             address = (cpu.AR [n].WORDNO + SIGNEXT15_18 (offset)) & AMASK;
1259 
1260             PNL (cpu.du.Dk_PTR_W[k-1] = address);
1261 #if defined(EIS_PTR)
1262             cpu.du.Dk_PTR_W[k-1] = address;
1263 #else
1264             e -> addr [k - 1].address = address;
1265 #endif
1266             cpu.cu.TSN_PRNO[k-1] = n;
1267             cpu.cu.TSN_VALID[k-1] = 1;
1268             e -> addr [k - 1].SNR = cpu.PR [n].SNR;
1269             e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR,
1270                                             cpu.TPR.TRR,
1271                                             cpu.PPR.PRR);
1272 
1273             e -> addr [k - 1].mat = viaPR;   // ARs involved
1274 sim_debug (DBG_TRACEEXT, & cpu_dev, "AR n %u k %u\n", n, k - 1);
1275           }
1276         else
1277           {
1278             e->addr [k - 1].mat = OperandRead;      // no ARs involved yet
1279 sim_debug (DBG_TRACEEXT, & cpu_dev, "No ARb %u\n", k - 1);
1280           }
1281 
1282         // Address modifier for ADDRESS. All register modifiers except du and
1283         // dl may be used. If the ic modifier is used, then ADDRESS is an
1284         // 18-bit offset relative to value of the instruction counter for the
1285         // instruction word. C(REG) is always interpreted as a word offset. REG
1286 
1287         uint reg = opDesc & 017;
1288         // XXX RH03/RJ78 say a,q modifiers are also available here. AL39 says al/ql only
1289         address += getMFReg18 (cpup, reg, false, true, mod_fault); // ID=1: disallow du, allow n,ic
1290         address &= AMASK;
1291 
1292         PNL (cpu.du.Dk_PTR_W[k-1] = address);
1293 
1294 #if defined(EIS_PTR)
1295         cpu.du.Dk_PTR_W[k-1] = address;
1296 #else
1297         e -> addr [k - 1].address = address;
1298 #endif
1299 
1300         // read EIS operand .. this should be an indirectread
1301         e -> op [k - 1] = EISRead (cpup, & e -> addr [k - 1]);
1302     }
1303     else
1304     {
1305           e->addr [k - 1].mat = OperandRead;      // no ARs involved yet
1306 sim_debug (DBG_TRACEEXT, & cpu_dev, "No ARa %u\n", k - 1);
1307     }
1308     setupOperandDescriptorCache (cpup, k);
1309 }
1310 
1311 void setupEISoperands (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1312   {
1313     PNL (cpu.du.POP = 0);
1314     PNL (cpu.du.POL = 0);
1315 
1316 #if defined(EIS_SETUP)
1317     for (int i = 0; i < 3; i ++)
1318       {
1319         if (i < cpu.currentInstruction.info -> ndes)
1320           setupOperandDescriptor (cpup, i + 1);
1321         else
1322           setupOperandDescriptorCache (cpup, i + 1);
1323       }
1324 #endif
1325   }
1326 
1327 static void parseAlphanumericOperandDescriptor (cpu_state_t * cpup, uint k, uint useTA, bool allowDU, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1328   {
1329     EISstruct * e = & cpu.currentEISinstruction;
1330     word18 MFk = e -> MF [k - 1];
1331 
1332     PNL (L68_ (if (k == 1)
1333       DU_CYCLE_ANLD1;
1334     else if (k == 2)
1335       DU_CYCLE_ANLD2;
1336     else if (k == 3)
1337       DU_CYCLE_ANSTR;))
1338 
1339     PNL (cpu.du.POP = 1);
1340 
1341     word36 opDesc = e -> op [k - 1];
1342 
1343     word8 ARn_CHAR = 0;
1344     word6 ARn_BITNO = 0;
1345 
1346     word18 address = GETHI (opDesc);
1347 
1348 #if defined(EIS_PTR3)
1349     if (useTA != k)
1350       cpu.du.TAk[k-1] = cpu.du.TAk[useTA-1];
1351     else
1352       cpu.du.TAk[k-1] = getbits36_2 (opDesc, 21);    // type alphanumeric
1353 #else
1354     if (useTA != k)
1355       e -> TA [k - 1] = e -> TA [useTA - 1];
1356     else
1357       e -> TA [k - 1] = getbits36_2 (opDesc, 21);    // type alphanumeric
1358 #endif
1359 
1360 #if defined(PANEL68)
1361     if (k == 1) // Use data from first operand
1362       {
1363         switch (e->TA[0])
1364           {
1365             case CTA9:
1366               cpu.dataMode = 0102; // 9 bit an
1367               cpu.ou.opsz = is_9 >> 12;
1368               break;
1369             case CTA6:
1370               cpu.dataMode = 0042; // 6 bit an
1371               cpu.ou.opsz = is_6 >> 12;
1372               break;
1373             case CTA4:
1374               cpu.dataMode = 0022; // 4 bit an
1375               cpu.ou.opsz = is_4 >> 12;
1376               break;
1377           }
1378       }
1379 #endif
1380 
1381 // 8. Modification of the operand descriptor address begins. This step is
1382 // reached directly from 2 if no indirection is involved. The AR bit of MF1 is
1383 // checked to determine if address register modification is specified.
1384 //
1385 // 9. Address register modification is performed on the operand descriptor as
1386 // described under "Address Modification with Address Registers" above. The
1387 // character and bit positions of the specified address register are used in
1388 // one of two ways, depending on the type of operand descriptor, i.e., whether
1389 // the type is a bit string, a numeric, or an alphanumeric descriptor.
1390 //
1391 // 10. The REG field of MF1 is checked for a legal code. If DU is specified in
1392 // the REG field of MF2 in one of the four multiword instructions (SCD, SCDR,
1393 // SCM, or SCMR) for which DU is legal, the CN field is ignored and the
1394 // character or characters are arranged within the 18 bits of the word address
1395 // portion of the operand descriptor.
1396 //
1397 // 11. The count contained in the register specified by the REG field code is
1398 // appropriately converted and added to the operand address.
1399 //
1400 // 12. The operand is retrieved from the calculated effective address location.
1401 //
1402 
1403     if (MFk & MFkAR)
1404       {
1405         // if MKf contains ar then it Means Y-charn is not the memory address
1406         // of the data but is a reference to a pointer register pointing to the
1407         // data.
1408         word3 n = (word3) getbits18 (address, 0, 3);
1409         CPTUR (cptUsePRn + n);
1410         word18 offset = SIGNEXT15_18 ((word15) address);  // 15-bit signed number
1411         address = (cpu.AR [n].WORDNO + offset) & AMASK;
1412 
1413         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1414         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1415 
1416         cpu.cu.TSN_PRNO[k-1] = n;
1417         cpu.cu.TSN_VALID[k-1] = 1;
1418         e -> addr [k - 1].SNR = cpu.PR [n].SNR;
1419         e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1420 
1421         e -> addr [k - 1].mat = viaPR;   // ARs involved
1422 sim_debug (DBG_TRACEEXT, & cpu_dev, "AR n %u k %u\n", n, k - 1);
1423       }
1424 
1425     PNL (cpu.du.POL = 1);
1426 
1427     uint CN = getbits36_3 (opDesc, 18);    // character number
1428 
1429     sim_debug (DBG_TRACEEXT, & cpu_dev, "initial CN%u %u\n", k, CN);
1430 
1431     if (MFk & MFkRL)
1432     {
1433         uint reg = opDesc & 017;
1434 // XXX Handle N too big intelligently....
1435         e -> N [k - 1] = (uint) getMFReg36 (cpup, reg, false, false, mod_fault); // RL=1: disallow du,n,ic
1436 #if defined(EIS_PTR3)
1437         switch (cpu.du.TAk[k-1])
1438 #else
1439         switch (e -> TA [k - 1])
1440 #endif
1441           {
1442             case CTA4:
1443               e -> N [k - 1] &= 017777777; // 22-bits of length
1444               break;
1445 
1446             case CTA6:
1447             case CTA9:
1448               e -> N [k - 1] &= 07777777;  // 21-bits of length.
1449               break;
1450 
1451             default:
1452               L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TA 3");)
1453               // DPS8M
1454               *mod_fault |= FR_ILL_PROC;
1455               break;
1456           }
1457       }
1458     else
1459       e -> N [k - 1] = opDesc & 07777;
1460 
1461     //if (e->N [k - 1] == 0)
1462       //doFault (FAULT_IPR, FR_ILL_PROC, "parseAlphanumericOperandDescriptor N 0");
1463 
1464     sim_debug (DBG_TRACEEXT, & cpu_dev, "N%u %o\n", k, e->N[k-1]);
1465 
1466     word36 r = getMFReg36 (cpup, MFk & 017, allowDU, true, mod_fault); // allow du based on instruction, allow n,ic
1467 
1468     if ((MFk & 017) == 4)   // reg == IC ?
1469       {
1470         address += r;
1471         address &= AMASK;
1472         r = 0;
1473       }
1474 
1475     // If seems that the effect address calcs given in AL39 p.6-27 are not
1476     // quite right. E.g. For CTA4/CTN4 because of the 4 "slop" bits you need
1477     // to do 32-bit calcs not 36-bit!
1478     uint effBITNO = 0;
1479     uint effCHAR = 0;
1480     uint effWORDNO = 0;
1481 
1482 #if defined(EIS_PTR3)
1483     switch (cpu.du.TAk[k-1])
1484 #else
1485     switch (e -> TA [k - 1])
1486 #endif
1487       {
1488         case CTA4:
1489           {
1490             // Calculate character number of ARn CHAR and BITNO
1491             uint bitoffset = ARn_CHAR * 9u + ARn_BITNO;
1492             uint arn_char4 = bitoffset * 2 / 9; // / 4.5
1493             // 8 chars per word plus the number of chars in r, plus the
1494             // number of chars in ARn CHAR/BITNO plus the CN from the operand
1495 // XXX Handle 'r' too big intelligently...
1496             uint nchars = address * 8 + (uint) r + arn_char4 + CN;
1497 
1498             effWORDNO = nchars / 8; // 8 chars/word
1499             effCHAR = nchars % 8; // effCHAR is the 4 bit char number, not
1500                                   // the 9-bit char no
1501             effBITNO = (nchars & 1) ? 5 : 0;
1502 
1503             effWORDNO &= AMASK;
1504 
1505             e -> CN [k - 1] = effCHAR;
1506             e -> WN [k - 1] = effWORDNO;
1507 
1508             sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA4\n",
1509                        k, e -> CN [k - 1]);
1510           }
1511           break;
1512 
1513         case CTA6:
1514           if (CN >= 6) {
1515             L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TAn CTA6 CN >= 6");)
1516             // DPS8M
1517             *mod_fault |= FR_ILL_PROC;
1518           }
1519           effBITNO = (9u * ARn_CHAR + 6u * r + ARn_BITNO) % 9u;
1520           effCHAR = ((6u * CN +
1521                       9u * ARn_CHAR +
1522                       6u * r + ARn_BITNO) % 36u) / 6u;//9;
1523           effWORDNO = (uint) (address +
1524                            (6u * CN +
1525                             9u * ARn_CHAR +
1526                             6u * r +
1527                             ARn_BITNO) / 36u);
1528           effWORDNO &= AMASK;
1529 
1530           e -> CN [k - 1] = effCHAR;   // ??????
1531           e -> WN [k - 1] = effWORDNO;
1532           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA6\n",
1533                      k, e -> CN [k - 1]);
1534           break;
1535 
1536         case CTA9:
1537           if (CN & 01) {
1538             L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor CTA9 & CN odd");)
1539             // DPS8M
1540             *mod_fault |= FR_ILL_PROC;
1541           }
1542           CN = (CN >> 1);
1543 
1544           effBITNO = 0;
1545           effCHAR = (CN + ARn_CHAR + r) % 4;
1546           sim_debug (DBG_TRACEEXT, & cpu_dev,
1547                      "effCHAR %d = (CN %d + ARn_CHAR %d + r %"PRId64") %% 4)\n",
1548                      effCHAR, CN, ARn_CHAR, r);
1549           effWORDNO = (uint) (address +
1550                            ((9u * CN +
1551                              9u * ARn_CHAR +
1552                              9u * r +
1553                              ARn_BITNO) / 36u));
1554           effWORDNO &= AMASK;
1555 
1556           e -> CN [k - 1] = effCHAR;   // ??????
1557           e -> WN [k - 1] = effWORDNO;
1558           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA9\n",
1559                      k, e -> CN [k - 1]);
1560           break;
1561 
1562         default:
1563           L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TA1 3");)
1564           // DPS8M
1565           *mod_fault |= FR_ILL_PROC;
1566           break;
1567     }
1568 
1569     EISaddr * a = & e -> addr [k - 1];
1570     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1571 #if defined(EIS_PTR)
1572     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1573 #else
1574     a -> address = effWORDNO;
1575 #endif
1576     a -> cPos= (int) effCHAR;
1577     a -> bPos = (int) effBITNO;
1578 
1579 #if !defined(EIS_PTR3)
1580     // a->_type = eisTA;
1581     a -> TA = (int) e -> TA [k - 1];
1582 #endif
1583   }
1584 
1585 static void parseArgOperandDescriptor (cpu_state_t * cpup, uint k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1586   {
1587     PNL (L68_ (if (k == 1)
1588       DU_CYCLE_NLD1;
1589     else if (k == 2)
1590       DU_CYCLE_NLD2;
1591     else if (k == 3)
1592       DU_CYCLE_GSTR;))
1593 
1594     EISstruct * e = & cpu.currentEISinstruction;
1595     word36 opDesc = e -> op [k - 1];
1596     word18 y = GETHI (opDesc);
1597     word1 yA = GET_A (opDesc);
1598 
1599     uint yREG = opDesc & 0xf;
1600 
1601     word36 r = getMFReg36 (cpup, yREG, false, true, mod_fault); // disallow du, allow n,ic
1602 
1603     word8 ARn_CHAR = 0;
1604     word6 ARn_BITNO = 0;
1605 
1606     PNL (cpu.du.POP = 1);
1607 
1608     if (yA)
1609       {
1610         // if operand contains A (bit-29 set) then it Means Y-char9n is not
1611         // the memory address of the data but is a reference to a pointer
1612         // register pointing to the data.
1613         word3 n = GET_ARN (opDesc);
1614         CPTUR (cptUsePRn + n);
1615         word15 offset = y & MASK15;  // 15-bit signed number
1616         y = (cpu.AR [n].WORDNO + SIGNEXT15_18 (offset)) & AMASK;
1617 
1618         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1619         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1620 
1621         cpu.cu.TSN_PRNO[k-1] = n;
1622         cpu.cu.TSN_VALID[k-1] = 1;
1623         e -> addr [k - 1].SNR = cpu.PR[n].SNR;
1624         e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1625         e -> addr [k - 1].mat = viaPR;
1626       }
1627 
1628     y += ((9u * ARn_CHAR + 36u * r + ARn_BITNO) / 36u);
1629     y &= AMASK;
1630 
1631     PNL (cpu.du.Dk_PTR_W[k-1] = y);
1632 
1633 #if defined(EIS_PTR)
1634     cpu.du.Dk_PTR_W[k-1] = y;
1635 #else
1636     e -> addr [k - 1].address = y;
1637 #endif
1638   }
1639 
1640 static void parseNumericOperandDescriptor (cpu_state_t * cpup, int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1641 {
1642     PNL (L68_ (if (k == 1)
1643       DU_CYCLE_NLD1;
1644     else if (k == 2)
1645       DU_CYCLE_NLD2;
1646     else if (k == 3)
1647       DU_CYCLE_GSTR;))
1648 
1649     EISstruct * e = & cpu.currentEISinstruction;
1650     word18 MFk = e->MF[k-1];
1651 
1652     PNL (cpu.du.POP = 1);
1653 
1654     word36 opDesc = e->op[k-1];
1655 
1656     word8 ARn_CHAR = 0;
1657     word6 ARn_BITNO = 0;
1658 
1659     word18 address = GETHI(opDesc);
1660     if (MFk & MFkAR)
1661     {
1662         // if MKf contains ar then it Means Y-charn is not the memory address
1663         // of the data but is a reference to a pointer register pointing to the
1664         // data.
1665         word3 n = (word3) getbits18 (address, 0, 3);
1666         CPTUR (cptUsePRn + n);
1667         word15 offset = address & MASK15;  // 15-bit signed number
1668         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1669 
1670         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1671         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1672 
1673         cpu.cu.TSN_PRNO[k-1] = n;
1674         cpu.cu.TSN_VALID[k-1] = 1;
1675         e->addr[k-1].SNR = cpu.PR[n].SNR;
1676         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1677 
1678         e->addr[k-1].mat = viaPR;   // ARs involved
1679     }
1680 
1681     PNL (cpu.du.POL = 1);
1682 
1683     word3 CN = getbits36_3 (opDesc, 18);    // character number
1684     e->TN[k-1] = getbits36_1 (opDesc, 21); // type numeric
1685 
1686 #if defined(PANEL68)
1687     if (k == 1)
1688       {
1689         if (e->TN[0])
1690           cpu.dataMode = 0021; // 4 bit numeric
1691         else
1692           cpu.dataMode = 0101; // 9 bit numeric
1693       }
1694 #endif
1695 
1696     e->S[k-1]  = getbits36_2 (opDesc, 22);    // Sign and decimal type of data
1697     e->SF[k-1] = SIGNEXT6_int (getbits36_6 (opDesc, 24));    // Scaling factor.
1698 
1699     // Operand length. If MFk.RL = 0, this field contains the operand length in
1700     // digits. If MFk.RL = 1, it contains the REG code for the register holding
1701     // the operand length and C(REG) is treated as a 0 modulo 64 number. See
1702     // Table 4-1 and EIS modification fields (MF) above for a discussion of
1703     // register codes.
1704 
1705     if (MFk & MFkRL)
1706     {
1707         uint reg = opDesc & 017;
1708         e->N[k-1] = getMFReg18 (cpup,reg, false, false, mod_fault) & 077; // RL=1: disallow du,n,ic
1709     }
1710     else
1711         e->N[k-1] = opDesc & 077;
1712 
1713     sim_debug (DBG_TRACEEXT, & cpu_dev, "parseNumericOperandDescriptor(cpup, ): N%u %0o\n", k, e->N[k-1]);
1714 
1715     word36 r = getMFReg36(cpup, MFk & 017, false, true, mod_fault); // disallow du, allow n, ic
1716     if ((MFk & 017) == 4)   // reg == IC ?
1717     {
1718         address += r;
1719         address &= AMASK;
1720         r = 0;
1721     }
1722 
1723 // handled in numeric instructions
1724 
1725 
1726 
1727 
1728 
1729 
1730 
1731 
1732 
1733 
1734 // Causes:
1735 //DBG(662088814)> CPU0 FAULT: Fault 10(012), sub 4294967296(040000000000), dfc N, 'parseNumericOperandDescriptor N=1 S=0|1|2'
1736 //DBG(662088814)> CPU0 FAULT: 00257:004574 bound_process_env_:command_query_+04574
1737 //DBG(662088814)> CPU0 FAULT:       664 end print_question;
1738 //DBG(662088814)> CPU0 FAULT: 00257:004574 4 000100301500 (BTD PR0|100) 000100 301(1) 0 0 0 00
1739 
1740     uint effBITNO = 0;
1741     uint effCHAR = 0;
1742     uint effWORDNO = 0;
1743 
1744     // If seems that the effect address calcs given in AL39 p.6-27 are not
1745     // quite right.
1746     // E.g. For CTA4/CTN4 because of the 4 "slop" bits you need to do 32-bit
1747     // calcs not 36-bit!
1748 
1749     switch (e->TN[k-1])
1750     {
1751         case CTN4:
1752           {
1753             // Calculate character number of ARn CHAR and BITNO
1754             uint bitoffset = ARn_CHAR * 9u + ARn_BITNO;
1755             uint arn_char4 = bitoffset * 2u / 9u; // / 4.5
1756             //// The odd chars start at the 6th bit, not the 5th
1757             //if (bitoffset & 1) // if odd
1758             //  arn_char4 ++;
1759             // 8 chars per word plus the number of chars in r, plus the number of chars in ARn CHAR/BITNO
1760 // XXX Handle 'r' too big intelligently...
1761             uint nchars = (uint) (address * 8u + r + arn_char4 + CN);
1762 
1763             effWORDNO = nchars / 8u; // 8 chars/word
1764             effCHAR = nchars % 8u; // effCHAR is the 4 bit char number, not the 9-bit char no
1765             effBITNO = (nchars & 1u) ? 5u : 0u;
1766             effWORDNO &= AMASK;
1767 
1768             e->CN[k-1] = effCHAR;        // ?????
1769           }
1770           break;
1771 
1772         case CTN9:
1773             if (CN & 1u) {
1774               L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseNumericOperandDescriptor CTA9 & CN odd");)
1775               // DPS8M
1776               *mod_fault |= FR_ILL_PROC;
1777             }
1778             CN = (CN >> 1u) & 03u;
1779 
1780             effBITNO = 0;
1781             effCHAR = ((word36) CN + (word36) ARn_CHAR + r) % 4u;
1782             effWORDNO = (uint) (address + (9u*CN + 9u*ARn_CHAR + 9u*r + ARn_BITNO) / 36);
1783             effWORDNO &= AMASK;
1784 
1785             e->CN[k-1] = effCHAR;        // ?????
1786 
1787             break;
1788         default:
1789 #if defined(EIS_PTR3)
1790             sim_printf ("parseNumericOperandDescriptor(cpup, ta=%d) How'd we get here 2?\n",
1791                         cpu.du.TAk[k-1]);
1792 #else
1793             sim_printf ("parseNumericOperandDescriptor(cpup, ta=%d) How'd we get here 2?\n",
1794                         e->TA[k-1]);
1795 #endif
1796             break;
1797     }
1798 
1799     EISaddr *a = &e->addr[k-1];
1800     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1801 #if defined(EIS_PTR)
1802     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1803 #else
1804     a->address = effWORDNO;
1805 #endif
1806     a->cPos = (int) effCHAR;
1807     a->bPos = (int) effBITNO;
1808 
1809     // a->_type = eisTN;
1810     a->TN = (int) e->TN[k-1];
1811 
1812 #if defined(EIS_PTR)
1813     sim_debug (DBG_TRACEEXT, & cpu_dev,
1814                "parseNumericOperandDescriptor(cpup, ): address:%06o cPos:%d bPos:%d N%u %u\n",
1815                cpu.du.Dk_PTR_W[k-1], a->cPos, a->bPos, k, e->N[k-1]);
1816 #else
1817     sim_debug (DBG_TRACEEXT, & cpu_dev,
1818                "parseNumericOperandDescriptor(cpup, ): address:%06o cPos:%d bPos:%d N%u %u\n",
1819                a->address, a->cPos, a->bPos, k, e->N[k-1]);
1820 #endif
1821 }
1822 
1823 static void parseBitstringOperandDescriptor (cpu_state_t * cpup, int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1824 {
1825     PNL (L68_ (if (k == 1)
1826       DU_CYCLE_ANLD1;
1827     else if (k == 2)
1828       DU_CYCLE_ANLD2;
1829     else if (k == 3)
1830       DU_CYCLE_ANSTR;))
1831 
1832     EISstruct * e = & cpu.currentEISinstruction;
1833     word18 MFk = e->MF[k-1];
1834     word36 opDesc = e->op[k-1];
1835 
1836 #if defined(PANEL68)
1837     if (k == 1)
1838       cpu.dataMode = 0010; // 1 bit not alpha, not alpha numeric
1839 #endif
1840     word8 ARn_CHAR = 0;
1841     word6 ARn_BITNO = 0;
1842 
1843     PNL (cpu.du.POP = 1);
1844 
1845     word18 address = GETHI(opDesc);
1846     if (MFk & MFkAR)
1847     {
1848         // if MKf contains ar then it Means Y-charn is not the memory address
1849         // of the data but is a reference to a pointer register pointing to the
1850         // data.
1851         word3 n = (word3) getbits18 (address, 0, 3);
1852         CPTUR (cptUsePRn + n);
1853         word15 offset = address & MASK15;  // 15-bit signed number
1854         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1855 
1856         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d AR%d\n", k, n);
1857 
1858         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1859         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1860         cpu.cu.TSN_PRNO[k-1] = n;
1861         cpu.cu.TSN_VALID[k-1] = 1;
1862         e->addr[k-1].SNR = cpu.PR[n].SNR;
1863         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1864         e->addr[k-1].mat = viaPR;   // ARs involved
1865     }
1866     PNL (cpu.du.POL = 1);
1867 
1868     //Operand length. If MFk.RL = 0, this field contains the string length of
1869     //the operand. If MFk.RL = 1, this field contains the code for a register
1870     //holding the operand string length. See Table 4-1 and EIS modification
1871     //fields (MF) above for a discussion of register codes.
1872     if (MFk & MFkRL)
1873     {
1874         uint reg = opDesc & 017;
1875         e->N[k-1] = getMFReg36(cpup, reg, false, false, mod_fault) & 077777777;  // RL=1: disallow du,n,ic
1876         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d RL reg %u val %"PRIo64"\n", k, reg, (word36)e->N[k-1]);
1877     }
1878     else
1879     {
1880         e ->N[k-1] = opDesc & 07777;
1881     }
1882 
1883     sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d opdesc %012"PRIo64"\n", k, opDesc);
1884     sim_debug (DBG_TRACEEXT, & cpu_dev, "N%u %u\n", k, e->N[k-1]);
1885 
1886     word4 B = getbits36_4(opDesc, 20);    // bit# from descriptor
1887     word2 C = getbits36_2 (opDesc, 18);     // char# from descriptor
1888 
1889     if (B >= 9) {
1890       L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseBitstringOperandDescriptor B >= 9");)
1891       // DPS8M
1892       *mod_fault |= FR_ILL_PROC;
1893     }
1894 
1895     word36 r = getMFReg36(cpup, MFk & 017, false, true, mod_fault);  // disallow du, allow n,ic
1896     if ((MFk & 017) == 4)   // reg == IC ?
1897     {
1898         // If reg == IC, then R is in words, not bits.
1899         //r *= 36;
1900         address += r;
1901         address &= AMASK;
1902         r = 0;
1903     }
1904 
1905     uint effBITNO = (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 9u;
1906     uint effCHAR = ((9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 36u) / 9u;
1907     uint effWORDNO = (uint) (address + (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) / 36u);
1908     effWORDNO &= AMASK;
1909 
1910     e->B[k-1] = effBITNO;
1911     e->C[k-1] = effCHAR;
1912 
1913     EISaddr *a = &e->addr[k-1];
1914     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1915 #if defined(EIS_PTR)
1916     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1917 #else
1918     a->address = effWORDNO;
1919 #endif
1920     a->cPos = (int) effCHAR;
1921     a->bPos = (int) effBITNO;
1922 }
1923 
1924 static void cleanupOperandDescriptor (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
1925   {
1926     EISstruct * e = & cpu.currentEISinstruction;
1927     if (e -> addr [k - 1].cacheValid && e -> addr [k - 1].cacheDirty)
1928       {
1929         EISWriteCache(cpup, & e -> addr [k - 1]);
1930       }
1931     e -> addr [k - 1].cacheDirty = false;
1932   }
1933 
1934 // For a4bd/s4bd, the world is made of 32 bit words, so the address space
1935 // is 2^18 * 32 bits
1936 #define n4bits (1 << 23)
1937 // For a4bd/s4bd, the world is made of 8 4-bitcharacter words, so the address space
1938 // is 2^18 * 8 characters
1939 #define n4chars (1 << 21)
1940 // For axbd/sxbd, the world is made of 36 bits words, so the address space
1941 // is 2^18 * 36 bits
1942 #define nxbits ((1 << 18) * 36)
1943 
1944 // 2 * (s->BITNO / 9) + (s->BITNO % 9) / 4;
1945 static unsigned int cntFromBit[36] = {
1946     0, 0, 0, 0, 0, 1, 1, 1, 1,
1947     2, 2, 2, 2, 2, 3, 3, 3, 3,
1948     4, 4, 4, 4, 4, 5, 5, 5, 5,
1949     6, 6, 6, 6, 6, 7, 7, 7, 7
1950 };
1951 
1952 static word6 bitFromCnt[8] = {1, 5, 10, 14, 19, 23, 28, 32};
1953 
1954 void a4bd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1955   {
1956     // 8 4-bit characters/word
1957 
1958     uint ARn = GET_ARN (cpu.cu.IWB);
1959     CPTUR (cptUsePRn + ARn);
1960     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
1961 //if (current_running_cpu_idx)
1962 //sim_printf ("a4bd address %o %d.\n", address, address);
1963 
1964     word4 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
1965                                      // au, qu, al, ql, xn)
1966     // r is the count of 4bit characters
1967     word36 ur = getCrAR (cpup, reg);
1968     int32 r = SIGNEXT22_32 ((word22) ur);
1969 //if (current_running_cpu_idx)
1970 //sim_printf ("a4bd r %o %d.\n", r, r);
1971 
1972     uint augend = 0; // in 4bit characters
1973     if (GET_A (cpu.cu.IWB))
1974        {
1975 //if (current_running_cpu_idx)
1976 //sim_printf ("a4bd AR%d WORDNO %o %d. CHAR %o BITNO %o\n",
1977 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO,
1978 //            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 #if defined(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 (cpu_state_t * cpup)
     /* [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 (cpup, 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 #if defined(TESTING)
2083     HDBGRegARW (ARn, "s4bd");
2084 #endif
2085   }
2086 
2087 void axbd (cpu_state_t * cpup, 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 (cpup, 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,
2110                "axbd sz %d ARn 0%o address 0%o reg 0%o r 0%o\n",
2111                sz, ARn, address, reg, r);
2112 
2113     uint augend = 0;
2114     if (GET_A (cpu.cu.IWB))
2115       {
2116        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2117                   "axbd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\n",
2118                   ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn),
2119                   GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2120        augend = cpu.AR[ARn].WORDNO * 36u + GET_AR_CHAR (ARn) * 9u + GET_AR_BITNO (ARn);
2121       }
2122     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2123                "axbd augend 0%o\n",
2124                augend);
2125     // force to character boundary
2126     //if (sz == 9 || sz == 36 || GET_A (cpu.cu.IWB))
2127     if (sz == 9 || GET_A (cpu.cu.IWB))
2128       {
2129         augend = (augend / sz) * sz;
2130         sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2131                    "axbd force augend 0%o\n",
2132                    augend);
2133       }
2134 // If sz == 9, this is an a9bd instruction; ISOLTS says that r is in characters, not bits.
2135 // wow. That breaks the boot bad.
2136 //    if (sz == 9)
2137 //      {
2138 //        r *= 9;
2139 //if (current_running_cpu_idx)
2140 //sim_printf ("axbd force chars 0%o %d. bits\n", r, r);
2141 //      }
2142 
2143     int32_t addend = address * 36 + r * (int32_t) sz;
2144     int32_t sum = (int32_t) augend + addend;
2145 
2146     // Handle over/under flow
2147     while (sum < 0)
2148       sum += nxbits;
2149     sum = sum % nxbits;
2150 
2151     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2152 
2153     cpu.AR [ARn].WORDNO = (word18) (sum / 36) & AMASK;
2154     //SET_PR_BITNO (ARn, sum % 36);
2155 #if defined(TESTING)
2156     HDBGRegARR (ARn, "axbd");
2157 #endif
2158     SET_AR_CHAR_BITNO (ARn, (word2)((sum % 36) / 9), (word2)(sum % 9));
2159 #if defined(TESTING)
2160     HDBGRegARW (ARn, "axbd");
2161 #endif
2162   }
2163 
2164 
2165 void abd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2166   {
2167     uint ARn = GET_ARN (cpu.cu.IWB);
2168     CPTUR (cptUsePRn + ARn);
2169 
2170     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2171 //if (current_running_cpu_idx)
2172 //sim_printf ("address %o\n", address);
2173     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2174     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2175     word24 r = getCrAR (cpup, (word4) reg) & MASK24;
2176 //if (current_running_cpu_idx)
2177 //sim_printf ("r 0%o %d.\n", r, r);
2178 //if (current_running_cpu_idx)
2179 //sim_printf ("abd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\n",
2180 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR,
2181 //            cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2182 
2183     //if (cpu.AR[ARn].BITNO > 8)
2184       //cpu.AR[ARn].BITNO = 8;
2185     if (GET_AR_BITNO (ARn) > 8)
2186       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2187 
2188     if (GET_A (cpu.cu.IWB))
2189       {
2190 //if (current_running_cpu_idx)
2191 //sim_printf ("A 1\n");
2192         //word24 bits = 9 * cpu.AR[ARn].CHAR + cpu.AR[ARn].BITNO + r;
2193         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) + r;
2194 //if (current_running_cpu_idx)
2195 //sim_printf ("bits 0%o %d.\n", bits, bits);
2196         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO + address +
2197                               bits / 36) & MASK18;
2198         if (r % 36)
2199           {
2200             //cpu.AR[ARn].CHAR = (bits % 36) / 9;
2201             //cpu.AR[ARn].BITNO = bits % 9;
2202             SET_AR_CHAR_BITNO (ARn, (bits % 36) / 9,
2203                                     bits % 9);
2204           }
2205       }
2206     else
2207       {
2208 //if (current_running_cpu_idx)
2209 //sim_printf ("A 0\n");
2210         cpu.AR[ARn].WORDNO = (address + r / 36) & MASK18;
2211         if (r % 36)
2212           {
2213             //cpu.AR[ARn].CHAR = (r % 36) / 9;
2214             //cpu.AR[ARn].BITNO = r % 9;
2215             SET_AR_CHAR_BITNO (ARn, (r % 36) / 9,
2216                                     r % 9);
2217           }
2218       }
2219 # if defined(TESTING)
2220     HDBGRegARW (ARn, "abd");
2221 # endif
2222 //if (current_running_cpu_idx)
2223 //sim_printf ("abd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\n",
2224 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR,
2225 //            cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
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 
2359 
2360 
2361 
2362 
2363 
2364 
2365 
2366 
2367 
2368 
2369 
2370 
2371 
2372 
2373 
2374 
2375 void awd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2376   {
2377     uint ARn = GET_ARN (cpu.cu.IWB);
2378     CPTUR (cptUsePRn + ARn);
2379     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2380     // 4-bit register modification (None except
2381     // au, qu, al, ql, xn)
2382     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2383     // r is the count of characters
2384 // XXX This code is assuming that 'r' has 18 bits of data....
2385     int32_t r = (int32_t) (getCrAR (cpup, reg) & MASK18);
2386     r = SIGNEXT18_32 ((word18) r);
2387 
2388     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2389                "awd ARn 0%o address 0%o reg 0%o r 0%o\n",
2390                ARn, address, reg, r);
2391 
2392     uint augend = 0;
2393     if (GET_A (cpu.cu.IWB))
2394       {
2395        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2396                   "awd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\n",
2397                   ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn),
2398                   GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2399 
2400        //augend = cpu.AR [ARn].WORDNO * 36 + GET_AR_CHAR (ARn) * 9 + GET_AR_BITNO (ARn);
2401        augend = cpu.AR [ARn].WORDNO;
2402       }
2403 
2404     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2405                "awd augend 0%o\n",
2406                augend);
2407 
2408     int32_t addend = address + r;
2409     int32_t sum = (int32_t) augend + addend;
2410 
2411     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2412                "awd augend 0%o addend 0%o sum 0%o\n",
2413                augend, addend, sum);
2414 
2415     cpu.AR[ARn].WORDNO = (word18) sum & AMASK;
2416     SET_AR_CHAR_BITNO (ARn, 0, 0);
2417 #if defined(TESTING)
2418     HDBGRegARW (ARn, "awd");
2419 #endif
2420   }
2421 
2422 void sbd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2423   {
2424     uint ARn = GET_ARN (cpu.cu.IWB);
2425 
2426     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2427     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2428     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2429     word24 r = getCrAR (cpup, (word4) reg) & MASK24;
2430     if (GET_AR_BITNO (ARn) > 8)
2431       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2432 
2433     if (GET_A (cpu.cu.IWB))
2434       {
2435         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) - r;
2436         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2437                              address + bits / 36) & MASK18;
2438         if (r % 36)
2439           {
2440             SET_AR_CHAR_BITNO (ARn, (- ((bits % 36) / 9)) & MASK2,
2441                                     (- (bits % 9)) & MASK4);
2442           }
2443       }
2444     else
2445       {
2446         cpu.AR[ARn].WORDNO = (- (address + r / 36)) & MASK18;
2447         if (r % 36)
2448           {
2449             SET_AR_CHAR_BITNO (ARn, (- ((r % 36) / 9)) & MASK2,
2450                                     (- (r % 9)) & MASK4);
2451           }
2452       }
2453 #if defined(TESTING)
2454     HDBGRegARW (ARn, "sbd");
2455 #endif
2456   }
2457 
2458 void swd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2459   {
2460     uint ARn = GET_ARN (cpu.cu.IWB);
2461     CPTUR (cptUsePRn + ARn);
2462     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2463     // 4-bit register modification (None except
2464     // au, qu, al, ql, xn)
2465     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2466     // r is the count of characters
2467 // XXX This code is assuming that 'r' has 18 bits of data....
2468     int32_t r = (int32_t) (getCrAR (cpup, reg) & MASK18);
2469     r = SIGNEXT18_32 ((word18) r);
2470 
2471     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2472                "swd ARn 0%o address 0%o reg 0%o r 0%o\n",
2473                ARn, address, reg, r);
2474 
2475     uint minued = 0;
2476     if (GET_A (cpu.cu.IWB))
2477       {
2478        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2479                   "swd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\n",
2480                   ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn),
2481                   GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2482 
2483        //minued = cpu.AR [ARn].WORDNO * 36 + GET_AR_BITNO (ARn);
2484        minued = cpu.AR [ARn].WORDNO;
2485       }
2486 
2487     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2488                "swd minued 0%o\n", minued);
2489 
2490     int32_t subtractend = address + r;
2491     int32_t difference = (int32_t) minued - subtractend;
2492 
2493     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2494                "swd minued 0%o subtractend 0%o difference 0%o\n",
2495                minued, subtractend, difference);
2496 
2497     cpu.AR [ARn].WORDNO = (word18) difference & AMASK;
2498     SET_AR_CHAR_BITNO (ARn, 0, 0);
2499 #if defined(TESTING)
2500     HDBGRegARW (ARn, "swd");
2501 #endif
2502   }
2503 
2504 void s9bd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2505   {
2506     uint ARn = GET_ARN (cpu.cu.IWB);
2507     CPTUR (cptUsePRn + ARn);
2508     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2509     // 4-bit register modification (None except
2510     // au, qu, al, ql, xn)
2511     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2512 
2513     // r is the count of 9-bit characters
2514     word21 r = getCrAR (cpup, reg) & MASK21;;
2515 
2516     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "s9bd r 0%o\n", r);
2517 
2518     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);
2519 
2520     if (GET_A (cpu.cu.IWB))
2521       {
2522         //cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2523         //                      address +
2524         //                      (cpu.AR[ARn].CHAR - r) / 4) & MASK18;
2525         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2526                               address +
2527                               (GET_AR_CHAR (ARn) - r) / 4) & MASK18;
2528         //if (r % 36)
2529           //{
2530             //cpu.AR[ARn].CHAR = ((cpu.AR[ARn].CHAR - r) % 4) & MASK2;
2531             //cpu.AR[ARn].CHAR = (cpu.AR[ARn].CHAR - r)  & MASK2;
2532             SET_AR_CHAR_BITNO (ARn, (GET_AR_CHAR (ARn) - r)  & MASK2, 0);
2533           //}
2534       }
2535     else
2536       {
2537         cpu.AR[ARn].WORDNO = (- (address + (r + 3) / 4)) & MASK18;
2538         //if (r % 36)
2539           //{
2540             //cpu.AR[ARn].CHAR = (-r) & MASK2;
2541             SET_AR_CHAR_BITNO (ARn, (-r) & MASK2, 0);
2542           //}
2543       }
2544     //cpu.AR[ARn].BITNO = 0;
2545 #if defined(TESTING)
2546     HDBGRegARW (ARn, "s9bd");
2547 #endif
2548 //if (current_running_cpu_idx)
2549 //sim_printf ("s9bd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\n",
2550 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR,
2551 //            cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2552   }
2553 
2554 //
2555 // Address Register arithmetic
2556 //
2557 // This code handles Address Register arithmetic
2558 //
2559 // asxbd (  ,       )
2560 // ABD     1   false
2561 // A4BD    4   false
2562 // A6BD    6   false
2563 // A9BD    9   false
2564 // AWD    36   false
2565 // SBD     1   true
2566 // S4BD    4   true
2567 // S6BD    6   true
2568 // S9BD    9   true
2569 // SWD    36   true
2570 //
2571 
2572 // The general approach is do all of the math as unsigned number of bits,
2573 // modulo 2^18 * 36 (the number of bits in a segment).
2574 //
2575 // To handle subtraction underflow, a preemptive borrow is done if the
2576 // the operation will underflow.
2577 //
2578 // Notes:
2579 //   According to ISOLTS 805, WORDNO is unsigned; this disagrees with AL-39
2580 
2581 void asxbd (cpu_state_t * cpup, uint sz, bool sub)
     /* [previous][next][first][last][top][bottom][index][help] */
2582   {
2583     // Map charno:bitno to bit offset for 4 bit char set
2584     uint map4 [64] =
2585       {      // 9-bit    4-bit
2586           0, // 0  0      0
2587           0, // 0  1      0
2588           0, // 0  2      0
2589           0, // 0  3      0
2590           0, // 0  4      0
2591           5, // 0  5      1
2592           5, // 0  6      1
2593           5, // 0  7      1
2594           5, // 0  8      1
2595           5, // 0  9  ill     guess
2596           5, // 0 10  ill     guess
2597           5, // 0 11  ill     guess
2598           5, // 0 12  ill     guess
2599           5, // 0 13  ill     guess
2600           5, // 0 14  ill     guess
2601           5, // 0 15  ill     guess
2602           9, // 1  0      2
2603           9, // 1  1      2
2604           9, // 1  2      2
2605           9, // 1  3      2
2606           9, // 1  4      2
2607          14, // 1  5      3
2608          14, // 1  6      3
2609          14, // 1  7      3
2610          14, // 1  8      3
2611          14, // 1  9  ill     guess
2612          14, // 1 10  ill ISOLTS 805 loop point 010226 sxbd test no 28 (4bit)
2613          14, // 1 11  ill     guess
2614          14, // 1 12  ill     guess
2615          14, // 1 13  ill     guess
2616          14, // 1 14  ill     guess
2617          14, // 1 15  ill     guess
2618          18, // 2  0      4
2619          18, // 2  1      4
2620          18, // 2  2      4
2621          18, // 2  3      4
2622          18, // 2  4      4
2623          23, // 2  5      5
2624          23, // 2  6      5
2625          23, // 2  7      5
2626          23, // 2  8      5
2627          23, // 2  9  ill     guess
2628          23, // 2 10  ill     guess
2629          23, // 2 11  ill     guess
2630          23, // 2 12  ill   ISOLTS 805 loop point 010226 sxbd test no 26 (4bit)
2631          23, // 2 13  ill     guess
2632          23, // 2 14  ill     guess
2633          23, // 2 15  ill     guess
2634          27, // 3  0      6
2635          27, // 3  1      6
2636          27, // 3  2      6
2637          27, // 3  3      6
2638          27, // 3  4      6
2639          32, // 3  5      7
2640          32, // 3  6      7
2641          32, // 3  7      7
2642          32, // 3  8      7
2643          32, // 3  9  ill     guess
2644          32, // 3 10  ill     guess
2645          32, // 3 11  ill     guess
2646          32, // 3 12  ill     guess
2647          32, // 3 13  ill     guess
2648          32, // 3 14  ill   ISOLTS 805 loop point 010226 sxbd test no 24 (4bit)
2649          32  // 3 15  ill     guess
2650       };
2651     // Map charno:bitno to bit offset for 6 bit char set
2652     uint map6 [64] =
2653       {      // 9-bit    6-bit
2654           0, // 0  0      0
2655           1, // 0  1      0
2656           2, // 0  2      0
2657           3, // 0  3      0
2658           4, // 0  4      0
2659           5, // 0  5      0
2660           6, // 0  6      1
2661           7, // 0  7      1
2662           8, // 0  8      1
2663           6, // 0  9  ill  ISOLTS 805 loop point 010100 sxbd test no 12
2664           6, // 0 10  ill     guess
2665           6, // 0 11  ill     guess
2666           6, // 0 12  ill     guess
2667           6, // 0 13  ill     guess
2668           6, // 0 14  ill     guess
2669           6, // 0 15  ill     guess
2670           9, // 1  0      1
2671          10, // 1  1      1
2672          11, // 1  2      1
2673          12, // 1  3      2
2674          13, // 1  4      2
2675          14, // 1  5      2
2676          15, // 1  6      2
2677          16, // 1  7      2
2678          17, // 1  8      2
2679          12, // 1  9  ill     guess
2680          12, // 1 10  ill     guess
2681          12, // 1 11  ill ISOLTS 805 loop point 010100 sxbd test no 12
2682          12, // 1 12  ill     guess
2683          12, // 1 13  ill     guess
2684          12, // 1 14  ill     guess
2685          12, // 1 15  ill     guess
2686          18, // 2  0      3
2687          19, // 2  1      3
2688          20, // 2  2      3
2689          21, // 2  3      3
2690          22, // 2  4      3
2691          23, // 2  5      3
2692          24, // 2  6      4
2693          25, // 2  7      4
2694          26, // 2  8      4
2695          24, // 2  9  ill     guess
2696          24, // 2 10  ill     guess
2697          24, // 2 11  ill     guess
2698          24, // 2 12  ill     guess
2699          24, // 2 13  ill   ISOLTS 805 loop point 010100 sxbd test no 10
2700          24, // 2 14  ill     guess
2701          24, // 2 15  ill     guess
2702          27, // 3  0      4
2703          28, // 3  1      4
2704          29, // 3  2      4
2705          30, // 3  3      5
2706          31, // 3  4      5
2707          32, // 3  5      5
2708          33, // 3  6      5
2709          34, // 3  7      5
2710          35, // 3  8      5
2711          30, // 3  9  ill     guess
2712          30, // 3 10  ill     guess
2713          30, // 3 11  ill     guess
2714          30, // 3 12  ill     guess
2715          30, // 3 13  ill     guess
2716          30, // 3 14  ill     guess
2717          30  // 3 15  ill   ISOLTS 805 loop point 010100 sxbd test no 8 (6bit)
2718       };
2719     // Map charno:bitno to 1 and 9 bit offset
2720     uint map9 [64] =
2721       {      // 9-bit
2722           0, // 0  0
2723           1, // 0  1
2724           2, // 0  2
2725           3, // 0  3
2726           4, // 0  4
2727           5, // 0  5
2728           6, // 0  6
2729           7, // 0  7
2730           8, // 0  8
2731           8, // 0  9  ill     guess
2732           8, // 0 10  ill     guess
2733           8, // 0 11  ill     guess
2734           8, // 0 12  ill     guess
2735           8, // 0 13  ill     guess
2736           8, // 0 14  ill     guess
2737           8, // 0 15  ill     guess
2738           9, // 1  0
2739          10, // 1  1
2740          11, // 1  2
2741          12, // 1  3
2742          13, // 1  4
2743          14, // 1  5
2744          15, // 1  6
2745          16, // 1  7
2746          17, // 1  8
2747          17, // 1  9  ill     guess
2748          17, // 1 10  ill     guess
2749          17, // 1 11  ill     guess
2750          17, // 1 12  ill     guess
2751          17, // 1 13  ill     guess
2752          17, // 1 14  ill     guess
2753          17, // 1 15  ill     guess
2754          18, // 2  0
2755          19, // 2  1
2756          20, // 2  2
2757          21, // 2  3
2758          22, // 2  4
2759          23, // 2  5
2760          24, // 2  6
2761          25, // 2  7
2762          26, // 2  8
2763          26, // 2  9  ill     guess
2764          26, // 2 10  ill     guess
2765          26, // 2 11  ill     guess
2766          26, // 2 12  ill     guess
2767          26, // 2 13  ill     guess
2768          26, // 2 14  ill     guess
2769          26, // 2 15  ill     guess
2770          27, // 3  0
2771          28, // 3  1
2772          29, // 3  2
2773          30, // 3  3
2774          31, // 3  4
2775          32, // 3  5
2776          33, // 3  6
2777          34, // 3  7
2778          35, // 3  8
2779          35, // 3  9  ill     guess
2780          35, // 3 10  ill     guess
2781          35, // 3 11  ill     guess
2782          35, // 3 12  ill     guess
2783          35, // 3 13  ill     guess
2784          35, // 3 14  ill     guess
2785          35  // 3 15  ill     guess
2786       };
2787 
2788 //
2789 // Extract the operand data from the instruction
2790 //
2791 
2792     uint ARn = GET_ARN (cpu.cu.IWB);
2793     uint address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2794     word4 reg = (word4) GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2795                                   // au, qu, al, ql, xn)
2796 
2797 //
2798 // Calculate r
2799 //
2800 
2801     // r is the count of characters (or bits if sz is 1; words if sz == 36)
2802     word36 rcnt = getCrAR (cpup, reg);
2803 
2804     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd sz %d r 0%"PRIo64"\n", sz, rcnt);
2805 
2806     // Crop rcnt into r based on the operand size.
2807     uint r = 0;
2808 
2809     if (sz == 1)
2810       r = (uint) (rcnt & MASK24);
2811     else if (sz == 4)
2812       r = (uint) (rcnt & MASK22);
2813     else if (sz == 6)
2814       r = (uint) (rcnt & MASK21);
2815     else if (sz == 9)
2816       r = (uint) (rcnt & MASK21);
2817     else // if (sz == 36)
2818       r = (uint) (rcnt & MASK18);
2819 
2820     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);
2821 
2822 //
2823 // Calculate augend
2824 //
2825 
2826     // If A is set, the instruction is AR = AR op operand; if not, AR = 0 op operand.
2827     uint augend = 0;
2828     if (GET_A (cpu.cu.IWB))
2829       {
2830         // For AWD/SWD, leave CHAR/BITNO alone
2831         if (sz == 36)
2832           {
2833             augend = cpu.AR[ARn].WORDNO * 36u;
2834           }
2835         else
2836           {
2837             uint bitno = GET_AR_BITNO (ARn);
2838             uint charno = GET_AR_CHAR (ARn);
2839 
2840             // The behavior of the DU for cases of CHAR > 9 is not defined; some values
2841             // are tested by ISOLTS, and have been recorded in the mapx tables; the
2842             // missing values are guessed at.
2843 
2844             uint * map;
2845             if (sz == 4)
2846               map = map4;
2847             else if (sz == 6)
2848               map = map6;
2849             else
2850               map = map9;
2851 
2852             augend = cpu.AR[ARn].WORDNO * 36u + map [charno * 16 + bitno];
2853             augend = augend % nxbits;
2854           }
2855       }
2856 
2857 //
2858 // Calculate addend
2859 //
2860 
2861     uint addend = 0;
2862     if (sz == 4)
2863       {
2864         // r is the number of 4 bit characters; each character is actually
2865         // 4.5 bits long
2866         addend = address * 36u + (r * 9) / 2;
2867 
2868         // round the odd character up one bit
2869         // (the odd character starts at bit n/2 + 1, not n/2.)
2870         if ((! sub) && r % 2) // r is odd
2871           addend ++;
2872       }
2873     else
2874       addend = address * 36u + r * sz;
2875 
2876     // Handle overflow
2877     addend = addend % nxbits;
2878 
2879 //
2880 // Calculate sum or difference
2881 //
2882 
2883     uint sum = 0;
2884     if (sub)
2885       {
2886         // Prevent underflow
2887         if (addend > augend)
2888           augend += nxbits;
2889         sum = augend - addend;
2890       }
2891     else
2892       {
2893         sum = augend + addend;
2894         sum %= nxbits;
2895       }
2896 
2897     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd augend 0%o addend 0%o sum 0%o\n", augend, addend, sum);
2898 
2899 //
2900 // Adjust to character boundary
2901 //
2902 
2903     if (sz == 6 || sz == 9)
2904       {
2905         sum = (sum / sz) * sz;
2906       }
2907 
2908 //
2909 // Convert sum to WORDNO/CHAR/BITNO
2910 //
2911 
2912     cpu.AR [ARn].WORDNO = (word18) (sum / 36u) & AMASK;
2913 
2914     // If AWD/SWD clear CHAR/BITNO
2915 
2916     if (sz == 36)
2917       {
2918         SET_AR_CHAR_BITNO (ARn, 0, 0);
2919       }
2920     else
2921       {
2922         if (sz == 4)
2923           {
2924             static uint tab [36] [2] =
2925               {
2926                 // char bitno  offset  4-bit charno
2927                 { 0, 0 }, // 0   0
2928                 { 0, 0 }, // 1
2929                 { 0, 0 }, // 2
2930                 { 0, 0 }, // 3
2931                 { 0, 0 }, // 4
2932 
2933                 { 0, 5 }, // 5   1
2934                 { 0, 5 }, // 6
2935                 { 0, 5 }, // 7
2936                 { 0, 5 }, // 8
2937 
2938                 { 1, 0 }, // 9   2
2939                 { 1, 0 }, // 10
2940                 { 1, 0 }, // 11
2941                 { 1, 0 }, // 12
2942                 { 1, 0 }, // 13
2943 
2944                 { 1, 5 }, // 15  3
2945                 { 1, 5 }, // 15
2946                 { 1, 5 }, // 16
2947                 { 1, 5 }, // 17
2948 
2949                 { 2, 0 }, // 18  4
2950                 { 2, 0 }, // 19
2951                 { 2, 0 }, // 20
2952                 { 2, 0 }, // 21
2953                 { 2, 0 }, // 22
2954 
2955                 { 2, 5 }, // 23  5
2956                 { 2, 5 }, // 24
2957                 { 2, 5 }, // 25
2958                 { 2, 5 }, // 26
2959 
2960                 { 3, 0 }, // 27  6
2961                 { 3, 0 }, // 28
2962                 { 3, 0 }, // 29
2963                 { 3, 0 }, // 30
2964                 { 3, 0 }, // 31
2965 
2966                 { 3, 5 }, // 32  7
2967                 { 3, 5 }, // 33
2968                 { 3, 5 }, // 34
2969                 { 3, 5 }  // 35
2970               };
2971             uint charno = tab [sum % 36u] [0];
2972             uint bitno = tab [sum % 36u] [1];
2973             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
2974           }
2975         else
2976           {
2977             uint charno = (sum % 36u) / 9;
2978             uint bitno = sum % 9;
2979             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
2980           }
2981       }
2982 #if defined(TESTING)
2983     HDBGRegARW (ARn, "asxbd");
2984 #endif
2985   }
2986 
2987 void cmpc (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2988   {
2989     EISstruct * e = & cpu.currentEISinstruction;
2990 
2991     // For i = 1, 2, ..., minimum (N1,N2)
2992     //    C(Y-charn1)i-1 :: C(Y-charn2)i-1
2993     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
2994     //    C(FILL) :: C(Y-charn2)i-1
2995     // If N1 > N2, then for i = N2+1, N2+2, ..., N1
2996     //    C(Y-charn1)i-1 :: C(FILL)
2997     //
2998     // Indicators:
2999     //     Zero: If C(Y-charn1)i-1 = C(Y-charn2)i-1 for all i, then ON;
3000     //       otherwise, OFF
3001     //     Carry: If C(Y-charn1)i-1 < C(Y-charn2)i-1 for any i, then OFF;
3002     //       otherwise ON
3003 
3004     // Both strings are treated as the data type given for the left-hand
3005     // string, TA1. A data type given for the right-hand string, TA2, is
3006     // ignored.
3007     //
3008     // Comparison is made on full 9-bit fields. If the given data type is not
3009     // 9-bit (TA1 ≠ 0), then characters from C(Y-charn1) and C(Y-charn2) are
3010     // high- order zero filled. All 9 bits of C(FILL) are used.
3011     //
3012     // Instruction execution proceeds until an inequality is found or the
3013     // larger string length count is exhausted.
3014 
3015     fault_ipr_subtype_ mod_fault = 0;
3016 
3017 #if !defined(EIS_SETUP)
3018     setupOperandDescriptor (cpup, 1, &mod_fault);
3019     setupOperandDescriptor (cpup, 2, &mod_fault);
3020 #endif
3021     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3022     parseAlphanumericOperandDescriptor (cpup, 2, 1, false, &mod_fault);
3023 
3024     L68_ (
3025       // L68 raises it immediately
3026       if (mod_fault)
3027         {
3028           doFault (FAULT_IPR,
3029                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3030                    "Illegal modifier");
3031         }
3032     )
3033 
3034     // Bits 9-10 MBZ
3035     if (IWB_IRODD & 0000600000000)
3036       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpc 9-10 MBZ");
3037 
3038     // Bit 23 of OP1 MBZ
3039     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3040       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "cmpc op1 23 MBZ");
3041 
3042 // ISOLTS ps846    test-07a    dec add test
3043 // Sets TA2 to the same as TA1. AL39 says TA2 ignored.
3044 // Try only check bit 23.
3045 // ISOLTS 880 test-04c sets bit 23.
3046 
3047 
3048 
3049 
3050 
3051 
3052 
3053 
3054     DPS8M_ (
3055       // DPS8M raises it delayed
3056       if (mod_fault)
3057         {
3058           doFault (FAULT_IPR,
3059                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3060                    "Illegal modifier");
3061         }
3062     )
3063 
3064     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
3065 
3066     SET_I_ZERO;  // set ZERO flag assuming strings are equal ...
3067     SET_I_CARRY; // set CARRY flag assuming strings are equal ...
3068 
3069     PNL (L68_ (if (max (e->N1, e->N2) < 128)
3070       DU_CYCLE_FLEN_128;))
3071 
3072     for (; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
3073       {
3074         word9 c1 = EISget469 (cpup, 1, cpu.du.CHTALLY); // get Y-char1n
3075         word9 c2 = EISget469 (cpup, 2, cpu.du.CHTALLY); // get Y-char2n
3076 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpc tally %d c1 %03o c2 %03o\n", cpu.du.CHTALLY, c1, c2);
3077         if (c1 != c2)
3078           {
3079             CLR_I_ZERO;  // an inequality found
3080             SC_I_CARRY (c1 > c2);
3081             cleanupOperandDescriptor (cpup, 1);
3082             cleanupOperandDescriptor (cpup, 2);
3083             return;
3084           }
3085       }
3086 
3087     if (e -> N1 < e -> N2)
3088       {
3089         for( ; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY ++)
3090           {
3091             word9 c1 = fill;     // use fill for Y-char1n
3092             word9 c2 = EISget469 (cpup, 2, cpu.du.CHTALLY); // get Y-char2n
3093 
3094             if (c1 != c2)
3095               {
3096                 CLR_I_ZERO;  // an inequality found
3097                 SC_I_CARRY (c1 > c2);
3098                 cleanupOperandDescriptor (cpup, 1);
3099                 cleanupOperandDescriptor (cpup, 2);
3100                 return;
3101               }
3102           }
3103       }
3104     else if (e->N1 > e->N2)
3105       {
3106         for ( ; cpu.du.CHTALLY < e->N1; cpu.du.CHTALLY ++)
3107           {
3108             word9 c1 = EISget469 (cpup, 1, cpu.du.CHTALLY); // get Y-char1n
3109             word9 c2 = fill;   // use fill for Y-char2n
3110 
3111             if (c1 != c2)
3112               {
3113                 CLR_I_ZERO;  // an inequality found
3114                 SC_I_CARRY (c1 > c2);
3115                 cleanupOperandDescriptor (cpup, 1);
3116                 cleanupOperandDescriptor (cpup, 2);
3117                 return;
3118               }
3119           }
3120       }
3121     // else ==
3122     cleanupOperandDescriptor (cpup, 1);
3123     cleanupOperandDescriptor (cpup, 2);
3124   }
3125 
3126 /*
3127  * SCD - Scan Characters Double
3128  */
3129 
3130 void scd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3131   {
3132     EISstruct * e = & cpu.currentEISinstruction;
3133 
3134     // For i = 1, 2, ..., N1-1
3135     //   C(Y-charn1)i-1,i :: C(Y-charn2)0,1
3136     // On instruction completion, if a match was found:
3137     //   00...0 → C(Y3)0,11
3138     //   i-1 → C(Y3)12,35
3139     // If no match was found:
3140     //   00...0 → C(Y3)0,11
3141     //      N1-1→ C(Y3)12,35
3142     //
3143 
3144     // The REG field of MF1 is checked for a legal code. If DU is specified in
3145     // the REG field of MF2 in one of the four multiword instructions (SCD,
3146     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3147     // the character or characters are arranged within the 18 bits of the word
3148     // address portion of the operand descriptor.
3149 
3150     fault_ipr_subtype_ mod_fault = 0;
3151 
3152 #if !defined(EIS_SETUP)
3153     setupOperandDescriptor (cpup, 1, &mod_fault);
3154     setupOperandDescriptor (cpup, 2, &mod_fault);
3155     setupOperandDescriptorCache (cpup,3);
3156 #endif
3157 
3158     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3159     parseAlphanumericOperandDescriptor (cpup, 2, 1, true, &mod_fault); // use TA1
3160     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3161 
3162     L68_ (
3163       // L68 raises it immediately
3164       if (mod_fault)
3165         {
3166           doFault (FAULT_IPR,
3167                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3168                    "Illegal modifier");
3169         }
3170     )
3171 
3172     // Bits 0-10 MBZ
3173     if (IWB_IRODD & 0777600000000)
3174       {
3175         //sim_printf ("scd %12"PRIo64"\n", IWB_IRODD);
3176         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scd 0-10 MBZ");
3177       }
3178 
3179     // Bit 23 of OP1 MBZ
3180     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3181       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op1 23 MBZ");
3182 
3183     // Bits 18-28. 30-31 of OP3 MBZ
3184     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3185       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op3 18-28. 30-31 MBZ");
3186 
3187     DPS8M_ (
3188       // DPS8M raises it delayed
3189       if (mod_fault)
3190         {
3191           doFault (FAULT_IPR,
3192                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3193                    "Illegal modifier");
3194         }
3195     )
3196 
3197     // Both the string and the test character pair are treated as the data type
3198     // given for the string, TA1. A data type given for the test character
3199     // pair, TA2, is ignored.
3200 
3201     // fetch 'test' char - double
3202     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3203     // instruction word does not contain an operand descriptor for the test
3204     // character; instead, it contains the test character as a direct upper
3205     // operand in bits 0,8.
3206 
3207     word9 c1 = 0;
3208     word9 c2 = 0;
3209 
3210     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3211       {
3212         // per Bull RJ78, p. 5-45
3213 #if defined(EIS_PTR3)
3214         switch (TA1) // Use TA1, not TA2
3215 #else
3216         switch (e -> TA1) // Use TA1, not TA2
3217 #endif
3218         {
3219             case CTA4:
3220 #if defined(EIS_PTR)
3221               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3222               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3223 #else
3224               c1 = (e -> ADDR2.address >> 13) & 017;
3225               c2 = (e -> ADDR2.address >>  9) & 017;
3226 #endif
3227               break;
3228 
3229             case CTA6:
3230 #if defined(EIS_PTR)
3231               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3232               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3233 #else
3234               c1 = (e -> ADDR2.address >> 12) & 077;
3235               c2 = (e -> ADDR2.address >>  6) & 077;
3236 #endif
3237               break;
3238 
3239             case CTA9:
3240 #if defined(EIS_PTR)
3241               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3242               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3243 #else
3244               c1 = (e -> ADDR2.address >> 9) & 0777;
3245               c2 = (e -> ADDR2.address     ) & 0777;
3246 #endif
3247               break;
3248           }
3249       }
3250     else
3251       {
3252         c1 = EISget469 (cpup, 2, 0);
3253         c2 = EISget469 (cpup, 2, 1);
3254       }
3255 
3256 #if defined(EIS_PTR3)
3257     switch (TA1) // Use TA1, not TA2
3258 #else
3259     switch (e -> TA1) // Use TA1, not TA2
3260 #endif
3261       {
3262         case CTA4:
3263           c1 &= 017;    // keep 4-bits
3264           c2 &= 017;    // keep 4-bits
3265           break;
3266 
3267         case CTA6:
3268           c1 &= 077;    // keep 6-bits
3269           c2 &= 077;    // keep 6-bits
3270           break;
3271 
3272         case CTA9:
3273           c1 &= 0777;   // keep 9-bits
3274           c2 &= 0777;   // keep 9-bits
3275           break;
3276       }
3277 
3278     PNL (L68_ (if (e->N1 < 128)
3279       DU_CYCLE_FLEN_128;))
3280 
3281     word9 yCharn11;
3282     word9 yCharn12;
3283     if (e -> N1)
3284       {
3285         uint limit = e -> N1 - 1;
3286         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3287           {
3288             yCharn11 = EISget469 (cpup, 1, cpu.du.CHTALLY);
3289             yCharn12 = EISget469 (cpup, 1, cpu.du.CHTALLY + 1);
3290             if (yCharn11 == c1 && yCharn12 == c2)
3291               break;
3292           }
3293         SC_I_TALLY (cpu.du.CHTALLY == limit);
3294       }
3295     else
3296       {
3297         SET_I_TALLY;
3298       }
3299 
3300     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3301     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3302     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3303 
3304     cleanupOperandDescriptor (cpup, 1);
3305     cleanupOperandDescriptor (cpup, 2);
3306     cleanupOperandDescriptor (cpup, 3);
3307  }
3308 
3309 /*
3310  * SCDR - Scan Characters Double Reverse
3311  */
3312 
3313 void scdr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3314   {
3315     EISstruct * e = & cpu.currentEISinstruction;
3316 
3317     // For i = 1, 2, ..., N1-1
3318     //   C(Y-charn1)N1-i-1,N1-i :: C(Y-charn2)0,1
3319     // On instruction completion, if a match was found:
3320     //   00...0 → C(Y3)0,11
3321     //   i-1 → C(Y3)12,35
3322     // If no match was found:
3323     //   00...0 → C(Y3)0,11
3324     //      N1-1→ C(Y3)12,35
3325     //
3326 
3327     // The REG field of MF1 is checked for a legal code. If DU is specified in
3328     // the REG field of MF2 in one of the four multiword instructions (SCD,
3329     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3330     // the character or characters are arranged within the 18 bits of the word
3331     // address portion of the operand descriptor.
3332 
3333     fault_ipr_subtype_ mod_fault = 0;
3334 
3335 #if !defined(EIS_SETUP)
3336     setupOperandDescriptor(cpup, 1, &mod_fault);
3337     setupOperandDescriptor(cpup, 2, &mod_fault);
3338     setupOperandDescriptorCache(cpup,3);
3339 #endif
3340 
3341     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
3342     parseAlphanumericOperandDescriptor(cpup, 2, 1, true, &mod_fault); // Use TA1
3343     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3344 
3345     L68_ (
3346       // L68 raises it immediately
3347       if (mod_fault)
3348         {
3349           doFault (FAULT_IPR,
3350                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3351                    "Illegal modifier");
3352         }
3353     )
3354 
3355     // Bits 0-10 MBZ
3356     if (IWB_IRODD & 0777600000000)
3357       {
3358         //sim_printf ("scdr %12"PRIo64"\n", IWB_IRODD);
3359         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scdr 0-10 MBZ");
3360       }
3361 
3362     // Bit 23 of OP1 MBZ
3363     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3364       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op1 23 MBZ");
3365 
3366     // Bits 18-28. 30-31 of OP3 MBZ
3367     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3368       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op3 18-28. 30-31 MBZ");
3369 
3370     DPS8M_ (
3371       // DPS8M raises it delayed
3372       if (mod_fault)
3373         {
3374           doFault (FAULT_IPR,
3375                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3376                    "Illegal modifier");
3377         }
3378     )
3379 
3380     // Both the string and the test character pair are treated as the data type
3381     // given for the string, TA1. A data type given for the test character
3382     // pair, TA2, is ignored.
3383 
3384     // fetch 'test' char - double
3385     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3386     // instruction word does not contain an operand descriptor for the test
3387     // character; instead, it contains the test character as a direct upper
3388     // operand in bits 0,8.
3389 
3390     word9 c1 = 0;
3391     word9 c2 = 0;
3392 
3393     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3394       {
3395         // per Bull RJ78, p. 5-45
3396 #if defined(EIS_PTR3)
3397         switch (TA1) // Use TA1, not TA2
3398 #else
3399         switch (e -> TA1)
3400 #endif
3401           {
3402             case CTA4:
3403 #if defined(EIS_PTR)
3404               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3405               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3406 #else
3407               c1 = (e -> ADDR2.address >> 13) & 017;
3408               c2 = (e -> ADDR2.address >>  9) & 017;
3409 #endif
3410               break;
3411 
3412             case CTA6:
3413 #if defined(EIS_PTR)
3414               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3415               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3416 #else
3417               c1 = (e -> ADDR2.address >> 12) & 077;
3418               c2 = (e -> ADDR2.address >>  6) & 077;
3419 #endif
3420               break;
3421 
3422             case CTA9:
3423 #if defined(EIS_PTR)
3424               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3425               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3426 #else
3427               c1 = (e -> ADDR2.address >> 9) & 0777;
3428               c2 = (e -> ADDR2.address     ) & 0777;
3429 #endif
3430               break;
3431           }
3432       }
3433     else
3434       {
3435         c1 = EISget469 (cpup, 2, 0);
3436         c2 = EISget469 (cpup, 2, 1);
3437       }
3438 
3439 #if defined(EIS_PTR3)
3440     switch (TA1) // Use TA1, not TA2
3441 #else
3442     switch (e -> TA1) // Use TA1, not TA2
3443 #endif
3444       {
3445         case CTA4:
3446           c1 &= 017;    // keep 4-bits
3447           c2 &= 017;    // keep 4-bits
3448           break;
3449 
3450         case CTA6:
3451           c1 &= 077;    // keep 6-bits
3452           c2 &= 077;    // keep 6-bits
3453           break;
3454 
3455         case CTA9:
3456           c1 &= 0777;   // keep 9-bits
3457           c2 &= 0777;   // keep 9-bits
3458           break;
3459       }
3460 
3461     word9 yCharn11;
3462     word9 yCharn12;
3463 
3464     PNL (L68_ (if (e->N1 < 128)
3465       DU_CYCLE_FLEN_128;))
3466 
3467     if (e -> N1)
3468       {
3469         uint limit = e -> N1 - 1;
3470 
3471         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3472           {
3473             yCharn11 = EISget469 (cpup, 1, limit - cpu.du.CHTALLY - 1);
3474             yCharn12 = EISget469 (cpup, 1, limit - cpu.du.CHTALLY);
3475 
3476             if (yCharn11 == c1 && yCharn12 == c2)
3477                 break;
3478           }
3479         SC_I_TALLY (cpu.du.CHTALLY == limit);
3480       }
3481     else
3482       {
3483         SET_I_TALLY;
3484       }
3485 
3486     //word36 CY3 = bitfieldInsert36(0, cpu.du.CHTALLY, 0, 24);
3487     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3488     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3489 
3490     cleanupOperandDescriptor (cpup, 1);
3491     cleanupOperandDescriptor (cpup, 2);
3492     cleanupOperandDescriptor (cpup, 3);
3493   }
3494 
3495 /*
3496  * SCM - Scan with Mask
3497  */
3498 
3499 void scm (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3500   {
3501     EISstruct * e = & cpu.currentEISinstruction;
3502 
3503     // For characters i = 1, 2, ..., N1
3504     //   For bits j = 0, 1, ..., 8
3505     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j ⊕ (C(Y-charn2)0)j)
3506     //      If C(Z)0,8 = 00...0, then
3507     //           00...0 → C(Y3)0,11
3508     //           i-1 → C(Y3)12,35
3509     //      otherwise, continue scan of C(Y-charn1)
3510     // If a masked character match was not found, then
3511     //   00...0 → C(Y3)0,11
3512     //   N1 → C(Y3)12,35
3513 
3514     // Starting at location YC1, the L1 type TA1 characters are masked and
3515     // compared with the assumed type TA1 character contained either in
3516     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3517     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3518     // mask is right-justified in bit positions 0-8 of the instruction word.
3519     // Each bit position of the mask that is a 1 prevents that bit position in
3520     // the two characters from entering into the compare.
3521 
3522     // The masked compare operation continues until either a match is found or
3523     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3524     // incremented by 1. When a match is found or when the L1 tally runs out,
3525     // this count is stored right-justified in bits 12-35 of location Y3 and
3526     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3527     // string remain unchanged. The RL bit of the MF2 field is not used.
3528 
3529     // The REG field of MF1 is checked for a legal code. If DU is specified in
3530     // the REG field of MF2 in one of the four multiword instructions (SCD,
3531     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3532     // the character or characters are arranged within the 18 bits of the word
3533     // address portion of the operand descriptor.
3534 
3535     fault_ipr_subtype_ mod_fault = 0;
3536 
3537 #if !defined(EIS_SETUP)
3538     setupOperandDescriptor (cpup, 1, &mod_fault);
3539     setupOperandDescriptor (cpup, 2, &mod_fault);
3540     setupOperandDescriptorCache (cpup,3);
3541 #endif
3542 
3543     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3544     parseAlphanumericOperandDescriptor (cpup, 2, 1, true, &mod_fault);
3545     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3546 
3547     L68_ (
3548       // L68 raises it immediately
3549       if (mod_fault)
3550         {
3551           doFault (FAULT_IPR,
3552                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3553                    "Illegal modifier");
3554         }
3555     )
3556 
3557     // Bits 9-10 MBZ
3558     if (IWB_IRODD & 0000600000000)
3559       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scm 9-10 MBZ");
3560 
3561     // Bit 23 of OP1 MBZ
3562     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3563       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op1 23 MBZ");
3564 
3565     // Bits 18-28, 39-31 of OP3 MBZ
3566     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3567       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op3 18-28, 39-31 MBZ");
3568 
3569     DPS8M_ (
3570       // DPS8M raises it delayed
3571       if (mod_fault)
3572         {
3573           doFault (FAULT_IPR,
3574                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3575                    "Illegal modifier");
3576         }
3577     )
3578 
3579     // Both the string and the test character pair are treated as the data type
3580     // given for the string, TA1. A data type given for the test character
3581     // pair, TA2, is ignored.
3582 
3583     // get 'mask'
3584     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3585 
3586     // fetch 'test' char
3587     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3588     // instruction word does not contain an operand descriptor for the test
3589     // character; instead, it contains the test character as a direct upper
3590     // operand in bits 0,8.
3591 
3592     word9 ctest = 0;
3593     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3594       {
3595         word18 duo = GETHI (e -> OP2);
3596         // per Bull RJ78, p. 5-45
3597 #if defined(EIS_PTR3)
3598         switch (TA1) // Use TA1, not TA2
3599 #else
3600         switch (e -> TA1)
3601 #endif
3602           {
3603             case CTA4:
3604               ctest = (duo >> 13) & 017;
3605               break;
3606             case CTA6:
3607               ctest = (duo >> 12) & 077;
3608               break;
3609             case CTA9:
3610               ctest = (duo >> 9) & 0777;
3611               break;
3612           }
3613       }
3614     else
3615       {
3616         ctest = EISget469 (cpup, 2, 0);
3617       }
3618 
3619 #if defined(EIS_PTR3)
3620     switch (TA1) // Use TA1, not TA2
3621 #else
3622     switch (e -> TA1) // use TA1, not TA2
3623 #endif
3624       {
3625         case CTA4:
3626             ctest &= 017;    // keep 4-bits
3627             break;
3628         case CTA6:
3629             ctest &= 077;    // keep 6-bits
3630             break;
3631         case CTA9:
3632             ctest &= 0777;   // keep 9-bits
3633       }
3634 
3635     PNL (L68_ (if (e->N1 < 128)
3636       DU_CYCLE_FLEN_128;))
3637 
3638     uint limit = e -> N1;
3639 
3640     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3641       {
3642         word9 yCharn1 = EISget469 (cpup, 1, cpu.du.CHTALLY);
3643         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3644         if (c == 0)
3645           {
3646             //00...0 → C(Y3)0,11
3647             //i-1 → C(Y3)12,35
3648             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3649             break;
3650           }
3651       }
3652     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3653     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3654 
3655     SC_I_TALLY (cpu.du.CHTALLY == limit);
3656 
3657     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3658 
3659     cleanupOperandDescriptor (cpup, 1);
3660     cleanupOperandDescriptor (cpup, 2);
3661     cleanupOperandDescriptor (cpup, 3);
3662   }
3663 /*
3664  * SCMR - Scan with Mask in Reverse
3665  */
3666 
3667 void scmr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3668   {
3669     EISstruct * e = & cpu.currentEISinstruction;
3670 
3671     // For characters i = 1, 2, ..., N1
3672     //   For bits j = 0, 1, ..., 8
3673     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j ⊕ (C(Y-charn2)0)j)
3674     //      If C(Z)0,8 = 00...0, then
3675     //           00...0 → C(Y3)0,11
3676     //           i-1 → C(Y3)12,35
3677     //      otherwise, continue scan of C(Y-charn1)
3678     // If a masked character match was not found, then
3679     //   00...0 → C(Y3)0,11
3680     //   N1 → C(Y3)12,35
3681 
3682     // Starting at location YC1, the L1 type TA1 characters are masked and
3683     // compared with the assumed type TA1 character contained either in
3684     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3685     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3686     // mask is right-justified in bit positions 0-8 of the instruction word.
3687     // Each bit position of the mask that is a 1 prevents that bit position in
3688     // the two characters from entering into the compare.
3689 
3690     // The masked compare operation continues until either a match is found or
3691     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3692     // incremented by 1. When a match is found or when the L1 tally runs out,
3693     // this count is stored right-justified in bits 12-35 of location Y3 and
3694     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3695     // string remain unchanged. The RL bit of the MF2 field is not used.
3696 
3697     // The REG field of MF1 is checked for a legal code. If DU is specified in
3698     // the REG field of MF2 in one of the four multiword instructions (SCD,
3699     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3700     // the character or characters are arranged within the 18 bits of the word
3701     // address portion of the operand descriptor.
3702 
3703     fault_ipr_subtype_ mod_fault = 0;
3704 
3705 #if !defined(EIS_SETUP)
3706     setupOperandDescriptor (cpup, 1, &mod_fault);
3707     setupOperandDescriptor (cpup, 2, &mod_fault);
3708     setupOperandDescriptorCache (cpup,3);
3709 #endif
3710 
3711     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3712     parseAlphanumericOperandDescriptor (cpup, 2, 1, true, &mod_fault);
3713     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3714 
3715     L68_ (
3716       // L68 raises it immediately
3717       if (mod_fault)
3718         {
3719           doFault (FAULT_IPR,
3720                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3721                    "Illegal modifier");
3722         }
3723     )
3724 
3725     // Bits 9-10 MBZ
3726     if (IWB_IRODD & 0000600000000)
3727       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scmr 9-10 MBZ");
3728 
3729     // Bit 23 of OP1 MBZ
3730     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3731       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op1 23 MBZ");
3732 
3733     // Bits 18 of OP3 MBZ
3734     //if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000400000)
3735     //  doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18 MBZ");
3736 
3737     // Bits 18-28, 39-31 of OP3 MBZ
3738     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3739       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18-28, 39-31 MBZ");
3740 
3741     DPS8M_ (
3742       // DPS8M raises it delayed
3743       if (mod_fault)
3744         {
3745           doFault (FAULT_IPR,
3746                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3747                    "Illegal modifier");
3748         }
3749     )
3750 
3751     // Both the string and the test character pair are treated as the data type
3752     // given for the string, TA1. A data type given for the test character
3753     // pair, TA2, is ignored.
3754 
3755     // get 'mask'
3756     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3757 
3758     // fetch 'test' char
3759     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3760     // instruction word does not contain an operand descriptor for the test
3761     // character; instead, it contains the test character as a direct upper
3762     // operand in bits 0,8.
3763 
3764     word9 ctest = 0;
3765     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3766       {
3767         word18 duo = GETHI (e -> OP2);
3768         // per Bull RJ78, p. 5-45
3769 #if defined(EIS_PTR3)
3770         switch (TA1) // Use TA1, not TA2
3771 #else
3772         switch (e -> TA1)
3773 #endif
3774           {
3775             case CTA4:
3776               ctest = (duo >> 13) & 017;
3777               break;
3778             case CTA6:
3779               ctest = (duo >> 12) & 077;
3780               break;
3781             case CTA9:
3782               ctest = (duo >> 9) & 0777;
3783               break;
3784           }
3785       }
3786     else
3787       {
3788         ctest = EISget469 (cpup, 2, 0);
3789       }
3790 
3791 #if defined(EIS_PTR3)
3792     switch (TA1) // Use TA1, not TA2
3793 #else
3794     switch (e -> TA1) // use TA1, not TA2
3795 #endif
3796       {
3797         case CTA4:
3798             ctest &= 017;    // keep 4-bits
3799             break;
3800         case CTA6:
3801             ctest &= 077;    // keep 6-bits
3802             break;
3803         case CTA9:
3804             ctest &= 0777;   // keep 9-bits
3805       }
3806 
3807     PNL (L68_ (if (e->N1 < 128)
3808       DU_CYCLE_FLEN_128;))
3809 
3810     uint limit = e -> N1;
3811     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3812       {
3813         word9 yCharn1 = EISget469 (cpup, 1, limit - cpu.du.CHTALLY - 1);
3814         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3815         if (c == 0)
3816           {
3817             //00...0 → C(Y3)0,11
3818             //i-1 → C(Y3)12,35
3819             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3820             break;
3821           }
3822       }
3823     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3824     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3825 
3826     SC_I_TALLY (cpu.du.CHTALLY == limit);
3827 
3828     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3829 
3830     cleanupOperandDescriptor (cpup, 1);
3831     cleanupOperandDescriptor (cpup, 2);
3832     cleanupOperandDescriptor (cpup, 3);
3833   }
3834 
3835 /*
3836  * TCT - Test Character and Translate
3837  */
3838 
3839 
3840 
3841 
3842 
3843 
3844 
3845 
3846 
3847 
3848 
3849 
3850 
3851 
3852 
3853 
3854 
3855 
3856 
3857 
3858 
3859 
3860 static word9 xlate (cpu_state_t * cpup, EISaddr * xlatTbl, uint dstTA, uint c)
     /* [previous][next][first][last][top][bottom][index][help] */
3861   {
3862     uint idx = (c / 4) & 0177;      // max 128-words (7-bit index)
3863     word36 entry = EISReadIdx(cpup, xlatTbl, idx);
3864 
3865     uint pos9 = c % 4;      // lower 2-bits
3866     word9 cout = GETBYTE (entry, pos9);
3867     switch (dstTA)
3868       {
3869         case CTA4:
3870           return cout & 017;
3871         case CTA6:
3872           return cout & 077;
3873         case CTA9:
3874           return cout;
3875       }
3876     return 0;
3877   }
3878 
3879 void tct (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3880   {
3881     EISstruct * e = & cpu.currentEISinstruction;
3882 
3883     // For i = 1, 2, ..., N1
3884     //   m = C(Y-charn1)i-1
3885     //   If C(Y-char92)m ≠ 00...0, then
3886     //     C(Y-char92)m → C(Y3)0,8
3887     //     000 → C(Y3)9,11
3888     //     i-1 → C(Y3)12,35
3889     //   otherwise, continue scan of C(Y-charn1)
3890     // If a non-zero table entry was not found, then 00...0 → C(Y3)0,11
3891     // N1 → C(Y3)12,35
3892     //
3893     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
3894     // otherwise, OFF
3895     //
3896     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
3897     // then characters from C(Y-charn1) are high-order zero filled in forming
3898     // the table index, m.
3899     // Instruction execution proceeds until a non-zero table entry is found or
3900     // the string length count is exhausted.
3901     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
3902     // on a word boundary.
3903 
3904     fault_ipr_subtype_ mod_fault = 0;
3905 
3906 #if !defined(EIS_SETUP)
3907     setupOperandDescriptor (cpup, 1, &mod_fault);
3908     setupOperandDescriptorCache (cpup,2);
3909     setupOperandDescriptorCache (cpup,3);
3910 #endif
3911 
3912     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3913     parseArgOperandDescriptor (cpup, 2, &mod_fault);
3914     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3915 
3916     L68_ (
3917       // L68 raises it immediately
3918       if (mod_fault)
3919         {
3920           doFault (FAULT_IPR,
3921                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3922                    "Illegal modifier");
3923         }
3924     )
3925 
3926     // Bits 0-17 MBZ
3927     if (IWB_IRODD & 0777777000000)
3928       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tct 0-17 MBZ");
3929 
3930     // Bit 23 of OP1 MBZ
3931     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3932       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op1 23 MBZ");
3933 
3934     // Bits 18-28, 39-31 of OP2 MBZ
3935     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
3936       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op2 18-28, 39-31 MBZ");
3937 
3938     // Bits 18-28, 39-31 of OP3 MBZ
3939     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3940       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op3 18-28, 39-31 MBZ");
3941 
3942     DPS8M_ (
3943       // DPS8M raises it delayed
3944       if (mod_fault)
3945         {
3946           doFault (FAULT_IPR,
3947                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3948                    "Illegal modifier");
3949         }
3950     )
3951 
3952 #if defined(EIS_PTR3)
3953     sim_debug (DBG_TRACEEXT, & cpu_dev,
3954                "TCT CN1: %d TA1: %d\n", e -> CN1, TA1);
3955 #else
3956     sim_debug (DBG_TRACEEXT, & cpu_dev,
3957                "TCT CN1: %d TA1: %d\n", e -> CN1, e -> TA1);
3958 #endif
3959 
3960     uint srcSZ = 0;
3961 
3962 #if defined(EIS_PTR3)
3963     switch (TA1)
3964 #else
3965     switch (e -> TA1)
3966 #endif
3967       {
3968         case CTA4:
3969             srcSZ = 4;
3970             break;
3971         case CTA6:
3972             srcSZ = 6;
3973             break;
3974         case CTA9:
3975             srcSZ = 9;
3976             break;
3977       }
3978 
3979     // ISOLTS-878 01h asserts no prepaging
3980 
3981 
3982 
3983 
3984 
3985 
3986 
3987 
3988 
3989 
3990 
3991 
3992 
3993 
3994 
3995 
3996 
3997 
3998 
3999 
4000 
4001 
4002 
4003 
4004 
4005 
4006 
4007 
4008 
4009 
4010 
4011 
4012 
4013 
4014 
4015 
4016 
4017 
4018     word36 CY3 = 0;
4019 
4020     sim_debug (DBG_TRACEEXT, & cpu_dev,
4021                "TCT N1 %d\n", e -> N1);
4022 
4023     PNL (L68_ (if (e->N1 < 128)
4024       DU_CYCLE_FLEN_128;))
4025 
4026     for ( ; cpu.du.CHTALLY < e -> N1; cpu.du.CHTALLY ++)
4027       {
4028         word9 c = EISget469 (cpup, 1, cpu.du.CHTALLY); // get src char
4029 
4030         uint m = 0;
4031 
4032         switch (srcSZ)
4033           {
4034             case 4:
4035               m = c & 017;    // truncate upper 2-bits
4036               break;
4037             case 6:
4038               m = c & 077;    // truncate upper 3-bits
4039               break;
4040             case 9:
4041               m = c;          // keep all 9-bits
4042               break;              // should already be 0-filled
4043           }
4044 
4045         word9 cout = xlate (cpup, &e->ADDR2, CTA9, m);
4046 
4047         sim_debug (DBG_TRACEEXT, & cpu_dev,
4048                    "TCT c %03o %c cout %03o %c\n",
4049                    m, isprint ((int) m) ? '?' : (char) m,
4050                    cout, isprint ((int) cout) ? '?' : (char) cout);
4051 
4052         if (cout)
4053           {
4054             // CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4055             CY3 = setbits36_9 (0, 0, cout);
4056             break;
4057           }
4058       }
4059 
4060     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4061 
4062     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4063     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4064     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
4065 
4066     cleanupOperandDescriptor (cpup, 1);
4067     cleanupOperandDescriptor (cpup, 2);
4068     cleanupOperandDescriptor (cpup, 3);
4069   }
4070 
4071 void tctr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4072   {
4073     EISstruct * e = & cpu.currentEISinstruction;
4074 
4075     // For i = 1, 2, ..., N1
4076     //   m = C(Y-charn1)N1-i
4077     //   If C(Y-char92)m ≠ 00...0, then
4078     //     C(Y-char92)m → C(Y3)0,8
4079     //     000 → C(Y3)9,11
4080     //     i-1 → C(Y3)12,35
4081     //   otherwise, continue scan of C(Y-charn1) If a non-zero table entry was
4082     //   not found, then
4083     // 00...0 → C(Y3)0,11
4084     // N1 → C(Y3)12,35
4085     //
4086     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
4087     // otherwise, OFF
4088     //
4089     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
4090     // then characters from C(Y-charn1) are high-order zero filled in forming
4091     // the table index, m.
4092 
4093     // Instruction execution proceeds until a non-zero table entry is found or
4094     // the string length count is exhausted.
4095 
4096     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
4097     // on a word boundary.
4098 
4099     fault_ipr_subtype_ mod_fault = 0;
4100 
4101 #if !defined(EIS_SETUP)
4102     setupOperandDescriptor (cpup, 1, &mod_fault);
4103     setupOperandDescriptorCache (cpup,2);
4104     setupOperandDescriptorCache (cpup,3);
4105 #endif
4106 
4107     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
4108     parseArgOperandDescriptor (cpup, 2, &mod_fault);
4109     parseArgOperandDescriptor (cpup, 3, &mod_fault);
4110 
4111     L68_ (
4112       // L68 raises it immediately
4113       if (mod_fault)
4114         {
4115           doFault (FAULT_IPR,
4116                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4117                    "Illegal modifier");
4118         }
4119     )
4120 
4121     // Bits 0-17 MBZ
4122     if (IWB_IRODD & 0777777000000)
4123       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tctr 0-17 MBZ");
4124 
4125     // Bit 23 of OP1 MBZ
4126     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4127       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op1 23 MBZ");
4128 
4129     // Bits 18-28, 39-31 of OP2 MBZ
4130     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
4131       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op2 18-28, 39-31 MBZ");
4132 
4133     // Bits 18-28, 39-31 of OP3 MBZ
4134     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
4135       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op3 18-28, 39-31 MBZ");
4136 
4137     DPS8M_ (
4138       // DPS8M raises it delayed
4139       if (mod_fault)
4140         {
4141           doFault (FAULT_IPR,
4142                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4143                    "Illegal modifier");
4144         }
4145     )
4146 
4147 #if defined(EIS_PTR3)
4148     sim_debug (DBG_TRACEEXT, & cpu_dev,
4149                "TCTR CN1: %d TA1: %d\n", e -> CN1, TA1);
4150 #else
4151     sim_debug (DBG_TRACEEXT, & cpu_dev,
4152                "TCTR CN1: %d TA1: %d\n", e -> CN1, e -> TA1);
4153 #endif
4154 
4155     uint srcSZ = 0;
4156 
4157 #if defined(EIS_PTR3)
4158     switch (TA1)
4159 #else
4160     switch (e -> TA1)
4161 #endif
4162       {
4163         case CTA4:
4164             srcSZ = 4;
4165             break;
4166         case CTA6:
4167             srcSZ = 6;
4168             break;
4169         case CTA9:
4170             srcSZ = 9;
4171             break;
4172       }
4173 
4174     // ISOLTS-878 01i asserts no prepaging
4175 
4176 
4177 
4178 
4179 
4180 
4181 
4182 
4183 
4184 
4185 
4186 
4187 
4188 
4189 
4190 
4191 
4192 
4193 
4194 
4195 
4196 
4197 
4198 
4199 
4200 
4201 
4202 
4203 
4204 
4205 
4206 
4207 
4208 
4209 
4210 
4211 
4212 
4213     word36 CY3 = 0;
4214 
4215     sim_debug (DBG_TRACEEXT, & cpu_dev,
4216                "TCT N1 %d\n", e -> N1);
4217 
4218     PNL (L68_ (if (e->N1 < 128)
4219       DU_CYCLE_FLEN_128;))
4220 
4221     uint limit = e -> N1;
4222     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
4223       {
4224         word9 c = EISget469 (cpup, 1, limit - cpu.du.CHTALLY - 1); // get src char
4225 
4226         uint m = 0;
4227 
4228         switch (srcSZ)
4229           {
4230             case 4:
4231               m = c & 017;    // truncate upper 2-bits
4232               break;
4233             case 6:
4234               m = c & 077;    // truncate upper 3-bits
4235               break;
4236             case 9:
4237               m = c;          // keep all 9-bits
4238               break;              // should already be 0-filled
4239           }
4240 
4241         word9 cout = xlate (cpup, &e->ADDR2, CTA9, m);
4242 
4243         sim_debug (DBG_TRACEEXT, & cpu_dev,
4244                    "TCT c %03o %c cout %03o %c\n",
4245                    m, isprint ((int) m) ? '?' : (char) m,
4246                    cout, isprint ((int) cout) ? '?' : (char) cout);
4247 
4248         if (cout)
4249           {
4250             //CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4251             CY3 = setbits36_9 (0, 0, cout);
4252             break;
4253           }
4254       }
4255 
4256     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4257 
4258     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4259     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4260     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
4261 
4262     cleanupOperandDescriptor (cpup, 1);
4263     cleanupOperandDescriptor (cpup, 2);
4264     cleanupOperandDescriptor (cpup, 3);
4265   }
4266 
4267 /*
4268  * MLR - Move Alphanumeric Left to Right
4269  *
4270  * (Nice, simple instruction if it weren't for the stupid overpunch stuff that ruined it!!!!)
4271  */
4272 
4273 /*
4274  * does 6-bit char represent a GEBCD negative overpunch? if so, which numeral?
4275  * Refer to Bull NovaScale 9000 RJ78 Rev2 p11-178
4276  */
4277 
4278 
4279 
4280 
4281 
4282 
4283 
4284 
4285 
4286 
4287 
4288 
4289 
4290 
4291 
4292 
4293 
4294 
4295 
4296 
4297 
4298 
4299 
4300 
4301 
4302 // RJ78 p.11-178,D-6
4303 static bool isGBCDOvp (uint c, bool * isNeg)
     /* [previous][next][first][last][top][bottom][index][help] */
4304   {
4305     if (c & 020)
4306       {
4307         * isNeg = false;
4308         return true;
4309       }
4310     if (c & 040)
4311       {
4312         * isNeg = true;
4313         return true;
4314       }
4315     return false;
4316   }
4317 
4318 // Applies to both MLR and MRL
4319 //
4320 // If L1 is greater than L2, the least significant (L1-L2) characters are not moved and
4321 // the Truncation indicator is set. If L1 is less than L2, bits 0-8, 3-8, or 5-8 of the FILL
4322 // character (depending on TA2) are inserted as the least significant (L2-L1)
4323 // characters. If L1 is less than L2, bit 0 of C(FILL) = 1, TA1 = 01, and TA2 = 10
4324 // (6-4 move); the hardware looks for a 6-bit overpunched sign. If a negative
4325 // overpunch sign is found, a negative sign (octal 15) is inserted as the last FILL
4326 // character. If a negative overpunch sign is not found, a positive sign (octal 14) is
4327 // inserted as the last FILL character
4328 
4329 void mlr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4330   {
4331     EISstruct * e = & cpu.currentEISinstruction;
4332 
4333     // For i = 1, 2, ..., minimum (N1,N2)
4334     //     C(Y-charn1)N1-i → C(Y-charn2)N2-i
4335     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4336     //    C(FILL) → C(Y-charn2)N2-i
4337     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4338 
4339     fault_ipr_subtype_ mod_fault = 0;
4340 
4341 #if !defined(EIS_SETUP)
4342     setupOperandDescriptor (cpup, 1, &mod_fault);
4343     setupOperandDescriptor (cpup, 2, &mod_fault);
4344     //setupOperandDescriptorCache (cpup,3);
4345 #endif
4346 
4347     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
4348     parseAlphanumericOperandDescriptor(cpup, 2, 2, false, &mod_fault);
4349 
4350     L68_ (
4351       // L68 raises it immediately
4352       if (mod_fault)
4353         {
4354           doFault (FAULT_IPR,
4355                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4356                    "Illegal modifier");
4357         }
4358     )
4359 
4360     // Bit 10 MBZ
4361     if (IWB_IRODD & 0000200000000)
4362       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mlr 10 MBZ");
4363 
4364     // Bit 23 of OP1 MBZ
4365     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4366       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op1 23 MBZ");
4367 
4368     // Bit 23 of OP2 MBZ
4369     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4370       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op2 23 MBZ");
4371 
4372     DPS8M_ (
4373       // DPS8M raises it delayed
4374       if (mod_fault)
4375         {
4376           doFault (FAULT_IPR,
4377                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4378                    "Illegal modifier");
4379         }
4380     )
4381 
4382     int srcSZ = 0, dstSZ = 0;
4383 
4384 #if defined(EIS_PTR3)
4385     switch (TA1)
4386 #else
4387     switch (e -> TA1)
4388 #endif
4389       {
4390         case CTA4:
4391           srcSZ = 4;
4392           break;
4393         case CTA6:
4394           srcSZ = 6;
4395           break;
4396         case CTA9:
4397           srcSZ = 9;
4398           break;
4399       }
4400 
4401 #if defined(EIS_PTR3)
4402     switch (TA2)
4403 #else
4404     switch (e -> TA2)
4405 #endif
4406       {
4407         case CTA4:
4408           dstSZ = 4;
4409           break;
4410         case CTA6:
4411           dstSZ = 6;
4412           break;
4413         case CTA9:
4414           dstSZ = 9;
4415           break;
4416       }
4417 
4418     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4419 
4420     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4421     word9 fillT = fill;  // possibly truncated fill pattern
4422 
4423     // play with fill if we need to use it
4424     switch (dstSZ)
4425       {
4426         case 4:
4427           fillT = fill & 017;    // truncate upper 5-bits
4428           break;
4429         case 6:
4430           fillT = fill & 077;    // truncate upper 3-bits
4431           break;
4432       }
4433 
4434     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4435     // and the truncation indicator is set ON.
4436 
4437     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4438     // characters are high-order truncated as they are moved to C(Y-charn2). No
4439     // character conversion takes place.
4440 
4441     // The user of string replication or overlaying is warned that the decimal
4442     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4443     // units of Y-block8 words and that the overlaid string, C(Y-charn2), is
4444     // not returned to main memory until the unit of Y-block8 words is filled or
4445     // the instruction completes.
4446 
4447     // If T = 1 and the truncation indicator is set ON by execution of the
4448     // instruction, then a truncation (overflow) fault occurs.
4449 
4450     // Attempted execution with the xed instruction causes an illegal procedure
4451     // fault.
4452 
4453     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4454     // illegal procedure fault.
4455 
4456     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4457       DU_CYCLE_FLEN_128;))
4458 
4459 #if defined(EIS_PTR3)
4460     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4461                (TA2 == 2); // (6-4 move)
4462 #else
4463     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4464                (e -> TA2 == 2); // (6-4 move)
4465 #endif
4466     //word9 on;     // number overpunch represents (if any)
4467     bool isNeg = false;
4468     //bool bOvp = false;  // true when a negative overpunch character has been
4469                         // found @ N1-1
4470 
4471 #if defined(EIS_PTR3)
4472     sim_debug (DBG_TRACEEXT, & cpu_dev,
4473                "MLR TALLY %u TA1 %u TA2 %u N1 %u N2 %u CN1 %u CN2 %u\n",
4474                cpu.du.CHTALLY, TA1, TA2, e -> N1, e -> N2, e -> CN1, e -> CN2);
4475 #else
4476     sim_debug (DBG_TRACEEXT, & cpu_dev,
4477                "MLR TALLY %u TA1 %u TA2 %u N1 %u N2 %u CN1 %u CN2 %u\n",
4478                cpu.du.CHTALLY, e -> TA1, e -> TA2, e -> N1, e -> N2, e -> CN1, e -> CN2);
4479 #endif
4480 
4481 //
4482 // Multics frequently uses certain code sequences which are easily detected
4483 // and optimized; eg. it uses the MLR instruction to copy or zero segments.
4484 //
4485 // The MLR implementation is correct, not efficient. Copy invokes 12 append
4486 // cycles per word, and fill 8.
4487 //
4488 
4489 //
4490 // Page copy
4491 //
4492 
4493     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4494 #if defined(EIS_PTR3)
4495         TA1 == CTA9 &&  // src and dst are both char 9
4496         TA2 == CTA9 &&
4497 #else
4498         e -> TA1 == CTA9 &&  // src and dst are both char 9
4499         e -> TA2 == CTA9 &&
4500 #endif
4501         (e -> N1 % (PGSZ * 4)) == 0 &&  // a page
4502         e -> N2 == e -> N1 && // the src is the same size as the dest.
4503         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4504         e -> CN2 == 0 &&
4505 #if defined(EIS_PTR)
4506         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4507         (cpu.du.D2_PTR_W & PGMK) == 0)
4508 #else
4509         (e -> ADDR1.address & PGMK) == 0 &&
4510         (e -> ADDR2.address & PGMK) == 0)
4511 #endif
4512       {
4513         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #3\n");
4514         while (cpu.du.CHTALLY < e -> N1)
4515           {
4516             word36 pg [PGSZ];
4517             EISReadPage (cpup, & e -> ADDR1, cpu.du.CHTALLY / 4, pg);
4518             EISWritePage (cpup, & e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4519             cpu.du.CHTALLY += PGSZ * 4;
4520           }
4521         cleanupOperandDescriptor (cpup, 1);
4522         cleanupOperandDescriptor (cpup, 2);
4523         // truncation fault check does need to be checked for here since
4524         // it is known that N1 == N2
4525         CLR_I_TRUNC;
4526         return;
4527       }
4528 
4529 //
4530 // Page zero
4531 //
4532 
4533     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4534 #if defined(EIS_PTR3)
4535         TA1 == CTA9 &&  // src and dst are both char 9
4536         TA2 == CTA9 &&
4537 #else
4538         e -> TA1 == CTA9 &&  // src and dst are both char 9
4539         e -> TA2 == CTA9 &&
4540 #endif
4541         e -> N1 == 0 && // the source is entirely fill
4542         (e -> N2 % (PGSZ * 4)) == 0 &&  // a page
4543         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4544         e -> CN2 == 0 &&
4545 #if defined(EIS_PTR)
4546         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4547         (cpu.du.D2_PTR_W& PGMK) == 0)
4548 #else
4549         (e -> ADDR1.address & PGMK) == 0 &&
4550         (e -> ADDR2.address & PGMK) == 0)
4551 #endif
4552       {
4553         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #4\n");
4554         word36 pg [PGSZ];
4555         if (fill)
4556           {
4557             word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4558             for (uint i = 0; i < PGSZ; i ++)
4559               pg [i] = w;
4560           }
4561         else
4562           {
4563            (void)memset (pg, 0, sizeof (pg));
4564           }
4565         while (cpu.du.CHTALLY < e -> N2)
4566           {
4567             EISWritePage (cpup, & e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4568             cpu.du.CHTALLY += PGSZ * 4;
4569           }
4570         cleanupOperandDescriptor (cpup, 1);
4571         cleanupOperandDescriptor (cpup, 2);
4572         // truncation fault check does need to be checked for here since
4573         // it is known that N1 == N2
4574         CLR_I_TRUNC;
4575         return;
4576       }
4577 
4578 // Test for the case of aligned word move; and do things a word at a time,
4579 // instead of a byte at a time...
4580 
4581 #if defined(EIS_PTR3)
4582     if (TA1 == CTA9 &&  // src and dst are both char 9
4583         TA2 == CTA9 &&
4584 #else
4585     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4586         e -> TA2 == CTA9 &&
4587 #endif
4588         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4589         e -> N2 == e -> N1 && // the src is the same size as the dest.
4590         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4591         e -> CN2 == 0)
4592       {
4593         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #1\n");
4594         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4595           {
4596             uint n = cpu.du.CHTALLY / 4;
4597             word36 w = EISReadIdx (cpup, & e -> ADDR1, n);
4598             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
4599           }
4600         cleanupOperandDescriptor (cpup, 1);
4601         cleanupOperandDescriptor (cpup, 2);
4602         // truncation fault check does need to be checked for here since
4603         // it is known that N1 == N2
4604         CLR_I_TRUNC;
4605         return;
4606       }
4607 
4608 // Test for the case of aligned word fill; and do things a word at a time,
4609 // instead of a byte at a time...
4610 
4611 #if defined(EIS_PTR3)
4612     if (TA1 == CTA9 && // src and dst are both char 9
4613         TA2 == CTA9 &&
4614 #else
4615     if (e -> TA1 == CTA9 && // src and dst are both char 9
4616         e -> TA2 == CTA9 &&
4617 #endif
4618         e -> N1 == 0 && // the source is entirely fill
4619         e -> N2 % 4 == 0 && // a whole number of words in the dest
4620         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4621         e -> CN2 == 0)
4622       {
4623         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #2\n");
4624         word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4625         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4626           {
4627             uint n = cpu.du.CHTALLY / 4;
4628             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
4629           }
4630         cleanupOperandDescriptor (cpup, 1);
4631         cleanupOperandDescriptor (cpup, 2);
4632         // truncation fault check does need to be checked for here since
4633         // it is known that N1 <= N2
4634         CLR_I_TRUNC;
4635         return;
4636       }
4637 
4638     for ( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
4639       {
4640         word9 c = EISget469 (cpup, 1, cpu.du.CHTALLY); // get src char
4641         word9 cout = 0;
4642 
4643 #if defined(EIS_PTR3)
4644         if (TA1 == TA2)
4645 #else
4646         if (e -> TA1 == e -> TA2)
4647 #endif
4648           EISput469 (cpup, 2, cpu.du.CHTALLY, c);
4649         else
4650           {
4651             // If data types are dissimilar (TA1 ≠ TA2), each character is
4652             // high-order truncated or zero filled, as appropriate, as it is
4653             // moved. No character conversion takes place.
4654             cout = c;
4655             switch (srcSZ)
4656               {
4657                 case 6:
4658                   switch(dstSZ)
4659                     {
4660                       case 4:
4661                         cout = c & 017;    // truncate upper 2-bits
4662                         break;
4663                       case 9:
4664                         break;              // should already be 0-filled
4665                     }
4666                   break;
4667                 case 9:
4668                   switch(dstSZ)
4669                     {
4670                       case 4:
4671                         cout = c & 017;    // truncate upper 5-bits
4672                         break;
4673                       case 6:
4674                         cout = c & 077;    // truncate upper 3-bits
4675                         break;
4676                     }
4677                   break;
4678               }
4679 
4680             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
4681             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
4682             // negative overpunch sign is found, then the minus sign character
4683             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
4684             // is placed in C(Y-charn2)N2-1.
4685 
4686             if (ovp && (cpu.du.CHTALLY == e -> N1 - 1))
4687               {
4688                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
4689                 // ISOLTS-838 01e, RJ78 p. 11-126
4690                 isGBCDOvp (c, & isNeg);
4691               }
4692             EISput469 (cpup, 2, cpu.du.CHTALLY, cout);
4693           }
4694       }
4695 
4696     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4697     //    C(FILL) → C(Y-charn2)N2-i
4698     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4699     // characters are high-order truncated as they are moved to C(Y-charn2). No
4700     // character conversion takes place.
4701 
4702     if (e -> N1 < e -> N2)
4703       {
4704         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
4705           {
4706             // if there's an overpunch then the sign will be the last of the fill
4707             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
4708               {
4709                 if (isNeg)
4710                   EISput469 (cpup, 2, cpu.du.CHTALLY, 015); // 015 is decimal -
4711                 else
4712                   EISput469 (cpup, 2, cpu.du.CHTALLY, 014); // 014 is decimal +
4713               }
4714             else
4715               EISput469 (cpup, 2, cpu.du.CHTALLY, fillT);
4716           }
4717     }
4718     cleanupOperandDescriptor (cpup, 1);
4719     cleanupOperandDescriptor (cpup, 2);
4720 
4721     if (e -> N1 > e -> N2)
4722       {
4723         SET_I_TRUNC;
4724         if (T && ! TST_I_OMASK)
4725           doFault (FAULT_OFL, fst_zero, "mlr truncation fault");
4726       }
4727     else
4728       CLR_I_TRUNC;
4729   }
4730 
4731 void mrl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4732   {
4733     EISstruct * e = & cpu.currentEISinstruction;
4734 
4735     // For i = 1, 2, ..., minimum (N1,N2)
4736     //     C(Y-charn1)N1-i → C(Y-charn2)N2-i
4737     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4738     //    C(FILL) → C(Y-charn2)N2-i
4739     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4740 
4741     fault_ipr_subtype_ mod_fault = 0;
4742 
4743 #if !defined(EIS_SETUP)
4744     setupOperandDescriptor (cpup, 1, &mod_fault);
4745     setupOperandDescriptor (cpup, 2, &mod_fault);
4746     //setupOperandDescriptorCache (cpup,3);
4747 #endif
4748 
4749     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
4750     parseAlphanumericOperandDescriptor(cpup, 2, 2, false, &mod_fault);
4751 
4752     L68_ (
4753       // L68 raises it immediately
4754       if (mod_fault)
4755         {
4756           doFault (FAULT_IPR,
4757                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4758                    "Illegal modifier");
4759         }
4760     )
4761 
4762     // Bit 10 MBZ
4763     if (IWB_IRODD & 0000200000000)
4764       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mrl 10 MBZ");
4765 
4766     // Bit 23 of OP1 MBZ
4767     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4768       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op1 23 MBZ");
4769 
4770     // Bit 23 of OP2 MBZ
4771     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4772       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op2 23 MBZ");
4773 
4774     DPS8M_ (
4775       // DPS8M raises it delayed
4776       if (mod_fault)
4777         {
4778           doFault (FAULT_IPR,
4779                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4780                    "Illegal modifier");
4781         }
4782     )
4783 
4784     int srcSZ = 0, dstSZ = 0;
4785 
4786 #if defined(EIS_PTR3)
4787     switch (TA1)
4788 #else
4789     switch (e -> TA1)
4790 #endif
4791       {
4792         case CTA4:
4793           srcSZ = 4;
4794           break;
4795         case CTA6:
4796           srcSZ = 6;
4797           break;
4798         case CTA9:
4799           srcSZ = 9;
4800           break;
4801       }
4802 
4803 #if defined(EIS_PTR3)
4804     switch (TA2)
4805 #else
4806     switch (e -> TA2)
4807 #endif
4808       {
4809         case CTA4:
4810           dstSZ = 4;
4811           break;
4812         case CTA6:
4813           dstSZ = 6;
4814           break;
4815         case CTA9:
4816           dstSZ = 9;
4817           break;
4818       }
4819 
4820     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4821 
4822     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4823     word9 fillT = fill;  // possibly truncated fill pattern
4824 
4825     // play with fill if we need to use it
4826     switch (dstSZ)
4827       {
4828         case 4:
4829           fillT = fill & 017;    // truncate upper 5-bits
4830           break;
4831         case 6:
4832           fillT = fill & 077;    // truncate upper 3-bits
4833           break;
4834       }
4835 
4836     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4837     // and the truncation indicator is set ON.
4838 
4839     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4840     // characters are high-order truncated as they are moved to C(Y-charn2). No
4841     // character conversion takes place.
4842 
4843     // The user of string replication or overlaying is warned that the decimal
4844     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4845     // units of Y-block8 words and that the overlaid string, C(Y-charn2), is
4846     // not returned to main memory until the unit of Y-block8 words is filled or
4847     // the instruction completes.
4848 
4849     // If T = 1 and the truncation indicator is set ON by execution of the
4850     // instruction, then a truncation (overflow) fault occurs.
4851 
4852     // Attempted execution with the xed instruction causes an illegal procedure
4853     // fault.
4854 
4855     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4856     // illegal procedure fault.
4857 
4858 #if defined(EIS_PTR3)
4859     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4860                (TA2 == 2); // (6-4 move)
4861 #else
4862     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4863                (e -> TA2 == 2); // (6-4 move)
4864 #endif
4865     bool isNeg = false;
4866     //bool bOvp = false;  // true when a negative overpunch character has been
4867                         // found @ N1-1
4868 
4869     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4870       DU_CYCLE_FLEN_128;))
4871 
4872 //
4873 // Test for the case of aligned word move; and do things a word at a time,
4874 // instead of a byte at a time...
4875 
4876 #if defined(EIS_PTR3)
4877     if (TA1 == CTA9 &&  // src and dst are both char 9
4878         TA2 == CTA9 &&
4879 #else
4880     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4881         e -> TA2 == CTA9 &&
4882 #endif
4883         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4884         e -> N2 == e -> N1 && // the src is the same size as the dest.
4885         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4886         e -> CN2 == 0)
4887       {
4888         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #1\n");
4889         uint limit = e -> N2;
4890         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY += 4)
4891           {
4892             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
4893             word36 w = EISReadIdx (cpup, & e -> ADDR1, n);
4894             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
4895           }
4896         cleanupOperandDescriptor (cpup, 1);
4897         cleanupOperandDescriptor (cpup, 2);
4898         // truncation fault check does need to be checked for here since
4899         // it is known that N1 == N2
4900         CLR_I_TRUNC;
4901         return;
4902       }
4903 
4904 // Test for the case of aligned word fill; and do things a word at a time,
4905 // instead of a byte at a time...
4906 
4907 #if defined(EIS_PTR3)
4908     if (TA1 == CTA9 && // src and dst are both char 9
4909         TA2 == CTA9 &&
4910 #else
4911     if (e -> TA1 == CTA9 && // src and dst are both char 9
4912         e -> TA2 == CTA9 &&
4913 #endif
4914         e -> N1 == 0 && // the source is entirely fill
4915         e -> N2 % 4 == 0 && // a whole number of words in the dest
4916         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4917         e -> CN2 == 0)
4918       {
4919         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #2\n");
4920         word36 w = (word36) fill |
4921                   ((word36) fill << 9) |
4922                   ((word36) fill << 18) |
4923                   ((word36) fill << 27);
4924         uint limit = e -> N2;
4925         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4926           {
4927             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
4928             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
4929           }
4930         cleanupOperandDescriptor (cpup, 1);
4931         cleanupOperandDescriptor (cpup, 2);
4932         // truncation fault check does need to be checked for here since
4933         // it is known that N1 <= N2
4934         CLR_I_TRUNC;
4935         return;
4936       }
4937 
4938     for ( ; cpu.du.CHTALLY < min (e -> N1, e -> N2); cpu.du.CHTALLY ++)
4939       {
4940         word9 c = EISget469 (cpup, 1, e -> N1 - cpu.du.CHTALLY - 1); // get src char
4941         word9 cout = 0;
4942 
4943 #if defined(EIS_PTR3)
4944         if (TA1 == TA2)
4945 #else
4946         if (e -> TA1 == e -> TA2)
4947 #endif
4948           EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, c);
4949         else
4950           {
4951             // If data types are dissimilar (TA1 ≠ TA2), each character is
4952             // high-order truncated or zero filled, as appropriate, as it is
4953             // moved. No character conversion takes place.
4954             cout = c;
4955             switch (srcSZ)
4956               {
4957                 case 6:
4958                   switch(dstSZ)
4959                     {
4960                       case 4:
4961                         cout = c & 017;    // truncate upper 2-bits
4962                         break;
4963                       case 9:
4964                         break;              // should already be 0-filled
4965                     }
4966                   break;
4967                 case 9:
4968                   switch(dstSZ)
4969                     {
4970                       case 4:
4971                         cout = c & 017;    // truncate upper 5-bits
4972                         break;
4973                       case 6:
4974                         cout = c & 077;    // truncate upper 3-bits
4975                         break;
4976                     }
4977                   break;
4978               }
4979 
4980             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
4981             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
4982             // negative overpunch sign is found, then the minus sign character
4983             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
4984             // is placed in C(Y-charn2)N2-1.
4985 
4986 // ISOLTS 838 01f, RJ78 p.11-154 - the rightmost digit is examined for overpunch.
4987             if (ovp && (cpu.du.CHTALLY == 0))
4988               {
4989                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
4990                 isGBCDOvp (c, & isNeg);
4991               }
4992             EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, cout);
4993           }
4994       }
4995 
4996     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4997     //    C(FILL) → C(Y-charn2)N2-i
4998     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4999     // characters are high-order truncated as they are moved to C(Y-charn2). No
5000     // character conversion takes place.
5001 
5002     if (e -> N1 < e -> N2)
5003       {
5004         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
5005           {
5006             // if there's an overpunch then the sign will be the last of the fill
5007             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
5008               {
5009                 if (isNeg)
5010                   EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, 015); // 015 is decimal -
5011                 else
5012                   EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, 014); // 014 is decimal +
5013               }
5014             else
5015               {
5016                  EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, fillT);
5017               }
5018           }
5019     }
5020     cleanupOperandDescriptor (cpup, 1);
5021     cleanupOperandDescriptor (cpup, 2);
5022 
5023     if (e -> N1 > e -> N2)
5024       {
5025         SET_I_TRUNC;
5026         if (T && ! TST_I_OMASK)
5027           doFault (FAULT_OFL, fst_zero, "mrl truncation fault");
5028       }
5029     else
5030       CLR_I_TRUNC;
5031   }
5032 
5033 // decimalZero
5034 //
5035 //  Try 1:
5036 //
5037 // This makes MVE 1-28 and all of MVNE work
5038 // Fails MVE 29-37 (6->6)
5039 //    #define decimalZero (e->srcTA != CTA4 ? '0' : 0)
5040 //
5041 // Try 2
5042 // This makes MVE 1-10 and 20-37 and all of MVNE work
5043 // Fails MVE 11-19 (6->9)
5044 //    #define decimalZero (e->srcTA == CTA9 ? '0' : 0)
5045 //
5046 // Try 4
5047 //
5048 #define isDecimalZero(c) ((e->srcTA == CTA9) ? \
5049                           ((c) == '0') : \
5050                           (((c) & 017) == 0))
5051 
5052 /*
5053  * Load the entire sending string number (maximum length 63 characters) into
5054  * the decimal unit input buffer as 4-bit digits (high-order truncating 9-bit
5055  * data). Strip the sign and exponent characters (if any), put them aside into
5056  * special holding registers and decrease the input buffer count accordingly.
5057  */
5058 
5059 static void EISloadInputBufferNumeric (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5060 {
5061     EISstruct * e = & cpu.currentEISinstruction;
5062 
5063     word9 *p = e->inBuffer; // p points to position in inBuffer where 4-bit chars are stored
5064     (void)memset(e->inBuffer, 0, sizeof(e->inBuffer));   // initialize to all 0's
5065 
5066     int pos = (int) e->CN[k-1];
5067 
5068     int TN = (int) e->TN[k-1];
5069     int S = (int) e->S[k-1];  // This is where MVNE gets really nasty.
5070     // I spit on the designers of this instruction set (and of COBOL.) >Ptui!<
5071 
5072     int N = (int) e->N[k-1];  // number of chars in src string
5073 
5074     EISaddr *a = &e->addr[k-1];
5075 
5076     e->sign = 1;
5077     e->exponent = 0;
5078 
5079     for(int n = 0 ; n < N ; n += 1)
5080     {
5081         word9 c = EISget49(cpup, a, &pos, TN);
5082         sim_debug (DBG_TRACEEXT, & cpu_dev, "src: %d: %o\n", n, c);
5083 
5084         /*
5085          * Here we need to distinguish between 4 type of numbers.
5086          *
5087          * CSFL - Floating-point, leading sign
5088          * CSLS - Scaled fixed-point, leading sign
5089          * CSTS - Scaled fixed-point, trailing sign
5090          * CSNS - Scaled fixed-point, unsigned
5091          */
5092         switch(S)
5093         {
5094             case CSFL:  // this is the real evil one ....
5095                 // Floating-point:
5096                 // [sign=c0] c1×10(n-3) + c2×10(n-4) + ... + c(n-3) [exponent=8
5097                 // bits]
5098                 //
5099                 // where:
5100                 //
5101                 //  ci is the decimal value of the byte in the ith byte
5102                 //  position.
5103                 //
5104                 //  [sign=ci] indicates that ci is interpreted as a sign byte.
5105                 //
5106                 //  [exponent=8 bits] indicates that the exponent value is
5107                 //  taken from the last 8 bits of the string. If the data is in
5108                 //  9-bit bytes, the exponent is bits 1-8 of c(n-1). If the
5109                 //  data is in 4- bit bytes, the exponent is the binary value
5110                 //  of the concatenation of c(n-2) and c(n-1).
5111 
5112                 if (n == 0) // first had better be a sign ....
5113                 {
5114                     c &= 0xf;   // hack off all but lower 4 bits
5115 
5116                     if (c < 012 || c > 017) //-V560
5117                       doFault (FAULT_IPR,
5118                                fst_ill_dig,
5119                                "loadInputBufferNumeric(1): illegal char in "
5120                                "input");
5121 
5122                     if (c == 015)   // '-'
5123                         e->sign = -1;
5124 
5125                     e->srcTally -= 1;   // 1 less source char
5126                 }
5127                 else if (TN == CTN9 && n == N-1)    // the 9-bit exponent (of which only 8-bits are used)
5128                 {
5129                     e->exponent = (signed char)(c & 0377); // want to do a sign extend
5130                     e->srcTally -= 1;   // 1 less source char
5131                 }
5132                 else if (TN == CTN4 && n == N-2)    // the 1st 4-chars of the 8-bit exponent
5133                 {
5134                     e->exponent = (c & 0xf);// << 4;
5135                     e->exponent <<= 4;
5136                     e->srcTally -= 1;   // 1 less source char
5137                 }
5138                 else if (TN == CTN4 && n == N-1)    // the 2nd 4-chars of the 8-bit exponent
5139                 {
5140                     e->exponent |= (c & 0xf);
5141 
5142                     signed char ce = (signed char) (e->exponent & 0xff);
5143                     e->exponent = ce;
5144 
5145                     e->srcTally -= 1;   // 1 less source char
5146                 }
5147                 else
5148                 {
5149                     c &= 0xf;   // hack off all but lower 4 bits
5150                     if (c > 011)                        // TODO: generate ill proc fault
5151                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(2): illegal char in input");
5152 
5153                     *p++ = c; // store 4-bit char in buffer
5154                 }
5155                 break;
5156 
5157             case CSLS:
5158                 // Only the byte values [0,11]8 are legal in digit positions
5159                 //    and only the byte values [12,17]8 are legal in sign positions.
5160                 //    Detection of an illegal byte value causes an illegal procedure fault
5161                 c &= 0xf;   // hack off all but lower 4 bits
5162 
5163                 if (n == 0) // first had better be a sign ....
5164                 {
5165                     if (c < 012 || c > 017) //-V560     // TODO: generate ill proc fault
5166                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(3): illegal char in input");
5167 
5168                     if (c == 015)  // '-'
5169                         e->sign = -1;
5170                     e->srcTally -= 1;   // 1 less source char
5171                 }
5172                 else
5173                 {
5174                     if (c > 011) //-V560
5175                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(4): illegal char in input");
5176                     *p++ = c; // store 4-bit char in buffer
5177                 }
5178                 break;
5179 
5180             case CSTS:
5181                 c &= 0xf;   // hack off all but lower 4 bits
5182 
5183                 if (n == N-1) // last had better be a sign ....
5184                 {
5185                     if (c < 012 || c > 017) //-V560
5186                          doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(5): illegal char in input");
5187                     if (c == 015)   // '-'
5188                         e->sign = -1;
5189                     e->srcTally -= 1;   // 1 less source char
5190                 }
5191                 else
5192                 {
5193                     if (c > 011)
5194                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(6): illegal char in input");
5195                     *p++ = c; // store 4-bit char in buffer
5196                 }
5197                 break;
5198 
5199             case CSNS:
5200                 c &= 0xf; // hack off all but lower 4 bits
5201 
5202                 *p++ = c; // the "easy" one
5203                 break;
5204         }
5205     }
5206     if_sim_debug (DBG_TRACEEXT, & cpu_dev)
5207       {
5208         sim_debug (DBG_TRACEEXT, & cpu_dev, "inBuffer:");
5209         for (word9 *q = e->inBuffer; q < p; q ++)
5210           sim_debug (DBG_TRACEEXT, & cpu_dev, " %02o", * q);
5211         sim_debug (DBG_TRACEEXT, & cpu_dev, "\n");
5212       }
5213 }
5214 
5215 /*
5216  * Load decimal unit input buffer with sending string characters. Data is read
5217  * from main memory in unaligned units (not modulo 8 boundary) of Y-block8
5218  * words. The number of characters loaded is the minimum of the remaining
5219  * sending string count, the remaining receiving string count, and 64.
5220  */
5221 
5222 static void EISloadInputBufferAlphnumeric (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5223   {
5224     EISstruct * e = & cpu.currentEISinstruction;
5225     // p points to position in inBuffer where 4-bit chars are stored
5226     word9 * p = e -> inBuffer;
5227     memset (e -> inBuffer, 0, sizeof (e -> inBuffer));// initialize to all 0's
5228 
5229     // minimum of the remaining sending string count, the remaining receiving
5230     // string count, and 64.
5231     // uint N = min3 (e -> N1, e -> N3, 64);
5232     // The above AL39 rule doesn't work with IGN and possibly other MOPs as
5233     // well. Workaround: Load all source, but max 63 characters (as RJ78
5234     // suggests).
5235     uint N = min (e-> N1, 63);
5236 
5237     for (uint n = 0 ; n < N ; n ++)
5238       {
5239         word9 c = EISget469 (cpup, k, n);
5240         * p ++ = c;
5241       }
5242 }
5243 
5244 static void EISwriteOutputBufferToMemory (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5245   {
5246     EISstruct * e = & cpu.currentEISinstruction;
5247 
5248     for (uint n = 0 ; n < (uint) e -> dstTally; n ++)
5249       {
5250         word9 c49 = e -> outBuffer [n];
5251         EISput469 (cpup, k, n, c49);
5252       }
5253   }
5254 
5255 static void writeToOutputBuffer (cpu_state_t *cpup, word9 **dstAddr, int szSrc, int szDst, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
5256 {
5257     EISstruct * e = & cpu.currentEISinstruction;
5258     // 4. If an edit insertion table entry or MOP insertion character is to be
5259     // stored, ANDed, or ORed into a receiving string of 4- or 6-bit
5260     // characters, high-order truncate the character accordingly.
5261     // 5. (MVNE) If the receiving string is 9-bit characters, high-order fill
5262     // the (4-bit) digits from the input buffer with bits 0-4 of character 8 of
5263     // the edit insertion table. If the receiving string is 6-bit characters,
5264     // high-order fill the digits with "00"b.
5265 
5266     if (e -> mvne)
5267       {
5268         switch (szSrc)   // XXX according to rule 1 of Numeric Edit,
5269                          // input should be 4bits. this needs cleaning
5270           {
5271             case 4:
5272               switch (szDst)
5273                 {
5274                   case 4:
5275                     ** dstAddr = c49 & 0xf;
5276                     break;
5277                   case 6:
5278                     ** dstAddr = c49 & 077;   // high-order fill the digits with "00"b.
5279                     break;
5280                   case 9:
5281                     ** dstAddr = c49 | (e -> editInsertionTable [7] & 0760);
5282                     break;
5283                 }
5284               break;
5285             case 6:
5286               switch (szDst)
5287                 {
5288                   case 4:
5289                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5290                     break;
5291                   case 6:
5292                     ** dstAddr = c49; //-V1037 // XXX is this safe? shouldn't it be & 077 ???
5293                     break;
5294                   case 9:
5295                     ** dstAddr = c49; //-V1037
5296                     break;
5297                 }
5298               break;
5299             // Note: case szSrc == 9 is also used for writing edit table
5300             // entries and MOP insertion characters which shall NOT be
5301             // transformed by rule 5
5302             case 9:
5303               switch(szDst)
5304                 {
5305                   case 4:
5306                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5307                     break;
5308                   case 6:
5309                     ** dstAddr = c49 & 077;   // write only 6-bits
5310                     break;
5311                   case 9:
5312                     ** dstAddr = c49;
5313                     break;
5314                 }
5315               break;
5316           }
5317       }
5318     else // mve
5319       {
5320         switch(szDst)
5321           {
5322             case 4:
5323               ** dstAddr = c49 & 0xf;    // write only-4-bits
5324               break;
5325             case 6:
5326               ** dstAddr = c49 & 077;   // write only 6-bits
5327               break;
5328             case 9:
5329               ** dstAddr = c49;
5330               break;
5331           }
5332       }
5333     e->dstTally -= 1;
5334     *dstAddr += 1;
5335 }
5336 
5337 /*!
5338  * This is the Micro Operation Executor/Interpreter
5339  */
5340 
5341 static char* defaultEditInsertionTable = " *+-$,.0";
5342 
5343 // Edit Flags
5344 //
5345 // The processor provides the following four edit flags for use by the micro
5346 // operations.
5347 //
5348 // bool mopES = false; // End Suppression flag; initially OFF, set ON by a
5349 // micro operation when zero-suppression ends.
5350 //
5351 // bool mopSN = false;
5352 // Sign flag; initially set OFF if the sending string has an alphanumeric
5353 // descriptor or an unsigned numeric descriptor. If the sending string has a
5354 // signed numeric descriptor, the sign is initially read from the sending
5355 // string from the digit position defined by the sign and the decimal type
5356 // field (S); SN is set OFF if positive, ON if negative. If all digits are
5357 // zero, the data is assumed positive and the SN flag is set OFF, even when the
5358 // sign is negative.
5359 //
5360 //bool mopBZ = false; i
5361 // Blank-when-zero flag; initially set OFF and set ON by either the ENF or SES
5362 // micro operation. If, at the completion of a move (L1 exhausted), both the Z
5363 // and BZ flags are ON, the receiving string is filled with character 1 of the
5364 // edit insertion table.
5365 
5366 /*!
5367  * CHT Micro Operation - Change Table
5368  * EXPLANATION: The edit insertion table is replaced by the string of eight
5369  * 9-bit characters immediately following the CHT micro operation.
5370  * FLAGS: None affected
5371  * NOTE: C(IF) is not interpreted for this operation.
5372  */
5373 
5374 static int mopCHT (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5375 {
5376     EISstruct * e = & cpu.currentEISinstruction;
5377     (void)memset(&e->editInsertionTable, 0, sizeof(e->editInsertionTable)); // XXX do we really need this?
5378     for(int i = 0 ; i < 8 ; i += 1)
5379     {
5380         if (e->mopTally == 0)
5381         {
5382             e->_faults |= FAULT_IPR;
5383             break;
5384         }
5385 #if defined(EIS_PTR2)
5386         word9 entry = EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);  // get mop table entries
5387 #else
5388         word9 entry = EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);  // get mop table entries
5389 #endif
5390         e->editInsertionTable[i] = entry & 0777;            // keep to 9-bits
5391         e->mopTally -= 1;
5392     }
5393     return 0;
5394 }
5395 
5396 /*!
5397  * ENF Micro Operation - End Floating Suppression
5398  * EXPLANATION:
5399  *  Bit 0 of IF, IF(0), specifies the nature of the floating suppression. Bit 1
5400  *  of IF, IF(1), specifies if blank when zero option is used.
5401  * For IF(0) = 0 (end floating-sign operation),
5402  * − If ES is OFF and SN is OFF, then edit insertion table entry 3 is moved to
5403  * the receiving field and ES is set ON.
5404  * − If ES is OFF and SN is ON, then edit insertion table entry 4 is moved to
5405  * the receiving field and ES is set ON.
5406  * − If ES is ON, no action is taken.
5407  * For IF(0) = 1 (end floating currency symbol operation),
5408  * − If ES is OFF, then edit insertion table entry 5 is moved to the receiving
5409  * field and ES is set ON.
5410  * − If ES is ON, no action is taken.
5411  * For IF(1) = 1 (blank when zero): the BZ flag is set ON. For IF(1) = 0 (no
5412  * blank when zero): no action is taken.
5413  * FLAGS: (Flags not listed are not affected)
5414  *      ES - If OFF, then set ON
5415  *      BZ - If bit 1 of C(IF) = 1, then set ON; otherwise, unchanged
5416  */
5417 
5418 static int mopENF (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5419 {
5420     EISstruct * e = & cpu.currentEISinstruction;
5421     // For IF(0) = 0 (end floating-sign operation),
5422     if (!(e->mopIF & 010))
5423     {
5424         // 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.
5425         if (!e->mopES && !e->mopSN)
5426         {
5427             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[2]);
5428             e->mopES = true;
5429         }
5430         // 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.
5431         if (!e->mopES && e->mopSN)
5432         {
5433             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[3]);
5434             e->mopES = true;
5435         }
5436         // If ES is ON, no action is taken.
5437     } else { // IF(0) = 1 (end floating currency symbol operation),
5438         if (!e->mopES)
5439         {
5440             // If ES is OFF, then edit insertion table entry 5 is moved to the receiving field and ES is set ON.
5441             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5442             e->mopES = true;
5443         }
5444         // If ES is ON, no action is taken.
5445     }
5446 
5447     // 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.
5448     if (e->mopIF & 04)
5449         e->mopBZ = true;
5450 
5451     return 0;
5452 }
5453 
5454 /*!
5455  * IGN Micro Operation - Ignore Source Characters
5456  * EXPLANATION:
5457  * IF specifies the number of characters to be ignored, where IF = 0 specifies
5458  * 16 characters.
5459  * The next IF characters in the source data field are ignored and the sending
5460  * tally is reduced accordingly.
5461  * FLAGS: None affected
5462  */
5463 
5464 static int mopIGN (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5465 {
5466     EISstruct * e = & cpu.currentEISinstruction;
5467 // AL-39 doesn't specify the == 0 test, but NovaScale does;
5468 // also ISOLTS ps830 test-04a seems to rely on it.
5469     if (e->mopIF == 0)
5470         e->mopIF = 16;
5471 
5472     for(int n = 0 ; n < e->mopIF ; n += 1)
5473     {
5474         if (e->dstTally == 0)
5475             break;
5476         if (e->srcTally == 0)
5477         {
5478             // IGN doesn't allow BZ, raise IPR straight away
5479             e->_faults |= FAULT_IPR;
5480             break;
5481         }
5482 
5483         e->srcTally -= 1;
5484         e->in += 1;
5485     }
5486     return 0;
5487 }
5488 
5489 /*!
5490  * INSA Micro Operation - Insert Asterisk on Suppression
5491  * EXPLANATION:
5492  * This MOP is the same as INSB except that if ES is OFF, then edit insertion
5493  * table entry 2 is moved to the receiving field.
5494  * FLAGS: None affected
5495  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5496  */
5497 
5498 static int mopINSA (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5499 {
5500     EISstruct * e = & cpu.currentEISinstruction;
5501     // If C(IF) = 9-15, an IPR fault occurs.
5502     if (e->mopIF >= 9 && e->mopIF <= 15)
5503     {
5504         e->_faults |= FAULT_IPR;
5505         return 0;
5506     }
5507 
5508 
5509     // If ES is OFF, then edit insertion table entry 1 is moved to the
5510     // receiving field. If IF = 0, then the next 9 bits are also skipped. If IF
5511     // is not 0, the next 9 bits are treated as a MOP.
5512 
5513     if (!e->mopES)
5514       {
5515         writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[1]);
5516 
5517         if (e->mopIF == 0)
5518           {
5519             if (e->mopTally == 0)
5520               {
5521                 e->_faults |= FAULT_IPR;
5522                 return 0;
5523               }
5524 # if defined(EIS_PTR2)
5525             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5526 # else
5527             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5528 # endif
5529             e->mopTally -= 1;
5530           }
5531       }
5532 
5533     // If ES is ON and IF = 0, then the 9-bit character immediately following
5534     // the INSB micro-instruction is moved to the receiving field
5535     else
5536       {
5537         if (e->mopIF == 0)
5538           {
5539             if (e->mopTally == 0)
5540               {
5541                 e->_faults |= FAULT_IPR;
5542                 return 0;
5543               }
5544 # if defined(EIS_PTR2)
5545             word9 c = EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5546 # else
5547             word9 c = EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5548 # endif
5549             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, c);
5550             e->mopTally -= 1;
5551           }
5552     // If ES is ON and IF<>0, then IF specifies which edit insertion table
5553     // entry (1-8) is to be moved to the receiving field.
5554         else
5555           {
5556             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF-1]);
5557           }
5558       }
5559 
5560 
5561 
5562 
5563 
5564 
5565 
5566 
5567 
5568 
5569 
5570 
5571 
5572 
5573 
5574 
5575 
5576 
5577 
5578 
5579 
5580 
5581 
5582 
5583 
5584 
5585 
5586 
5587 
5588 
5589 
5590 
5591 
5592 
5593 
5594 
5595 
5596 
5597 
5598 
5599 
5600 
5601 
5602 
5603 
5604 
5605 
5606 
5607 
5608     return 0;
5609 }
5610 
5611 /*!
5612  * INSB Micro Operation - Insert Blank on Suppression
5613  * EXPLANATION:
5614  * IF specifies which edit insertion table entry is inserted.
5615  * If IF = 0, the 9 bits immediately following the INSB micro operation are
5616  * treated as a 9-bit character (not a MOP) and are moved or skipped according
5617  * to ES.
5618  * − If ES is OFF, then edit insertion table entry 1 is moved to the receiving
5619  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5620  * next 9 bits are treated as a MOP.
5621  * − If ES is ON and IF = 0, then the 9-bit character immediately following the
5622  * INSB micro-instruction is moved to the receiving field.
5623  * − If ES is ON and IF<>0, then IF specifies which edit insertion table entry
5624  * (1-8) is to be moved to the receiving field.
5625  * FLAGS: None affected
5626  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5627  */
5628 
5629 static int mopINSB (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5630 {
5631     EISstruct * e = & cpu.currentEISinstruction;
5632     // If C(IF) = 9-15, an IPR fault occurs.
5633     if (e->mopIF >= 9 && e->mopIF <= 15)
5634     {
5635         e->_faults |= FAULT_IPR;
5636         return 0;
5637     }
5638 
5639     if (!e->mopES)
5640     {
5641         // If ES is OFF, then edit insertion table entry 1 is moved to the
5642         // receiving field. If IF = 0, then the next 9 bits are also skipped.
5643         // If IF is not 0, the next 9 bits are treated as a MOP.
5644         writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5645 
5646         if (e->mopIF == 0)
5647         {
5648             if (e->mopTally == 0)
5649             {
5650                 e->_faults |= FAULT_IPR;
5651                 return 0;
5652             }
5653 #if defined(EIS_PTR2)
5654             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5655 #else
5656             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5657 #endif
5658             e->mopTally -= 1;
5659         }
5660 
5661     } else {
5662         // ES is ON
5663 
5664         // If C(IF) != 0
5665         if (e->mopIF)
5666         {
5667             // If ES is ON and IF<>0, then IF specifies which edit
5668             // insertion table entry (1-8) is to be moved to the receiving
5669             // field.
5670             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5671         } else {
5672             // If ES is ON and IF = 0, then the 9-bit character immediately
5673             // following the INSB micro-instruction is moved to the
5674             // receiving field.
5675             if (e->mopTally == 0)
5676             {
5677                 e->_faults |= FAULT_IPR;
5678                 return 0;
5679             }
5680 #if defined(EIS_PTR2)
5681             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9));
5682             //EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5683 #else
5684             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, e->mopAddress, &e->mopPos, CTN9));
5685             //EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5686 #endif
5687             e->mopTally -= 1;
5688 
5689         }
5690     }
5691     return 0;
5692 }
5693 
5694 /*!
5695  * INSM Micro Operation - Insert Table Entry One Multiple
5696  * EXPLANATION:
5697  * IF specifies the number of receiving characters affected, where IF = 0
5698  * specifies 16 characters.
5699  * Edit insertion table entry 1 is moved to the next IF (1-16) receiving field
5700  * characters.
5701  * FLAGS: None affected
5702  */
5703 
5704 static int mopINSM (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5705 {
5706     EISstruct * e = & cpu.currentEISinstruction;
5707     if (e->mopIF == 0)
5708         e->mopIF = 16;
5709     for(int n = 0 ; n < e->mopIF ; n += 1)
5710     {
5711         if (e->dstTally == 0)
5712           break;
5713         writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5714     }
5715     return 0;
5716 }
5717 
5718 /*!
5719  * INSN Micro Operation - Insert on Negative
5720  * EXPLANATION:
5721  * IF specifies which edit insertion table entry is inserted. If IF = 0, the 9
5722  * bits immediately following the INSN micro operation are treated as a 9-bit
5723  * character (not a MOP) and are moved or skipped according to SN.
5724  * − If SN is OFF, then edit insertion table entry 1 is moved to the receiving
5725  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5726  * next 9 bits are treated as a MOP.
5727  * − If SN is ON and IF = 0, then the 9-bit character immediately following the
5728  * INSN micro-instruction is moved to the receiving field.
5729  * − If SN is ON and IF <> 0, then IF specifies which edit insertion table
5730  * entry (1-8) is to be moved to the receiving field.
5731  * FLAGS: None affected
5732  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5733  */
5734 
5735 static int mopINSN (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5736 {
5737     EISstruct * e = & cpu.currentEISinstruction;
5738     // If C(IF) = 9-15, an IPR fault occurs.
5739     if (e->mopIF >= 9 && e->mopIF <= 15)
5740     {
5741         e->_faults |= FAULT_IPR;
5742         return 0;
5743     }
5744 
5745     // If IF = 0, the 9 bits immediately following the INSN micro operation are
5746     // treated as a 9-bit character (not a MOP) and are moved or skipped
5747     // according to SN.
5748 
5749     if (e->mopIF == 0)
5750     {
5751         if (e->mopTally == 0)
5752         {
5753             e->_faults |= FAULT_IPR;
5754             return 0;
5755         }
5756       if (!e->mopSN)
5757         {
5758             //If SN is OFF, then edit insertion table entry 1 is moved to the
5759             //receiving field. If IF = 0, then the next 9 bits are also
5760             //skipped. If IF is not 0, the next 9 bits are treated as a MOP.
5761 #if defined(EIS_PTR2)
5762             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5763 #else
5764             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5765 #endif
5766             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5767             e->mopTally -= 1;
5768         } else {
5769             // If SN is ON and IF = 0, then the 9-bit character immediately
5770             // following the INSN micro-instruction is moved to the receiving
5771             // field.
5772 #if defined(EIS_PTR2)
5773             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9));
5774 #else
5775             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, e->mopAddress, &e->mopPos, CTN9));
5776 #endif
5777 
5778             e->mopTally -= 1;
5779         }
5780     }
5781     else
5782     {
5783         if (e->mopSN)
5784         {
5785             //If SN is ON and IF <> 0, then IF specifies which edit insertion
5786             //table entry (1-8) is to be moved to the receiving field.
5787             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5788         } else {
5789             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5790         }
5791     }
5792     return 0;
5793 }
5794 
5795 /*!
5796  * INSP Micro Operation - Insert on Positive
5797  * EXPLANATION:
5798  * INSP is the same as INSN except that the responses for the SN values are
5799  * reversed.
5800  * FLAGS: None affected
5801  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5802  */
5803 
5804 static int mopINSP (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5805 {
5806     EISstruct * e = & cpu.currentEISinstruction;
5807     // If C(IF) = 9-15, an IPR fault occurs.
5808     if (e->mopIF >= 9 && e->mopIF <= 15)
5809     {
5810         e->_faults |= FAULT_IPR;
5811         return 0;
5812     }
5813 
5814     if (e->mopIF == 0)
5815     {
5816         if (e->mopTally == 0)
5817         {
5818             e->_faults |= FAULT_IPR;
5819             return 0;
5820         }
5821         if (e->mopSN)
5822         {
5823 #if defined(EIS_PTR2)
5824             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5825 #else
5826             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5827 #endif
5828             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5829             e->mopTally -= 1;
5830         } else {
5831 #if defined(EIS_PTR2)
5832             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9));
5833 #else
5834             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, e->mopAddress, &e->mopPos, CTN9));
5835 #endif
5836             e->mopTally -= 1;
5837         }
5838     }
5839     else
5840     {
5841         if (!e->mopSN)
5842         {
5843             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5844         } else {
5845             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5846         }
5847     }
5848 
5849     return 0;
5850 }
5851 
5852 /*!
5853  * LTE Micro Operation - Load Table Entry
5854  * EXPLANATION:
5855  * IF specifies the edit insertion table entry to be replaced.
5856  * The edit insertion table entry specified by IF is replaced by the 9-bit
5857  * character immediately following the LTE microinstruction.
5858  * FLAGS: None affected
5859  * NOTE: If C(IF) = 0 or C(IF) = 9-15, an Illegal Procedure fault occurs.
5860  */
5861 
5862 static int mopLTE (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5863 {
5864     EISstruct * e = & cpu.currentEISinstruction;
5865     if (e->mopIF == 0 || (e->mopIF >= 9 && e->mopIF <= 15))
5866     {
5867         e->_faults |= FAULT_IPR;
5868         return 0;
5869     }
5870     if (e->mopTally == 0)
5871     {
5872         e->_faults |= FAULT_IPR;
5873         return 0;
5874     }
5875 #if defined(EIS_PTR2)
5876     word9 next = EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5877 #else
5878     word9 next = EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5879 #endif
5880     e->mopTally -= 1;
5881 
5882     e->editInsertionTable[e->mopIF - 1] = next;
5883     sim_debug (DBG_TRACEEXT, & cpu_dev, "LTE IT[%d]<=%d\n", e -> mopIF - 1, next);
5884     return 0;
5885 }
5886 
5887 /*!
5888  * MFLC Micro Operation - Move with Floating Currency Symbol Insertion
5889  * EXPLANATION:
5890  * IF specifies the number of characters of the sending field upon which the
5891  * operation is performed, where IF = 0 specifies 16 characters.
5892  * Starting with the next available sending field character, the next IF
5893  * characters are individually fetched and the following conditional actions
5894  * occur.
5895  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
5896  * moved to the receiving field in place of the character.
5897  * − If ES is OFF and the character is not zero, then edit insertion table
5898  * entry 5 is moved to the receiving field, the character is also moved to the
5899  * receiving field, and ES is set ON.
5900  * − If ES is ON, the character is moved to the receiving field.
5901  * The number of characters placed in the receiving field is data-dependent. If
5902  * the entire sending field is zero, IF characters are placed in the receiving
5903  * field. However, if the sending field contains a nonzero character, IF+1
5904  * characters (the insertion character plus the characters from the sending
5905  * field) are placed in the receiving field.
5906  * An IPR fault occurs when the sending field is exhausted before the receiving
5907  * field is filled. In order to provide space in the receiving field for an
5908  * inserted currency symbol, the receiving field must have a string length one
5909  * character longer than the sending field. When the sending field is all
5910  * zeros, no currency symbol is inserted by the MFLC micro operation and the
5911  * receiving field is not filled when the sending field is exhausted. The user
5912  * should provide an ENF (ENF,12) micro operation after a MFLC micro operation
5913  * that has as its character count the number of characters in the sending
5914  * field. The ENF micro operation is engaged only when the MFLC micro operation
5915  * fails to fill the receiving field. Then it supplies a currency symbol to
5916  * fill the receiving field and blanks out the entire field.
5917  * FLAGS: (Flags not listed are not affected.)
5918  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
5919  * is unchanged.
5920  * NOTE: Since the number of characters moved to the receiving string is
5921  * data-dependent, a possible IPR fault may be avoided by ensuring that the Z
5922  * and BZ flags are ON.
5923  */
5924 
5925 static int mopMFLC (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5926 {
5927     EISstruct * e = & cpu.currentEISinstruction;
5928     if (e->mopIF == 0)
5929         e->mopIF = 16;
5930 
5931     //  Starting with the next available sending field character, the next IF
5932     //  characters are individually fetched and the following conditional
5933     //  actions occur.
5934     sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC IF %d, srcTally %d, dstTally %d\n", e->mopIF, e->srcTally, e->dstTally);
5935     for(int n = 0 ; n < e->mopIF ; n += 1)
5936     {
5937         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC n %d, srcTally %d, dstTally %d\n", n, e->srcTally, e->dstTally);
5938         if (e->dstTally == 0)
5939             break;
5940         if (e->srcTally == 0)
5941             return -1;
5942         // If ES is OFF and the character is zero, edit insertion table entry 1
5943         // is moved to the receiving field in place of the character.
5944         // If ES is OFF and the character is not zero, then edit insertion
5945         // table entry 5 is moved to the receiving field, the character is also
5946         // moved to the receiving field, and ES is set ON.
5947 
5948         word9 c = *(e->in);
5949         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC c %d (0%o)\n", c, c);
5950         if (!e->mopES) { // e->mopES is OFF
5951 
5952             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES off\n");
5953             if (isDecimalZero (c)) {
5954                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is zero\n");
5955                 // edit insertion table entry 1 is moved to the receiving field
5956                 // in place of the character.
5957                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5958                 e->in += 1;
5959                 e->srcTally -= 1;
5960             } else {
5961                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is not zero\n");
5962                 // then edit insertion table entry 5 is moved to the receiving
5963                 // field, the character is also moved to the receiving field,
5964                 // and ES is set ON.
5965                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5966 
5967                 writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
5968                 e->mopZ = false; // iszero() tested above.
5969                 e->in += 1;
5970                 e->srcTally -= 1;
5971 
5972                 e->mopES = true;
5973             }
5974         } else {
5975             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES on\n");
5976             // If ES is ON, the character is moved to the receiving field.
5977             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
5978 
5979             if (! isDecimalZero (c))
5980                 e->mopZ = false;
5981             e->in += 1;
5982             e->srcTally -= 1;
5983         }
5984     }
5985 
5986     return 0;
5987 }
5988 
5989 /*!
5990  * MFLS Micro Operation - Move with Floating Sign Insertion
5991  * EXPLANATION:
5992  * IF specifies the number of characters of the sending field upon which the
5993  * operation is performed, where IF = 0 specifies 16 characters.
5994  * Starting with the next available sending field character, the next IF
5995  * characters are individually fetched and the following conditional actions
5996  * occur.
5997  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
5998  * moved to the receiving field in place of the character.
5999  * − If ES is OFF, the character is not zero, and SN is OFF; then edit
6000  * insertion table entry 3 is moved to the receiving field; the character is
6001  * also moved to the receiving field, and ES is set ON.
6002  * − If ES is OFF, the character is nonzero, and SN is ON; edit insertion table
6003  * entry 4 is moved to the receiving field; the character is also moved to the
6004  * receiving field, and ES is set ON.
6005  * − If ES is ON, the character is moved to the receiving field.
6006  * The number of characters placed in the receiving field is data-dependent. If
6007  * the entire sending field is zero, IF characters are placed in the receiving
6008  * field. However, if the sending field contains a nonzero character, IF+1
6009  * characters (the insertion character plus the characters from the sending
6010  * field) are placed in the receiving field.
6011  * An IPR fault occurs when the sending field is exhausted before the receiving
6012  * field is filled. In order to provide space in the receiving field for an
6013  * inserted sign, the receiving field must have a string length one character
6014  * longer than the sending field. When the sending field is all zeros, no sign
6015  * is inserted by the MFLS micro operation and the receiving field is not
6016  * filled when the sending field is exhausted. The user should provide an ENF
6017  * (ENF,4) micro operation after a MFLS micro operation that has as its
6018  * character count the number of characters in the sending field. The ENF micro
6019  * operation is engaged only when the MFLS micro operation fails to fill the
6020  * receiving field; then, it supplies a sign character to fill the receiving
6021  * field and blanks out the entire field.
6022  *
6023  * FLAGS: (Flags not listed are not affected.)
6024  *     ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6025  *     it is unchanged.
6026  * NOTE: Since the number of characters moved to the receiving string is
6027  * data-dependent, a possible Illegal Procedure fault may be avoided by
6028  * ensuring that the Z and BZ flags are ON.
6029  */
6030 
6031 static int mopMFLS (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6032 {
6033     EISstruct * e = & cpu.currentEISinstruction;
6034     if (e->mopIF == 0)
6035         e->mopIF = 16;
6036 
6037     for(int n = 0 ; n < e->mopIF; n += 1)
6038     {
6039         if (e->dstTally == 0)
6040             break;
6041         if (e->srcTally == 0)
6042             return -1;
6043 
6044         word9 c = *(e->in);
6045         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLS n %d c %o\n", n, c);
6046         if (!e->mopES) { // e->mopES is OFF
6047             if (isDecimalZero (c))
6048             {
6049                 // edit insertion table entry 1 is moved to the receiving field
6050                 // in place of the character.
6051                 sim_debug (DBG_TRACEEXT, & cpu_dev,
6052                            "ES is off, c is zero; edit insertion table entry 1"
6053                            " is moved to the receiving field in place of the character.\n");
6054                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6055                 e->in += 1;
6056                 e->srcTally -= 1;
6057             } else {
6058                 // c is non-zero
6059                 if (!e->mopSN)
6060                 {
6061                     // then edit insertion table entry 3 is moved to the
6062                     // receiving field; the character is also moved to the
6063                     // receiving field, and ES is set ON.
6064                     sim_debug (DBG_TRACEEXT, & cpu_dev,
6065                                "ES is off, c is non-zero, SN is off; edit insertion table entry 3"
6066                                " is moved to the receiving field; the character is also moved to"
6067                                " the receiving field, and ES is set ON.\n");
6068                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[2]);
6069 
6070                     e->in += 1;
6071                     e->srcTally -= 1;
6072                     e->mopZ = false; // iszero tested above
6073 
6074 
6075 
6076 
6077 
6078 
6079 
6080 
6081                     writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6082 
6083                     e->mopES = true;
6084                 } else {
6085                     //  SN is ON; edit insertion table entry 4 is moved to the
6086                     //  receiving field; the character is also moved to the
6087                     //  receiving field, and ES is set ON.
6088                     sim_debug (DBG_TRACEEXT, & cpu_dev,
6089                                "ES is off, c is non-zero, SN is OFF; edit insertion table entry 4"
6090                                " is moved to the receiving field; the character is also moved to"
6091                                " the receiving field, and ES is set ON.\n");
6092                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[3]);
6093 
6094                     e->in += 1;
6095                     e->srcTally -= 1;
6096                     e->mopZ = false; // iszero tested above
6097 
6098                     writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6099 
6100                     e->mopES = true;
6101                 }
6102             }
6103         } else {
6104             // If ES is ON, the character is moved to the receiving field.
6105             sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is ON, the character is moved to the receiving field.\n");
6106             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6107 
6108             if (! isDecimalZero (c))
6109                 e->mopZ = false;
6110             e->in += 1;
6111             e->srcTally -= 1;
6112         }
6113     }
6114 
6115     // NOTE: Since the number of characters moved to the receiving string is
6116     // data-dependent, a possible Illegal Procedure fault may be avoided by
6117     // ensuring that the Z and BZ flags are ON.
6118 
6119     return 0;
6120 }
6121 
6122 /*!
6123  * MORS Micro Operation - Move and OR Sign
6124  * EXPLANATION:
6125  * IF specifies the number of characters of the sending field upon which the
6126  * operation is performed, where IF = 0 specifies 16 characters.
6127  * Starting with the next available sending field character, the next IF
6128  * characters are individually fetched and the following conditional actions
6129  * occur.
6130  * − If SN is OFF, the next IF characters in the source data field are moved to
6131  * the receiving data field and, during the move, edit insertion table entry 3
6132  * is ORed to each character.
6133  * − If SN is ON, the next IF characters in the source data field are moved to
6134  * the receiving data field and, during the move, edit insertion table entry 4
6135  * is ORed to each character.
6136  * MORS can be used to generate a negative overpunch for a receiving field to
6137  * be used later as a sending field.
6138  * FLAGS: None affected
6139  */
6140 
6141 static int mopMORS (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6142 {
6143     EISstruct * e = & cpu.currentEISinstruction;
6144     if (e->mopIF == 0)
6145         e->mopIF = 16;
6146 
6147     sim_debug (DBG_TRACEEXT, & cpu_dev, "MORS mopIF %d src %d dst %d\n", e->mopIF, e->srcTally, e->dstTally);
6148     for(int n = 0 ; n < e->mopIF ; n += 1)
6149     {
6150 // The micro operation sequence is terminated normally when the receiving
6151 // string length becomes exhausted. The micro operation sequence is terminated
6152 // abnormally (with an illegal procedure fault) if a move from an exhausted
6153 // sending string or the use of an exhausted MOP string is attempted.
6154 
6155         if (e->dstTally == 0)
6156             break;
6157         if (e->srcTally == 0)
6158             return -1;
6159 
6160         // XXX this is probably wrong regarding the ORing, but it's a start ....
6161         word9 c = (*e->in | (!e->mopSN ? e->editInsertionTable[2] : e->editInsertionTable[3]));
6162         if (! isDecimalZero (*e->in))
6163             e->mopZ = false;
6164         e->in += 1;
6165         e->srcTally -= 1;
6166 
6167         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6168     }
6169 
6170     return 0;
6171 }
6172 
6173 /*!
6174  * MVC Micro Operation - Move Source Characters
6175  * EXPLANATION:
6176  * IF specifies the number of characters to be moved, where IF = 0 specifies 16
6177  * characters.
6178  * The next IF characters in the source data field are moved to the receiving
6179  * data field.
6180  * FLAGS: None affected
6181  */
6182 
6183 static int mopMVC (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6184 {
6185     EISstruct * e = & cpu.currentEISinstruction;
6186     if (e->mopIF == 0)
6187         e->mopIF = 16;
6188 
6189     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC mopIF %d\n", e->mopIF);
6190 
6191     for(int n = 0 ; n < e->mopIF ; n += 1)
6192     {
6193         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC n %d srcTally %d dstTally %d\n", n, e->srcTally, e->dstTally);
6194 // GD's test_float shows that data exhaustion is not a fault.
6195 //#if 0
6196         if (e->dstTally == 0)
6197             break;
6198         if (e->srcTally == 0)
6199             return -1;
6200 
6201         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC write to output buffer %o\n", *e->in);
6202         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, *e->in);
6203         if (! isDecimalZero (*e->in))
6204             e->mopZ = false;
6205         e->in += 1;
6206 
6207         e->srcTally -= 1;
6208     }
6209 
6210     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC done\n");
6211     return 0;
6212 }
6213 
6214 /*!
6215  * MSES Micro Operation - Move and Set Sign
6216  * EXPLANATION:
6217  * IF specifies the number of characters of the sending field upon which the
6218  * operation is performed, where IF = 0 specifies 16 characters. For MVE,
6219  * starting with the next available sending field character, the next IF
6220  * characters are individually fetched and the following conditional actions
6221  * occur.
6222  * Starting with the first character during the move, a comparative AND is made
6223  * first with edit insertion table entry 3. If the result is nonzero, the first
6224  * character and the rest of the characters are moved without further
6225  * comparative ANDs. If the result is zero, a comparative AND is made between
6226  * the character being moved and edit insertion table entry 4 If that result is
6227  * nonzero, the SN indicator is set ON (indicating negative) and the first
6228  * character and the rest of the characters are moved without further
6229  * comparative ANDs. If the result is zero, the second character is treated
6230  * like the first. This process continues until one of the comparative AND
6231  * results is nonzero or until all characters are moved.
6232  * For MVNE instruction, the sign (SN) flag is already set and IF characters
6233  * are moved to the destination field (MSES is equivalent to the MVC
6234  * instruction).
6235  * FLAGS: (Flags not listed are not affected.)
6236  * SN If edit insertion table entry 4 is found in C(Y-1), then ON; otherwise,
6237  * it is unchanged.
6238  */
6239 
6240 static int mopMSES (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6241 {
6242     EISstruct * e = & cpu.currentEISinstruction;
6243     if (e->mvne == true)
6244         return mopMVC (cpup);   // XXX I think!
6245 
6246     if (e->mopIF == 0)
6247         e->mopIF = 16;
6248 
6249     int overpunch = false;
6250 
6251     for(int n = 0 ; n < e->mopIF ; n += 1)
6252     {
6253         if (e->dstTally == 0)
6254             break;
6255         if (e->srcTally == 0)
6256             return -1;
6257 
6258         //Starting with the first character during the move, a comparative AND
6259         //is made first with edit insertion table entry 3. If the result is
6260         //nonzero, the first character and the rest of the characters are moved
6261         //without further comparative ANDs. If the result is zero, a
6262         //comparative AND is made between the character being moved and edit
6263         //insertion table entry 4 If that result is nonzero, the SN indicator
6264         //is set ON (indicating negative) and the first character and the rest
6265         //of the characters are moved without further comparative ANDs. If the
6266         //result is zero, the second character is treated like the first. This
6267         //process continues until one of the comparative AND results is nonzero
6268         //or until all characters are moved.
6269 
6270         word9 c = *(e->in);
6271 
6272         if (!overpunch) {
6273             if (c & e->editInsertionTable[2])  // XXX only lower 4-bits are considered
6274                 overpunch = true;
6275 
6276             else if (c & e->editInsertionTable[3])  // XXX only lower 4-bits are considered
6277             {
6278                 e->mopSN = true;
6279                 overpunch = true;
6280             }
6281         }
6282 
6283         e->in += 1;
6284         e->srcTally -= 1;   // XXX is this correct? No chars have been consumed, but ......
6285         if (! isDecimalZero (c))
6286             e->mopZ = false;
6287         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6288     }
6289 
6290     return 0;
6291 }
6292 
6293 /*!
6294  * MVZA Micro Operation - Move with Zero Suppression and Asterisk Replacement
6295  * EXPLANATION:
6296  * MVZA is the same as MVZB except that if ES is OFF and the character is zero,
6297  * then edit insertion table entry 2 is moved to the receiving field.
6298  * FLAGS: (Flags not listed are not affected.)
6299  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
6300  * is unchanged.
6301  */
6302 
6303 static int mopMVZA (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6304 {
6305     EISstruct * e = & cpu.currentEISinstruction;
6306     if (e->mopIF == 0)
6307         e->mopIF = 16;
6308 
6309     for(int n = 0 ; n < e->mopIF ; n += 1)
6310     {
6311         if (e->dstTally == 0)
6312             break;
6313         if (e->srcTally == 0)
6314             return -1;
6315 
6316         word9 c = *e->in;
6317         e->in += 1;
6318         e->srcTally -= 1;
6319 
6320         //if (!e->mopES && c == 0)
6321         // XXX See srcTA comment in MVNE
6322         if (!e->mopES && isDecimalZero (c))
6323         {
6324             //If ES is OFF and the character is zero, then edit insertion table
6325             //entry 2 is moved to the receiving field in place of the
6326             //character.
6327             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[1]);
6328         //} else if (!e->mopES && c != 0)
6329         // XXX See srcTA comment in MVNE
6330         }
6331         else if ((! e->mopES) && (! isDecimalZero (c)))
6332         {
6333             //If ES is OFF and the character is not zero, then the character is
6334             //moved to the receiving field and ES is set ON.
6335             e->mopZ = false;
6336             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6337 
6338             e->mopES = true;
6339         } else if (e->mopES)
6340         {
6341             //If ES is ON, the character is moved to the receiving field.
6342             if (! isDecimalZero (c))
6343                 e->mopZ = false;
6344             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6345         }
6346     }
6347 
6348     return 0;
6349 }
6350 
6351 /*!
6352  * MVZB Micro Operation - Move with Zero Suppression and Blank Replacement
6353  * EXPLANATION:
6354  * IF specifies the number of characters of the sending field upon which the
6355  * operation is performed, where IF = 0 specifies 16 characters.
6356  * Starting with the next available sending field character, the next IF
6357  * characters are individually fetched and the following conditional actions
6358  * occur.
6359  * − If ES is OFF and the character is zero, then edit insertion table entry 1
6360  * is moved to the receiving field in place of the character.
6361  * − If ES is OFF and the character is not zero, then the character is moved to
6362  * the receiving field and ES is set ON.
6363  * − If ES is ON, the character is moved to the receiving field.
6364  * FLAGS: (Flags not listed are not affected.)
6365  *   ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6366  *   it is unchanged.
6367  */
6368 
6369 static int mopMVZB (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6370 {
6371     EISstruct * e = & cpu.currentEISinstruction;
6372     if (e->mopIF == 0)
6373         e->mopIF = 16;
6374 
6375     for(int n = 0 ; n < e->mopIF ; n += 1)
6376     {
6377         if (e->dstTally == 0)
6378             break;
6379         if (e->srcTally == 0)
6380           return -1;
6381 
6382         word9 c = *e->in;
6383         e->srcTally -= 1;
6384         e->in += 1;
6385 
6386         //if (!e->mopES && c == 0)
6387         // XXX See srcTA comment in MVNE
6388         if ((!e->mopES) && isDecimalZero (c))
6389         {
6390             //If ES is OFF and the character is zero, then edit insertion table
6391             //entry 1 is moved to the receiving field in place of the
6392             //character.
6393             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6394         //} else if (!e->mopES && c != 0)
6395         // XXX See srcTA comment in MVNE
6396         }
6397         if ((! e->mopES) && (! isDecimalZero (c)))
6398         {
6399             //If ES is OFF and the character is not zero, then the character is
6400             //moved to the receiving field and ES is set ON.
6401             e->mopZ = false;
6402             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6403 
6404             e->mopES = true;
6405         } else if (e->mopES)
6406         {
6407             //If ES is ON, the character is moved to the receiving field.
6408             if (! isDecimalZero (c))
6409                 e->mopZ = false;
6410             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6411         }
6412     }
6413 
6414     return 0;
6415 }
6416 
6417 /*!
6418  * SES Micro Operation - Set End Suppression
6419  * EXPLANATION:
6420  * Bit 0 of IF (IF(0)) specifies the setting of the ES switch.
6421  * If IF(0) = 0, the ES flag is set OFF. If IF(0) = 1, the ES flag is set ON.
6422  * Bit 1 of IF (IF(1)) specifies the setting of the blank-when-zero option.
6423  * If IF(1) = 0, no action is taken.
6424  * If IF(1) = 1, the BZ flag is set ON.
6425  * FLAGS: (Flags not listed are not affected.)
6426  * ES set by this micro operation
6427  * BZ If bit 1 of C(IF) = 1, then ON; otherwise, it is unchanged.
6428  */
6429 
6430 static int mopSES (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6431 {
6432     EISstruct * e = & cpu.currentEISinstruction;
6433     if (e->mopIF & 010)
6434         e->mopES = true;
6435     else
6436         e->mopES = false;
6437 
6438     if (e->mopIF & 04)
6439         e->mopBZ = true;
6440 
6441     return 0;
6442 }
6443 
6444 // Table 4-9. Micro Operation Code Assignment Map
6445 #if !defined(QUIET_UNUSED)
6446 static char * mopCodes [040] =
6447   {
6448     //            0       1       2       3       4       5       6       7
6449     /* 00 */      0, "insm",  "enf",  "ses", "mvzb", "mvza", "mfls", "mflc",
6450     /* 10 */ "insb", "insa", "insn", "insp",  "ign",  "mvc", "mses", "mors",
6451     /* 20 */  "lte",  "cht",      0,      0,      0,      0,      0,      0,
6452     /* 30 */      0,      0,      0,      0,      0,      0,      0,      0
6453   };
6454 #endif
6455 
6456 static MOP_struct mopTab[040] = {
6457     {NULL, 0},
6458     {"insm", mopINSM },
6459     {"enf",  mopENF  },
6460     {"ses",  mopSES  },
6461     {"mvzb", mopMVZB },
6462     {"mvza", mopMVZA },
6463     {"mfls", mopMFLS },
6464     {"mflc", mopMFLC },
6465     {"insb", mopINSB },
6466     {"insa", mopINSA },
6467     {"insn", mopINSN },
6468     {"insp", mopINSP },
6469     {"ign",  mopIGN  },
6470     {"mvc",  mopMVC  },
6471     {"mses", mopMSES },
6472     {"mors", mopMORS },
6473     {"lte",  mopLTE  },
6474     {"cht",  mopCHT  },
6475     {NULL, 0},
6476     {NULL, 0},
6477     {NULL, 0},
6478     {NULL, 0},
6479     {NULL, 0},
6480     {NULL, 0},
6481     {NULL, 0},
6482     {NULL, 0},
6483     {NULL, 0},
6484     {NULL, 0},
6485     {NULL, 0},
6486     {NULL, 0},
6487     {NULL, 0},
6488     {NULL, 0}
6489 };
6490 
6491 /*!
6492  * fetch MOP from e->mopAddr/e->mopPos ...
6493  */
6494 
6495 static MOP_struct* EISgetMop (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6496 {
6497     EISstruct * e = & cpu.currentEISinstruction;
6498     //static word18 lastAddress;  // try to keep memory access' down
6499     //static word36 data;
6500 
6501     if (e == NULL) //-V547
6502     //{
6503     //    p->lastAddress = -1;
6504     //    p->data = 0;
6505         return NULL;
6506     //}
6507 
6508 #if defined(EIS_PTR2)
6509     EISaddr *p = &e->ADDR2;
6510 #else
6511     EISaddr *p = e->mopAddress;
6512 #endif
6513 
6514     //if (p->lastAddress != p->address)                 // read from memory if different address
6515         p->data = EISRead(cpup, p);   // read data word from memory
6516 
6517     if (e->mopPos > 3)   // overflows to next word?
6518     {   // yep....
6519         e->mopPos = 0;   // reset to 1st byte
6520 #if defined(EIS_PTR2)
6521         cpu.du.Dk_PTR_W[KMOP] = (cpu.du.Dk_PTR_W[KMOP] + 1) & AMASK;     // bump source to next address
6522         p->data = EISRead(cpup, &e->ADDR2);   // read it from memory
6523 #else
6524         PNL (cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK);     // bump source to next address
6525         PNL (p->data = EISRead(cpup, e->mopAddress));   // read it from memory
6526 # if defined(EIS_PTR)
6527         cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK;     // bump source to next address
6528         p->data = EISRead(cpup, e->mopAddress);   // read it from memory
6529 # else
6530         e->mopAddress->address = (e->mopAddress->address + 1) & AMASK;     // bump source to next address
6531         p->data = EISRead(cpup, e->mopAddress);   // read it from memory
6532 # endif
6533 #endif
6534     }
6535 
6536     word9 mop9  = (word9) get9 (p -> data, e -> mopPos); // get 9-bit mop
6537     word5 mop   = (mop9 >> 4) & 037;
6538     e->mopIF = mop9 & 0xf;
6539 
6540     MOP_struct *m = &mopTab[mop];
6541     sim_debug (DBG_TRACEEXT, & cpu_dev, "MOP %s(%o) %o\n", m -> mopName, mop, e->mopIF);
6542     e->m = m;
6543     if (e->m == NULL || e->m->f == NULL)
6544     {
6545         sim_debug (DBG_TRACEEXT, & cpu_dev, "getMop(e->m == NULL || e->m->f == NULL): mop:%d IF:%d\n", mop, e->mopIF);
6546         return NULL;
6547     }
6548 
6549     e->mopPos += 1;
6550     e->mopTally -= 1;
6551 
6552     //p->lastAddress = p->address;
6553 
6554     return m;
6555 }
6556 
6557 #if defined(EIS_PTR2)
6558 static void mopExecutor (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6559 #else
6560 static void mopExecutor (cpu_state_t * cpup, int kMop)
6561 #endif
6562   {
6563     EISstruct * e = & cpu.currentEISinstruction;
6564     PNL (L68_ (DU_CYCLE_FEXOP;))
6565 #if defined(EIS_PTR2)
6566     e->mopTally = (int) e->N[KMOP];        // number of micro-ops
6567     e->mopPos   = (int) e->CN[KMOP];        // starting at char pos CN
6568 #else
6569     e->mopAddress = &e->addr[kMop-1];
6570     e->mopTally = (int) e->N[kMop-1];        // number of micro-ops
6571     e->mopPos   = (int) e->CN[kMop-1];        // starting at char pos CN
6572 #endif
6573 
6574     word9 *p9 = e->editInsertionTable; // re-initialize edit insertion table
6575     char *q = defaultEditInsertionTable;
6576     while((*p9++ = (word9) (*q++)))
6577         ;
6578 
6579     e->in = e->inBuffer;    // reset input buffer pointer
6580     e->out = e->outBuffer;  // reset output buffer pointer
6581 
6582     e->_faults = 0; // No faults (yet!)
6583 
6584     // execute dstTally micro operations
6585     // The micro operation sequence is terminated normally when the receiving
6586     // string length becomes exhausted. The micro operation sequence is
6587     // terminated abnormally (with an illegal procedure fault) if a move from
6588     // an exhausted sending string or the use of an exhausted MOP string is
6589     // attempted.
6590 
6591     while (e->dstTally)
6592     {
6593         sim_debug (DBG_TRACEEXT, & cpu_dev,
6594                    "mopExecutor srcTally %d dstTally %d mopTally %d\n",
6595                    e->srcTally, e->dstTally, e->mopTally);
6596         MOP_struct *m = EISgetMop(cpup);
6597         if (! m)
6598           {
6599             sim_debug (DBG_TRACEEXT, & cpu_dev, "mopExecutor EISgetMop forced break\n");
6600             e->_faults |= FAULT_IPR;   // XXX ill proc fault
6601             break;
6602           }
6603         int mres = m->f(cpup);    // execute mop
6604 
6605         // PVS-Studio claims: Expression 'e->_faults & FAULT_IPR' is always false.
6606         if (e->_faults & FAULT_IPR) //-V547
6607             break; // hard IPR raised by a MOP
6608 
6609         // RJ78 specifies "if at completion of a move (L1 exhausted)", AL39
6610         // doesn't define "completion of a move".
6611         // But ISOLTS-845 asserts a case where L1 is NOT exhausted. Therefore I
6612         // assume "L2 exhausted" or "L1 or L2 exhausted" is the correct
6613         // interpretation. Both these options pass ISOLTS-845.
6614         // "L3 exhausted" is also an option but unlikely since that would fire
6615         // the BZ check even upon normal termination.
6616         // XXX DH03 7-295 suggests that there might be a difference between MVE
6617         // and MVNE. It might well be that DPS88/9000 behaves differently than
6618         // DPS8.
6619 
6620 
6621 
6622 
6623 
6624 
6625 
6626         // immediate (L1 or L2) srcTally test
6627         // perhaps more adherent to documentation
6628         if (e->mopTally == 0 || mres)
6629           {
6630             sim_debug (DBG_TRACEEXT, & cpu_dev,
6631                        "mopExecutor N1 or N2 exhausted\n");
6632 
6633             if (e->mopZ && e->mopBZ)
6634               {
6635                 e->out = e->outBuffer; //-V1048  // reset output buffer pointer
6636                 e->dstTally = (int) e->N3;       // number of chars in dst (max 63)
6637                 while (e->dstTally)
6638                   {
6639                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6640                   }
6641               }
6642             else if (mres || e->dstTally) //-V560
6643               { // N1 or N2 exhausted and BZ wasn't enabled
6644                 e->_faults |= FAULT_IPR;
6645               } // otherwise normal termination
6646             break;
6647           }
6648     }
6649 
6650     sim_debug (DBG_TRACEEXT, & cpu_dev, "mop faults %o src %d dst %d mop %d\n",
6651                e->_faults, e->srcTally, e->dstTally, e->mopTally);
6652 
6653 //"The micro-operation sequence is terminated normally when the receiving string
6654 // length is exhausted. The micro-operation sequence is terminated abnormally (with
6655 // an IPR fault) if an attempt is made to move from an exhausted sending string or to
6656 // use an exhausted MOP string.
6657 
6658 // ISOLTS 845 is happy with no check at all
6659 
6660 
6661 
6662 
6663 
6664 
6665 
6666 
6667 
6668 
6669 
6670 
6671 
6672 
6673 
6674 
6675 
6676 
6677 
6678 
6679 
6680 
6681 
6682 
6683 
6684 
6685 
6686 
6687 
6688 
6689 
6690 
6691 
6692 
6693 
6694 
6695 
6696 
6697 
6698 
6699     if (e -> _faults)
6700       doFault (FAULT_IPR, fst_ill_proc, "mopExecutor");
6701 }
6702 
6703 void mve (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6704   {
6705     EISstruct * e = & cpu.currentEISinstruction;
6706 
6707     sim_debug(DBG_TRACEEXT, & cpu_dev, "mve\n");
6708 
6709     fault_ipr_subtype_ mod_fault = 0;
6710 
6711 #if !defined(EIS_SETUP)
6712     setupOperandDescriptor(cpup, 1, &mod_fault);
6713     setupOperandDescriptor(cpup, 2, &mod_fault);
6714     setupOperandDescriptor(cpup, 3, &mod_fault);
6715 #endif
6716 
6717     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
6718     parseAlphanumericOperandDescriptor(cpup, 2, 2, false, &mod_fault);
6719     parseAlphanumericOperandDescriptor(cpup, 3, 3, false, &mod_fault);
6720 
6721     L68_ (
6722       // L68 raises it immediately
6723       if (mod_fault)
6724         {
6725           doFault (FAULT_IPR,
6726                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6727                    "Illegal modifier");
6728         }
6729     )
6730 
6731     // Bits 0, 1, 9, and 10 MBZ
6732     // According to RJ78, bit 9 is T, but is not mentioned in the text.
6733     if (IWB_IRODD & 0600600000000)
6734       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mve: 0, 1, 9, 10 MBZ");
6735 
6736     // Bit 23 of OP1 MBZ
6737     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
6738       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op1 23 MBZ");
6739 
6740 
6741 
6742 
6743 
6744 
6745     // only bit 23 according to RH03. this was fixed in DPS9000
6746     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
6747       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op2 23 MBZ");
6748 
6749     // Bit 23 of OP3 MBZ
6750     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6751       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op3 23 MBZ");
6752 
6753     DPS8M_ (
6754       // DPS8M raises it delayed
6755       if (mod_fault)
6756         {
6757           doFault (FAULT_IPR,
6758                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6759                    "Illegal modifier");
6760         }
6761     )
6762 
6763     // initialize mop flags. Probably best done elsewhere.
6764     e->mopES = false; // End Suppression flag
6765     e->mopSN = false; // Sign flag
6766     e->mopBZ = false; // Blank-when-zero flag
6767     e->mopZ  = true;  // Zero flag
6768 
6769     e->srcTally = (int) e->N1;  // number of chars in src (max 63)
6770     e->dstTally = (int) e->N3;  // number of chars in dst (max 63)
6771 
6772 #if defined(EIS_PTR3)
6773     e->srcTA = (int) TA1;    // type of chars in src
6774 #else
6775     e->srcTA = (int) e->TA1;    // type of chars in src
6776 #endif
6777 
6778     switch (e -> srcTA)
6779       {
6780         case CTA4:
6781           e -> srcSZ = 4;
6782           break;
6783         case CTA6:
6784           e -> srcSZ = 6;
6785           break;
6786         case CTA9:
6787           e -> srcSZ = 9;
6788           break;
6789       }
6790 
6791 #if defined(EIS_PTR3)
6792     uint dstTA = TA3;    // type of chars in dst
6793 #else
6794     uint dstTA = e -> TA3;    // type of chars in dst
6795 #endif
6796 
6797     switch (dstTA)
6798       {
6799         case CTA4:
6800           e -> dstSZ = 4;
6801           break;
6802         case CTA6:
6803           e -> dstSZ = 6;
6804           break;
6805         case CTA9:
6806           e -> dstSZ = 9;
6807           break;
6808       }
6809 
6810     // 1. load sending string into inputBuffer
6811     EISloadInputBufferAlphnumeric (cpup, 1);   // according to MF1
6812 
6813     // 2. Execute micro operation string, starting with first (4-bit) digit.
6814     e -> mvne = false;
6815 
6816 #if defined(EIS_PTR2)
6817     mopExecutor (cpup);
6818 #else
6819     mopExecutor (cpup, 2);
6820 #endif
6821 
6822     e -> dstTally = (int) e -> N3;  // restore dstTally for output
6823 
6824     EISwriteOutputBufferToMemory (cpup, 3);
6825     cleanupOperandDescriptor (cpup, 1);
6826     cleanupOperandDescriptor (cpup, 2);
6827     cleanupOperandDescriptor (cpup, 3);
6828   }
6829 
6830 void mvne (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6831   {
6832     EISstruct * e = & cpu.currentEISinstruction;
6833 
6834     fault_ipr_subtype_ mod_fault = 0;
6835 
6836 #if !defined(EIS_SETUP)
6837     setupOperandDescriptor (cpup, 1, &mod_fault);
6838     setupOperandDescriptor (cpup, 2, &mod_fault);
6839     setupOperandDescriptor (cpup, 3, &mod_fault);
6840 #endif
6841 
6842     parseNumericOperandDescriptor (cpup, 1, &mod_fault);
6843     parseAlphanumericOperandDescriptor (cpup, 2, 2, false, &mod_fault);
6844     parseAlphanumericOperandDescriptor (cpup, 3, 3, false, &mod_fault);
6845 
6846     L68_ (
6847       // L68 raises it immediately
6848       if (mod_fault)
6849         {
6850           doFault (FAULT_IPR,
6851                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6852                    "Illegal modifier");
6853         }
6854     )
6855 
6856     // Bits 0, 1, 9, and 10 MBZ
6857     if (IWB_IRODD & 0600600000000)
6858       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvne: 0, 1, 9, 10 MBZ");
6859 
6860     // Bit 24-29 of OP1 MBZ
6861     // Multics has been observed to use 600162017511, cf RJ78
6862     //if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
6863       //doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op1 24-29 MBZ");
6864 
6865 
6866 
6867 
6868 
6869 
6870     // only bits 21-23 according to RJ78, maybe even less on DPS8
6871     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000070000)
6872       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op2 21-23 MBZ");
6873 
6874 
6875 
6876 
6877 
6878 
6879     // only bit 23 according to RJ78
6880     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6881       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op3 23 MBZ");
6882 
6883     DPS8M_ (
6884       // DPS8M raises it delayed
6885       if (mod_fault)
6886         {
6887           doFault (FAULT_IPR,
6888                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6889                    "Illegal modifier");
6890         }
6891     )
6892 
6893     uint srcTN = e -> TN1;    // type of chars in src
6894 
6895     int n1 = 0;
6896 
6897     /*
6898      * Here we need to distinguish between 4 type of numbers.
6899      *
6900      * CSFL - Floating-point, leading sign
6901      * CSLS - Scaled fixed-point, leading sign
6902      * CSTS - Scaled fixed-point, trailing sign
6903      * CSNS - Scaled fixed-point, unsigned
6904      */
6905 
6906     // determine precision
6907     switch(e->S1)
6908     {
6909         case CSFL:
6910             n1 = (int) e->N1 - 1; // need to account for the - sign
6911             if (srcTN == CTN4)
6912                 n1 -= 2;    // 2 4-bit digits exponent
6913             else
6914                 n1 -= 1;    // 1 9-bit digit exponent
6915             break;
6916 
6917         case CSLS:
6918         case CSTS:
6919             n1 = (int) e->N1 - 1; // only 1 sign
6920             break;
6921 
6922         case CSNS:
6923             n1 = (int) e->N1;     // no sign
6924             break;  // no sign wysiwyg
6925     }
6926 
6927     if (n1 < 1)
6928         doFault (FAULT_IPR, fst_ill_proc, "mvne adjusted n1<1");
6929 
6930     // Putting this check in pAOD breaks Multics boot
6931     // From DH03 it seems that DPS8 does not check this explicitly, but L2 exhaust occurs which raises IPR anyway
6932     // So we may as well keep it here.
6933     if (e->N[1] == 0)
6934       doFault (FAULT_IPR, fst_ill_proc, "mvne N2 0");
6935 
6936     // this is a flaw in DPS8/70 which was corrected in DPS88 and later
6937     // ISOLTS-841 07h, RH03 p.7-295
6938     if (e->N[2] == 0)
6939       doFault (FAULT_IPR, fst_ill_proc, "mvne N3 0");
6940 
6941 //if ((e -> op [0]  & 0000000007700) ||
6942 //    (e -> op [1]  & 0000000077700) ||
6943 //    (e -> op [2]  & 0000000017700))
6944 //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]);
6945 //if (e -> op [0]  & 0000000007700) sim_printf ("op1\n");
6946 //if (e -> op [1]  & 0000000077700) sim_printf ("op2\n");
6947 //if (e -> op [2]  & 0000000017700) sim_printf ("op3\n");
6948 //000140  aa  100 004 024 500   mvne      (pr),(ic),(pr)
6949 //000141  aa  6 00162 01 7511   desc9ls   pr6|114,9,-3
6950 //000142  aa   000236 00 0007   desc9a    158,7               000376 = 403040144040
6951 //000143  aa  6 00134 00 0012   desc9a    pr6|92,10           vcpu
6952 //
6953 // The desc8ls is sign-extending the -3.
6954 
6955     // initialize mop flags. Probably best done elsewhere.
6956     e->mopES = false; // End Suppression flag
6957     e->mopSN = false; // Sign flag
6958     e->mopBZ = false; // Blank-when-zero flag
6959     e->mopZ  = true;  // Zero flag
6960 
6961     e -> srcTally = (int) e -> N1;  // number of chars in src (max 63)
6962     e -> dstTally = (int) e -> N3;  // number of chars in dst (max 63)
6963 
6964 // XXX Temp hack to get MOP to work. Merge TA/TN?
6965 // The MOP operators look at srcTA to make 9bit/not 9-bit decisions about
6966 // the contents of inBuffer; parseNumericOperandDescriptor(cpup, ) always puts
6967 // 4 bit data in inBuffer, so signal the MOPS code of that.
6968     e->srcTA = CTA4;    // type of chars in src
6969 
6970     switch(srcTN)
6971     {
6972         case CTN4:
6973             //e->srcAddr = e->YChar41;
6974             e->srcSZ = 4; //-V1037  // stored as 4-bit decimals
6975             break;
6976         case CTN9:
6977             //e->srcAddr = e->YChar91;
6978             e->srcSZ = 4; //-V1037  // 'cause everything is stored as 4-bit decimals
6979             break;
6980     }
6981 
6982 #if defined(EIS_PTR3)
6983     uint dstTA = TA3;     // type of chars in dst
6984 #else
6985     uint dstTA = e->TA3;  // type of chars in dst
6986 #endif
6987     switch(dstTA)
6988     {
6989         case CTA4:
6990             //e->dstAddr = e->YChar43;
6991             e->dstSZ = 4;
6992             break;
6993         case CTA6:
6994             //e->dstAddr = e->YChar63;
6995             e->dstSZ = 6;
6996             break;
6997         case CTA9:
6998             //e->dstAddr = e->YChar93;
6999             e->dstSZ = 9;
7000             break;
7001     }
7002 
7003 #if defined(EIS_PTR3)
7004     sim_debug (DBG_TRACEEXT, & cpu_dev,
7005       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
7006       e->N1, e->N2, e->N3, e->TN1, e->CN1, TA3, e->CN3);
7007 #else
7008     sim_debug (DBG_TRACEEXT, & cpu_dev,
7009       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
7010       e->N1, e->N2, e->N3, e->TN1, e->CN1, e->TA3, e->CN3);
7011 #endif
7012 
7013     // 1. load sending string into inputBuffer
7014     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7015 
7016     // 2. Test sign and, if required, set the SN flag. (Sign flag; initially
7017     // set OFF if the sending string has an alphanumeric descriptor or an
7018     // unsigned numeric descriptor. If the sending string has a signed numeric
7019     // descriptor, the sign is initially read from the sending string from the
7020     // digit position defined by the sign and the decimal type field (S); SN is
7021     // set OFF if positive, ON if negative. If all digits are zero, the data is
7022     // assumed positive and the SN flag is set OFF, even when the sign is
7023     // negative.)
7024 
7025     int sum = 0;
7026     for(int n = 0 ; n < e -> srcTally ; n ++)
7027         sum += e -> inBuffer [n];
7028     if ((e -> sign == -1) && sum)
7029         e -> mopSN = true;
7030 
7031     // 3. Execute micro operation string, starting with first (4-bit) digit.
7032     e -> mvne = true;
7033 
7034 #if defined(EIS_PTR2)
7035     mopExecutor (cpup);
7036 #else
7037     mopExecutor (cpup, 2);
7038 #endif
7039 
7040     e -> dstTally = (int) e -> N3;  // restore dstTally for output
7041 
7042     EISwriteOutputBufferToMemory (cpup, 3);
7043     cleanupOperandDescriptor (cpup, 1);
7044     cleanupOperandDescriptor (cpup, 2);
7045     cleanupOperandDescriptor (cpup, 3);
7046   }
7047 
7048 /*
7049  * MVT - Move Alphanumeric with Translation
7050  */
7051 
7052 void mvt (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7053   {
7054     EISstruct * e = & cpu.currentEISinstruction;
7055 
7056     // For i = 1, 2, ..., minimum (N1,N2)
7057     //    m = C(Y-charn1)i-1
7058     //    C(Y-char93)m → C(Y-charn2)i-1
7059     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7060     //    m = C(FILL)
7061     //    C(Y-char93)m → C(Y-charn2)i-1
7062 
7063     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
7064 
7065     fault_ipr_subtype_ mod_fault = 0;
7066 
7067 #if !defined(EIS_SETUP)
7068     setupOperandDescriptor (cpup, 1, &mod_fault);
7069     setupOperandDescriptor (cpup, 2, &mod_fault);
7070     setupOperandDescriptorCache (cpup,3);
7071 #endif
7072 
7073     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
7074     parseAlphanumericOperandDescriptor (cpup, 2, 2, false, &mod_fault);
7075     parseArgOperandDescriptor (cpup, 3, &mod_fault);
7076 
7077     L68_ (
7078       // L68 raises it immediately
7079       if (mod_fault)
7080         {
7081           doFault (FAULT_IPR,
7082                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7083                    "Illegal modifier");
7084         }
7085     )
7086 
7087 // ISOLTS 808 test-03b sets bit 0, 1
7088 // ISOLTS 808 test-03b sets bit 0, 1, 9
7089 
7090     // Bits 10 MBZ
7091     if (IWB_IRODD & 0000200000000)
7092       {
7093         //sim_printf ("mvt %012"PRIo64"\n", IWB_IRODD);
7094         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvt 10 MBZ");
7095       }
7096 
7097 
7098 
7099 
7100 
7101 
7102 
7103 
7104 
7105     // Bit 23 of OP1 MBZ
7106     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
7107       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op1 23 MBZ");
7108 
7109 // This breaks eis_tester mvt 110
7110 
7111 
7112 
7113 
7114 
7115 
7116     // Bits 18-28 of OP3 MBZ
7117     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777600)
7118       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op3 18-28 MBZ");
7119 
7120     DPS8M_ (
7121       // DPS8M raises it delayed
7122       if (mod_fault)
7123         {
7124           doFault (FAULT_IPR,
7125                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7126                    "Illegal modifier");
7127         }
7128     )
7129 
7130 #if defined(EIS_PTR3)
7131     e->srcTA = (int) TA1;
7132     uint dstTA = TA2;
7133 
7134     switch (TA1)
7135 #else
7136     e->srcTA = (int) e->TA1;
7137     uint dstTA = e->TA2;
7138 
7139     switch (e -> TA1)
7140 #endif
7141       {
7142         case CTA4:
7143           e -> srcSZ = 4;
7144           break;
7145         case CTA6:
7146           e -> srcSZ = 6;
7147           break;
7148         case CTA9:
7149           e -> srcSZ = 9;
7150          break;
7151       }
7152 
7153 #if defined(EIS_PTR3)
7154     switch (TA2)
7155 #else
7156     switch (e -> TA2)
7157 #endif
7158       {
7159         case CTA4:
7160           e -> dstSZ = 4;
7161           break;
7162         case CTA6:
7163           e -> dstSZ = 6;
7164           break;
7165         case CTA9:
7166           e -> dstSZ = 9;
7167           break;
7168       }
7169 
7170     //  Prepage Check in a Multiword Instruction
7171     //  The MVT, TCT, TCTR, and CMPCT instruction have a prepage check. The
7172     //  size of the translate table is determined by the TA1 data type as shown
7173     //  in the table below. Before the instruction is executed, a check is made
7174     //  for allocation in memory for the page for the translate table. If the
7175     //  page is not in memory, a Missing Page fault occurs before execution of
7176     //  the instruction. (Bull RJ78 p.7-75)
7177 
7178     // TA1              TRANSLATE TABLE SIZE
7179     // 4-BIT CHARACTER      4 WORDS
7180     // 6-BIT CHARACTER     16 WORDS
7181     // 9-BIT CHARACTER    128 WORDS
7182 
7183     uint xlatSize = 0;   // size of xlation table in words .....
7184 #if defined(EIS_PTR3)
7185     switch(TA1)
7186 #else
7187     switch(e->TA1)
7188 #endif
7189     {
7190         case CTA4:
7191             xlatSize = 4;
7192             break;
7193         case CTA6:
7194             xlatSize = 16;
7195             break;
7196         case CTA9:
7197             xlatSize = 128;
7198             break;
7199     }
7200 
7201 
7202 
7203 
7204 
7205 
7206 
7207 
7208 
7209     // ISOLTS 878 01c - op1 and xlate table are prepaged, in that order
7210     // prepage op1
7211     int lastpageidx = ((int)e->N1 + (int)e->CN1 -1) / e->srcSZ;
7212     if (lastpageidx>0)
7213         EISReadIdx(cpup, &e->ADDR1, (uint)lastpageidx);
7214     // prepage xlate table
7215     EISReadIdx(cpup, &e->ADDR3, 0);
7216     EISReadIdx(cpup, &e->ADDR3, xlatSize-1);
7217 
7218     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7219 
7220     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
7221     word9 fillT = fill;  // possibly truncated fill pattern
7222     // play with fill if we need to use it
7223     switch(e->srcSZ)
7224     {
7225         case 4:
7226             fillT = fill & 017;    // truncate upper 5-bits
7227             break;
7228         case 6:
7229             fillT = fill & 077;    // truncate upper 3-bits
7230             break;
7231     }
7232 
7233     sim_debug (DBG_TRACEEXT, & cpu_dev,
7234       "%s srcCN:%d dstCN:%d srcSZ:%d dstSZ:%d T:%d fill:%03o/%03o N1:%d N2:%d\n",
7235       __func__, e -> CN1, e -> CN2, e -> srcSZ, e -> dstSZ, T,
7236       fill, fillT, e -> N1, e -> N2);
7237 
7238     PNL (L68_ (if (max (e->N1, e->N2) < 128)
7239       DU_CYCLE_FLEN_128;))
7240 
7241     for ( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY ++)
7242     {
7243         word9 c = EISget469(cpup, 1, cpu.du.CHTALLY); // get src char
7244         int cidx = 0;
7245 
7246 #if defined(EIS_PTR3)
7247         if (TA1 == TA2)
7248 #else
7249         if (e->TA1 == e->TA2)
7250 #endif
7251             EISput469(cpup, 2, cpu.du.CHTALLY, xlate (cpup, &e->ADDR3, dstTA, c));
7252         else
7253         {
7254             // If data types are dissimilar (TA1 ≠ TA2), each character is high-order
7255             //   truncated or zero filled, as appropriate, as it is moved.
7256             //   No character conversion takes place.
7257             cidx = c;
7258 
7259             word9 cout = xlate(cpup, &e->ADDR3, dstTA, (uint) cidx);
7260 
7261 //            switch(e->dstSZ)
7262 //            {
7263 //                case 4:
7264 //                    cout &= 017;    // truncate upper 5-bits
7265 //                    break;
7266 //                case 6:
7267 //                    cout &= 077;    // truncate upper 3-bits
7268 //                    break;
7269 //            }
7270 
7271             switch (e->srcSZ)
7272             {
7273                 case 6:
7274                     switch(e->dstSZ)
7275                     {
7276                         case 4:
7277                             cout &= 017;    // truncate upper 2-bits
7278                             break;
7279                         case 9:
7280                             break;              // should already be 0-filled
7281                     }
7282                     break;
7283                 case 9:
7284                     switch(e->dstSZ)
7285                     {
7286                         case 4:
7287                             cout &= 017;    // truncate upper 5-bits
7288                             break;
7289                         case 6:
7290                             cout &= 077;    // truncate upper 3-bits
7291                             break;
7292                     }
7293                     break;
7294             }
7295 
7296             EISput469 (cpup, 2, cpu.du.CHTALLY, cout);
7297         }
7298     }
7299 
7300     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7301     //    m = C(FILL)
7302     //    C(Y-char93)m → C(Y-charn2)N2-i
7303 
7304     if (e->N1 < e->N2)
7305     {
7306         word9 cfill = xlate(cpup, &e->ADDR3, dstTA, fillT);
7307         switch (e->srcSZ)
7308         {
7309             case 6:
7310                 switch(e->dstSZ)
7311                 {
7312                     case 4:
7313                         cfill &= 017;    // truncate upper 2-bits
7314                         break;
7315                     case 9:
7316                         break;              // should already be 0-filled
7317                 }
7318                 break;
7319             case 9:
7320                 switch(e->dstSZ)
7321                 {
7322                     case 4:
7323                         cfill &= 017;    // truncate upper 5-bits
7324                         break;
7325                     case 6:
7326                         cfill &= 077;    // truncate upper 3-bits
7327                         break;
7328                 }
7329                 break;
7330         }
7331 
7332         for( ; cpu.du.CHTALLY < e->N2 ; cpu.du.CHTALLY ++)
7333             EISput469 (cpup, 2, cpu.du.CHTALLY, cfill);
7334     }
7335 
7336     cleanupOperandDescriptor (cpup, 1);
7337     cleanupOperandDescriptor (cpup, 2);
7338     cleanupOperandDescriptor (cpup, 3);
7339 
7340     if (e->N1 > e->N2)
7341       {
7342         SET_I_TRUNC;
7343         if (T && ! TST_I_OMASK)
7344           doFault(FAULT_OFL, fst_zero, "mvt truncation fault");
7345       }
7346     else
7347       CLR_I_TRUNC;
7348   }
7349 
7350 /*
7351  * cmpn - Compare Numeric
7352  */
7353 
7354 void cmpn (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7355 {
7356     EISstruct * e = & cpu.currentEISinstruction;
7357 
7358     // C(Y-charn1) :: C(Y-charn2) as numeric values
7359 
7360     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7361     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7362     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7363 
7364     fault_ipr_subtype_ mod_fault = 0;
7365 
7366 #if !defined(EIS_SETUP)
7367     setupOperandDescriptor(cpup, 1, &mod_fault);
7368     setupOperandDescriptor(cpup, 2, &mod_fault);
7369 #endif
7370 
7371     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
7372     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
7373 
7374     L68_ (
7375       // L68 raises it immediately
7376       if (mod_fault)
7377         {
7378           doFault (FAULT_IPR,
7379                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7380                    "Illegal modifier");
7381         }
7382     )
7383 
7384     // Bits 0-10 MBZ
7385     if (IWB_IRODD & 0777600000000)
7386       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpn 0-10 MBZ");
7387 
7388     DPS8M_ (
7389       // DPS8M raises it delayed
7390       if (mod_fault)
7391         {
7392           doFault (FAULT_IPR,
7393                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7394                    "Illegal modifier");
7395         }
7396     )
7397 
7398     uint srcTN = e->TN1;    // type of chars in src
7399 
7400     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
7401 
7402     /*
7403      * Here we need to distinguish between 4 type of numbers.
7404      *
7405      * CSFL - Floating-point, leading sign
7406      * CSLS - Scaled fixed-point, leading sign
7407      * CSTS - Scaled fixed-point, trailing sign
7408      * CSNS - Scaled fixed-point, unsigned
7409      */
7410 
7411     // determine precision
7412     switch(e->S1)
7413     {
7414         case CSFL:
7415             n1 = (int) e->N1 - 1; // need to account for the - sign
7416             if (srcTN == CTN4)
7417                 n1 -= 2;    // 2 4-bit digits exponent
7418             else
7419                 n1 -= 1;    // 1 9-bit digit exponent
7420             sc1 = 0;        // no scaling factor
7421             break;
7422 
7423         case CSLS:
7424         case CSTS:
7425             n1 = (int) e->N1 - 1; // only 1 sign
7426             sc1 = -e->SF1;
7427             break;
7428 
7429         case CSNS:
7430             n1 = (int) e->N1;     // no sign
7431             sc1 = -e->SF1;
7432             break;  // no sign wysiwyg
7433     }
7434 
7435     if (n1 < 1)
7436         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n1<1");
7437 
7438     switch(e->S2)
7439     {
7440         case CSFL:
7441             n2 = (int) e->N2 - 1; // need to account for the sign
7442             if (e->TN2 == CTN4)
7443                 n2 -= 2;    // 2 4-bit digit exponent
7444             else
7445                 n2 -= 1;    // 1 9-bit digit exponent
7446             sc2 = 0;        // no scaling factor
7447             break;
7448 
7449         case CSLS:
7450         case CSTS:
7451             n2 = (int) e->N2 - 1; // 1 sign
7452             sc2 = -e->SF2;
7453             break;
7454 
7455         case CSNS:
7456             n2 = (int) e->N2;     // no sign
7457             sc2 = -e->SF2;
7458             break;  // no sign wysiwyg
7459     }
7460 
7461     if (n2 < 1)
7462         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n2<1");
7463 
7464     decContext set;
7465     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
7466     decContextDefaultDPS8(&set);
7467 
7468     set.traps=0;
7469 
7470     decNumber _1, _2, _3;
7471 
7472     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7473 
7474     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
7475     if (e->sign == -1)
7476         op1->bits |= DECNEG;
7477     if (e->S1 == CSFL)
7478         op1->exponent = e->exponent;
7479 
7480     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
7481 
7482     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
7483     if (e->sign == -1)
7484         op2->bits |= DECNEG;
7485     if (e->S2 == CSFL)
7486         op2->exponent = e->exponent;
7487 
7488     // signed-compare
7489     decNumber *cmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7490     int cSigned = decNumberToInt32(cmp, &set);
7491 
7492     // take absolute value of operands
7493     op1 = decNumberAbs(op1, op1, &set);
7494     op2 = decNumberAbs(op2, op2, &set);
7495 
7496     // magnitude-compare
7497     decNumber *mcmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7498     int cMag = decNumberToInt32(mcmp, &set);
7499 
7500     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7501     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7502     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7503 
7504     SC_I_ZERO (cSigned == 0);
7505     SC_I_NEG (cSigned == 1);
7506     SC_I_CARRY (cMag != 1);
7507 
7508     cleanupOperandDescriptor (cpup, 1);
7509     cleanupOperandDescriptor (cpup, 2);
7510 }
7511 
7512 /*
7513  * mvn - move numeric (initial version was deleted by house gnomes)
7514  */
7515 
7516 /*
7517  * write 4-bit chars to memory @ pos ...
7518  */
7519 
7520 static void EISwrite4(cpu_state_t * cpup, EISaddr *p, int *pos, word4 char4)
     /* [previous][next][first][last][top][bottom][index][help] */
7521 {
7522     word36 w;
7523     if (*pos > 7)    // out-of-range?
7524     {
7525         *pos = 0;    // reset to 1st byte
7526 #if defined(EIS_PTR)
7527         long eisaddr_idx = EISADDR_IDX (p);
7528 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7529         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7530 #else
7531         p->address = (p->address + 1) & AMASK;        // goto next dstAddr in memory
7532 #endif
7533     }
7534 
7535     w = EISRead(cpup, p);      // read dst memory into w
7536 
7537 // AL39, Figure 2-3
7538     switch (*pos)
7539     {
7540         case 0:
7541             //w = bitfieldInsert36(w, char4, 31, 5);
7542             w = setbits36_4 (w, 1, char4);
7543             break;
7544         case 1:
7545             //w = bitfieldInsert36(w, char4, 27, 4);
7546             w = setbits36_4 (w, 5, char4);
7547             break;
7548         case 2:
7549             //w = bitfieldInsert36(w, char4, 22, 5);
7550             w = setbits36_4 (w, 10, char4);
7551             break;
7552         case 3:
7553             //w = bitfieldInsert36(w, char4, 18, 4);
7554             w = setbits36_4 (w, 14, char4);
7555             break;
7556         case 4:
7557             //w = bitfieldInsert36(w, char4, 13, 5);
7558             w = setbits36_4 (w, 19, char4);
7559             break;
7560         case 5:
7561             //w = bitfieldInsert36(w, char4, 9, 4);
7562             w = setbits36_4 (w, 23, char4);
7563             break;
7564         case 6:
7565             //w = bitfieldInsert36(w, char4, 4, 5);
7566             w = setbits36_4 (w, 28, char4);
7567             break;
7568         case 7:
7569             //w = bitfieldInsert36(w, char4, 0, 4);
7570             w = setbits36_4 (w, 32, char4);
7571             break;
7572     }
7573 
7574     EISWriteIdx(cpup, p, 0, w, true); // XXX this is the inefficient part!
7575 
7576     *pos += 1;       // to next char.
7577 }
7578 
7579 /*
7580  * write 9-bit bytes to memory @ pos ...
7581  */
7582 
7583 static void EISwrite9(cpu_state_t *cpup, EISaddr *p, int *pos, word9 char9)
     /* [previous][next][first][last][top][bottom][index][help] */
7584 {
7585     word36 w;
7586     if (*pos > 3)    // out-of-range?
7587     {
7588         *pos = 0;    // reset to 1st byte
7589 #if defined(EIS_PTR)
7590         long eisaddr_idx = EISADDR_IDX (p);
7591 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7592         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7593 #else
7594         p->address = (p->address + 1) & AMASK;       // goto next dstAddr in memory
7595 #endif
7596     }
7597 
7598     w = EISRead(cpup, p);      // read dst memory into w
7599 
7600 // AL39, Figure 2-5
7601     switch (*pos)
7602     {
7603         case 0:
7604             //w = bitfieldInsert36(w, char9, 27, 9);
7605             w = setbits36_9 (w, 0, char9);
7606             break;
7607         case 1:
7608             //w = bitfieldInsert36(w, char9, 18, 9);
7609             w = setbits36_9 (w, 9, char9);
7610             break;
7611         case 2:
7612             //w = bitfieldInsert36(w, char9, 9, 9);
7613             w = setbits36_9 (w, 18, char9);
7614             break;
7615         case 3:
7616             //w = bitfieldInsert36(w, char9, 0, 9);
7617             w = setbits36_9 (w, 27, char9);
7618             break;
7619     }
7620 
7621     EISWriteIdx (cpup, p, 0, w, true); // XXX this is the inefficient part!
7622 
7623     *pos += 1;       // to next byte.
7624 }
7625 
7626 /*
7627  * write a 4-, or 9-bit numeric char to dstAddr ....
7628  */
7629 
7630 static void EISwrite49(cpu_state_t * cpup, EISaddr *p, int *pos, int tn, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
7631 {
7632     switch(tn)
7633     {
7634         case CTN4:
7635             EISwrite4(cpup, p, pos, (word4) c49);
7636             return;
7637         case CTN9:
7638             EISwrite9(cpup, p, pos, c49);
7639             return;
7640     }
7641 }
7642 
7643 void mvn (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7644 {
7645     /*
7646      * EXPLANATION:
7647      * Starting at location YC1, the decimal number of data type TN1 and sign
7648      * and decimal type S1 is moved, properly scaled, to the decimal number of
7649      * data type TN2 and sign and decimal type S2 that starts at location YC2.
7650      * If S2 indicates a fixed-point format, the results are stored as L2
7651      * digits using scale factor SF2, and thereby may cause
7652      * most-significant-digit overflow and/or least- significant-digit
7653      * truncation.
7654      * If P = 1, positive signed 4-bit results are stored using octal 13 as the
7655      * plus sign. Rounding is legal for both fixed-point and floating-point
7656      * formats. If P = 0, positive signed 4-bit results are stored using octal
7657      * 14 as the plus sign.
7658      * Provided that string 1 and string 2 are not overlapped, the contents of
7659      * the decimal number that starts in location YC1 remain unchanged.
7660      */
7661 
7662     EISstruct * e = & cpu.currentEISinstruction;
7663 
7664     fault_ipr_subtype_ mod_fault = 0;
7665 
7666 #if !defined(EIS_SETUP)
7667     setupOperandDescriptor(cpup, 1, &mod_fault);
7668     setupOperandDescriptor(cpup, 2, &mod_fault);
7669 #endif
7670 
7671     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
7672     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
7673 
7674     L68_ (
7675       // L68 raises it immediately
7676       if (mod_fault)
7677         {
7678           doFault (FAULT_IPR,
7679                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7680                    "Illegal modifier");
7681         }
7682     )
7683 
7684     // Bits 2-8 MBZ
7685     if (IWB_IRODD & 0377000000000)
7686      doFault (FAULT_IPR,
7687               (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault},
7688               "mvn 2-8 MBZ");
7689 
7690     DPS8M_ (
7691       // DPS8M raises it delayed
7692       if (mod_fault)
7693         {
7694           doFault (FAULT_IPR,
7695                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7696                    "Illegal modifier");
7697         }
7698     )
7699 
7700     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character
7701                                               //  control
7702     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7703     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
7704     PNL (L68_ (if (R)
7705       DU_CYCLE_FRND;))
7706 
7707     uint srcTN = e->TN1;    // type of chars in src
7708 
7709     uint dstTN = e->TN2;    // type of chars in dst
7710     uint dstCN = e->CN2;    // starting at char pos CN
7711 
7712     sim_debug (DBG_CAC, & cpu_dev,
7713                "mvn(1): TN1 %d CN1 %d N1 %d TN2 %d CN2 %d N2 %d\n",
7714                e->TN1, e->CN1, e->N1, e->TN2, e->CN2, e->N2);
7715     sim_debug (DBG_CAC, & cpu_dev,
7716                "mvn(2): SF1 %d              SF2 %d\n",
7717                e->SF1, e->SF2);
7718     sim_debug (DBG_CAC, & cpu_dev,
7719                "mvn(3): OP1 %012"PRIo64" OP2 %012"PRIo64"\n",
7720                e->OP1, e->OP2);
7721 
7722     int n1 = 0, n2 = 0, sc1 = 0;
7723 
7724     /*
7725      * Here we need to distinguish between 4 type of numbers.
7726      *
7727      * CSFL - Floating-point, leading sign
7728      * CSLS - Scaled fixed-point, leading sign
7729      * CSTS - Scaled fixed-point, trailing sign
7730      * CSNS - Scaled fixed-point, unsigned
7731      */
7732 
7733     // determine precision
7734     switch(e->S1)
7735     {
7736         case CSFL:
7737             n1 = (int) e->N1 - 1; // need to account for the - sign
7738             if (srcTN == CTN4)
7739                 n1 -= 2;    // 2 4-bit digits exponent
7740             else
7741                 n1 -= 1;    // 1 9-bit digit exponent
7742             sc1 = 0;        // no scaling factor
7743             break;
7744 
7745         case CSLS:
7746         case CSTS:
7747             n1 = (int) e->N1 - 1; // only 1 sign
7748             sc1 = -e->SF1;
7749             break;
7750 
7751         case CSNS:
7752             n1 = (int) e->N1;     // no sign
7753             sc1 = -e->SF1;
7754             break;  // no sign wysiwyg
7755     }
7756 
7757     sim_debug (DBG_CAC, & cpu_dev, "n1 %d sc1 %d\n", n1, sc1);
7758 
7759     // RJ78: An Illegal Procedure fault occurs if:
7760     // The values for the number of characters (N1 or N2) of the data
7761     // descriptors are not large enough to hold the number of characters
7762     // required for the specified sign and/or exponent, plus at least one
7763     // digit.
7764 
7765     if (n1 < 1)
7766         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n1<1");
7767 
7768     switch(e->S2)
7769     {
7770         case CSFL:
7771             n2 = (int) e->N2 - 1; // need to account for the sign
7772             if (dstTN == CTN4)
7773                 n2 -= 2;    // 2 4-bit digit exponent
7774             else
7775                 n2 -= 1;    // 1 9-bit digit exponent
7776             break;
7777 
7778         case CSLS:
7779         case CSTS:
7780             n2 = (int) e->N2 - 1; // 1 sign
7781             break;
7782 
7783         case CSNS:
7784             n2 = (int) e->N2;     // no sign
7785             break;          // no sign wysiwyg
7786     }
7787 
7788     sim_debug (DBG_CAC, & cpu_dev, "n2 %d\n", n2);
7789 
7790     if (n2 < 1)
7791         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n2<1");
7792 
7793     decContext set;
7794     decContextDefaultDPS8(&set);
7795     set.traps=0;
7796 
7797     decNumber _1;
7798 
7799     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7800 
7801     decNumber *op1 = decBCD9ToNumber (e->inBuffer, n1, sc1, &_1);
7802 
7803     if (e->sign == -1)
7804         op1->bits |= DECNEG;
7805     if (e->S1 == CSFL)
7806         op1->exponent = e->exponent;
7807     if (decNumberIsZero (op1))
7808         op1->exponent = 127;
7809 
7810     if_sim_debug (DBG_CAC, & cpu_dev)
7811     {
7812         PRINTDEC ("mvn input (op1)", op1);
7813     }
7814 
7815     bool Ovr = false, EOvr = false, Trunc = false;
7816 
7817     uint8_t out [256];
7818     char * res = formatDecimal (out, & set, op1, n2, (int) e->S2, e->SF2, R,
7819                                 & Ovr, & Trunc);
7820 
7821     sim_debug (DBG_CAC, & cpu_dev, "mvn res: '%s'\n", res);
7822 
7823     // now write to memory in proper format.....
7824 
7825     //word18 dstAddr = e->dstAddr;
7826     int pos = (int) dstCN;
7827 
7828     // 1st, take care of any leading sign .......
7829     switch(e->S2)
7830     {
7831         case CSFL:  // floating-point, leading sign.
7832         case CSLS:  // fixed-point, leading sign
7833             switch(dstTN)
7834             {
7835                 case CTN4:
7836  // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7837  // sign character is placed appropriately if the result of the operation is
7838  // positive.
7839                     if (e->P)
7840                         // special +
7841                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7842                                    (decNumberIsNegative (op1) &&
7843                                     ! decNumberIsZero(op1)) ? 015 : 013);
7844                     else
7845                         // default +
7846                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7847                                     (decNumberIsNegative (op1) &&
7848                                      ! decNumberIsZero (op1)) ? 015 : 014);
7849                     break;
7850                 case CTN9:
7851                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7852                                 (decNumberIsNegative (op1) &&
7853                                  ! decNumberIsZero (op1)) ? '-' : '+');
7854                     break;
7855             }
7856             break;
7857 
7858         case CSTS:  // nuttin' to do here .....
7859         case CSNS:
7860             break;  // no sign wysiwyg
7861     }
7862 
7863     // 2nd, write the digits .....
7864     for (int i = 0 ; i < n2 ; i ++)
7865         switch (dstTN)
7866         {
7867             case CTN4:
7868                 EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7869                             (word9) (res[i] - '0'));
7870                 break;
7871             case CTN9:
7872                 EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN, (word9) res[i]);
7873                 break;
7874         }
7875 
7876     // 3rd, take care of any trailing sign or exponent ...
7877     switch(e->S2)
7878     {
7879         case CSTS:  // write trailing sign ....
7880             switch(dstTN)
7881             {
7882                 case CTN4:
7883 // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7884 // sign character is placed appropriately if the result of the operation is
7885 // positive.
7886                     if (e->P)
7887                         // special +
7888                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7889                                     (decNumberIsNegative (op1) &&
7890                                      ! decNumberIsZero(op1)) ? 015 :  013);
7891                     else
7892                         // default +
7893                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7894                                     (decNumberIsNegative (op1) &&
7895                                      ! decNumberIsZero (op1)) ? 015 :  014);
7896                     break;
7897 
7898                 case CTN9:
7899                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7900                                 (decNumberIsNegative (op1) &&
7901                                  ! decNumberIsZero(op1)) ? '-' : '+');
7902                     break;
7903             }
7904             break;
7905 
7906         case CSFL:  // floating-point, leading sign.
7907             // write the exponent
7908             switch(dstTN)
7909             {
7910                 case CTN4:
7911                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7912                                 (op1->exponent >> 4) & 0xf); // upper 4-bits
7913                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7914                                 op1->exponent       & 0xf); // lower 4-bits
7915                     break;
7916                 case CTN9:
7917                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7918                                  op1->exponent & 0xff); // write 8-bit exponent
7919                 break;
7920             }
7921             break;
7922 
7923         case CSLS:  // fixed point, leading sign - already done
7924         case CSNS:  // fixed point, unsigned - nuttin' needed to do
7925             break;
7926     }
7927 
7928     // set flags, etc ...
7929     if (e->S2 == CSFL)
7930     {
7931         if (op1->exponent > 127)
7932         {
7933             SET_I_EOFL;
7934             EOvr = true;
7935         }
7936         if (op1->exponent < -128)
7937         {
7938             SET_I_EUFL;
7939             EOvr = true;
7940         }
7941     }
7942 
7943 sim_debug (DBG_CAC, & cpu_dev, "is neg %o\n", decNumberIsNegative(op1));
7944 sim_debug (DBG_CAC, & cpu_dev, "is zero %o\n", decNumberIsZero(op1));
7945 sim_debug (DBG_CAC, & cpu_dev, "R %o\n", R);
7946 sim_debug (DBG_CAC, & cpu_dev, "Trunc %o\n", Trunc);
7947 sim_debug (DBG_CAC, & cpu_dev, "TRUNC %o\n", TST_I_TRUNC);
7948 sim_debug (DBG_CAC, & cpu_dev, "OMASK %o\n", TST_I_OMASK);
7949 sim_debug (DBG_CAC, & cpu_dev, "tstOVFfault %o\n", tstOVFfault (cpup));
7950 sim_debug (DBG_CAC, & cpu_dev, "T %o\n", T);
7951 sim_debug (DBG_CAC, & cpu_dev, "EOvr %o\n", EOvr);
7952 sim_debug (DBG_CAC, & cpu_dev, "Ovr %o\n", Ovr);
7953     // set negative indicator if op3 < 0
7954     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));
7955 
7956     // set zero indicator if op3 == 0
7957     SC_I_ZERO (decNumberIsZero(op1));
7958 
7959     // If the truncation condition exists without rounding, then ON;
7960     // otherwise OFF
7961     SC_I_TRUNC (!R && Trunc);
7962 
7963     cleanupOperandDescriptor (cpup, 1);
7964     cleanupOperandDescriptor (cpup, 2);
7965 
7966     if (TST_I_TRUNC && T && tstOVFfault (cpup))
7967         doFault (FAULT_OFL, fst_zero, "mvn truncation(overflow) fault");
7968     if (EOvr && tstOVFfault (cpup))
7969         doFault (FAULT_OFL, fst_zero, "mvn over/underflow fault");
7970     if (Ovr)
7971     {
7972         SET_I_OFLOW;
7973         if (tstOVFfault (cpup))
7974           doFault (FAULT_OFL, fst_zero, "mvn overflow fault");
7975     }
7976 }
7977 
7978 void csl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7979   {
7980     EISstruct * e = & cpu.currentEISinstruction;
7981 
7982     // For i = bits 1, 2, ..., minimum (N1,N2)
7983     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
7984     //   C(BOLR)m → C(Y-bit2)i-1
7985     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
7986     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
7987     //   C(BOLR)m → C(Y-bit2)i-1
7988     //
7989     // INDICATORS: (Indicators not listed are not affected)
7990     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
7991     //     Truncation If N1 > N2, then ON; otherwise OFF
7992     //
7993     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
7994     // processed and the truncation indicator is set ON.
7995     //
7996     // If T = 1 and the truncation indicator is set ON by execution of the
7997     // instruction, then a truncation (overflow) fault occurs.
7998     //
7999     // BOLR
8000     // If first operand    and    second operand    then result
8001     // bit is:                    bit is:           is from bit:
8002     //        0                          0                      5
8003     //        0                          1                      6
8004     //        1                          0                      7
8005     //        1                          1                      8
8006     //
8007     // The Boolean operations most commonly used are
8008     //                  BOLR Field Bits
8009     // Operation        5      6      7      8
8010     //
8011     // MOVE             0      0      1      1
8012     // AND              0      0      0      1
8013     // OR               0      1      1      1
8014     // NAND             1      1      1      0
8015     // EXCLUSIVE OR     0      1      1      0
8016     // Clear            0      0      0      0
8017     // Invert           1      1      0      0
8018     //
8019 
8020 // 0 0 0 0  Clear
8021 // 0 0 0 1  a AND b
8022 // 0 0 1 0  a AND !b
8023 // 0 0 1 1  a
8024 // 0 1 0 0  !a AND b
8025 // 0 1 0 1  b
8026 // 0 1 1 0  a XOR b
8027 // 0 1 1 1  a OR b
8028 // 1 0 0 0  !a AND !b     !(a OR b)
8029 // 1 0 0 1  a == b        !(a XOR b)
8030 // 1 0 1 0  !b
8031 // 1 0 1 1  !b OR A
8032 // 1 1 0 0  !a
8033 // 1 1 0 1  !b AND a
8034 // 1 1 1 0  a NAND b
8035 // 1 1 1 1  Set
8036 
8037     fault_ipr_subtype_ mod_fault = 0;
8038 
8039 #if !defined(EIS_SETUP)
8040     setupOperandDescriptor (cpup, 1, & mod_fault);
8041     setupOperandDescriptor (cpup, 2, & mod_fault);
8042 #endif
8043 
8044     parseBitstringOperandDescriptor (cpup, 1, & mod_fault);
8045     parseBitstringOperandDescriptor (cpup, 2, & mod_fault);
8046 
8047     L68_ (
8048       // L68 raises it immediately
8049       if (mod_fault)
8050           doFault (FAULT_IPR,
8051                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8052                    "Illegal modifier");
8053     )
8054 
8055     // Bits 1-4 and 10 MBZ
8056     if (IWB_IRODD & 0360200000000)
8057       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8058 
8059     DPS8M_ (
8060       // DPS8M raises it delayed
8061       if (mod_fault)
8062           doFault (FAULT_IPR,
8063                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8064                    "Illegal modifier");
8065     )
8066 
8067     e->ADDR1.cPos = (int) e->C1;
8068     e->ADDR2.cPos = (int) e->C2;
8069 
8070     e->ADDR1.bPos = (int) e->B1;
8071     e->ADDR2.bPos = (int) e->B2;
8072 
8073     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8074     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8075 
8076     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8077     bool B5 = !! (BOLR & 8);
8078     bool B6 = !! (BOLR & 4);
8079     bool B7 = !! (BOLR & 2);
8080     bool B8 = !! (BOLR & 1);
8081 
8082     e->ADDR1.mode = eRWreadBit;
8083 
8084 #if !defined(EIS_PTR)
8085     sim_debug (DBG_TRACEEXT, & cpu_dev,
8086                "CSL N1 %d N2 %d\n"
8087                "CSL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8088                "CSL BOLR %u%u%u%u\n"
8089                "CSL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8090                "CSL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8091                e -> N1, e -> N2,
8092                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8093                B5, B6, B7, B8,
8094                e -> addr [0].SNR, e -> addr [0].address,
8095                e -> addr [0].cPos, e -> addr [0].bPos,
8096                e -> addr [1].SNR, e -> addr [1].address,
8097                e -> addr [1].cPos, e -> addr [1].bPos);
8098 #endif
8099 
8100     bool bR = false; // result bit
8101 
8102     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8103                  DU_CYCLE_FLEN_128;))
8104 
8105     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8106       {
8107         bool b1 = EISgetBitRWN(cpup, &e->ADDR1, true);
8108         e->ADDR2.mode = eRWreadBit;
8109         bool b2 = EISgetBitRWN(cpup, &e->ADDR2, true);
8110 
8111         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8112 
8113         if (bR)
8114           {
8115             //CLR_I_ZERO);
8116             cpu.du.Z = 0;
8117           }
8118 
8119         // write out modified bit
8120         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8121         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8122         // if ADDR1 is on a word boundary, it might fault on the next loop,
8123         // so we flush the write in case.
8124         EISgetBitRWN(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8125     }
8126 
8127     if (e->N1 < e->N2)
8128       {
8129         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8130           {
8131             bool b1 = F;
8132 
8133             e->ADDR2.mode = eRWreadBit;
8134             bool b2 = EISgetBitRWN(cpup, &e->ADDR2, true);
8135 
8136             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8137 
8138             if (bR)
8139               {
8140                 //CLR_I_ZERO;
8141                 cpu.du.Z = 0;
8142               }
8143 
8144             // write out modified bit
8145             e->ADDR2.bit = bR ? 1 : 0;
8146             e->ADDR2.mode = eRWwriteBit;
8147             // if ADDR1 is on a word boundary, it might fault on the next loop,
8148             // so we flush the write in case.
8149             EISgetBitRWN(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8150           }
8151       }
8152 
8153     EISWriteCache (cpup, &e->ADDR2);
8154 
8155     cleanupOperandDescriptor (cpup, 1);
8156     cleanupOperandDescriptor (cpup, 2);
8157 
8158     SC_I_ZERO (cpu.du.Z);
8159     if (e->N1 > e->N2)
8160       {
8161         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8162         // processed and the truncation indicator is set ON.
8163         //
8164         // If T = 1 and the truncation indicator is set ON by execution of the
8165         // instruction, then a truncation (overflow) fault occurs.
8166 
8167         SET_I_TRUNC;
8168         if (T && tstOVFfault (cpup))
8169           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8170       }
8171     else
8172       {
8173         CLR_I_TRUNC;
8174       }
8175   }
8176 
8177 /*
8178  * return B (bit position), C (char position) and word offset given:
8179  *  'length' # of bits, etc ....
8180  *  'initC' initial char position (C)
8181  *  'initB' initial bit position
8182  */
8183 
8184 static void getBitOffsets(int length, int initC, int initB, int *nWords, int *newC, int *newB)
     /* [previous][next][first][last][top][bottom][index][help] */
8185 {
8186     if (length == 0)
8187         return;
8188 
8189     int endBit = (length + 9 * initC + initB - 1) % 36;
8190 
8191     //int numWords = (length + 35) / 36;  // how many additional words will the bits take up?
8192     int numWords = (length + 9 * initC + initB + 35) / 36;  // how many additional words will the bits take up?
8193     int lastWordOffset = numWords - 1;
8194 
8195     if (lastWordOffset > 0)          // more that the 1 word needed?
8196         *nWords = lastWordOffset;  // # of additional words
8197     else
8198         *nWords = 0;    // no additional words needed
8199 
8200     *newC = endBit / 9; // last character number
8201     *newB = endBit % 9; // last bit number
8202 }
8203 
8204 static bool EISgetBitRWNR (cpu_state_t * cpup, EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
8205   {
8206     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
8207     int baseBitPosn = baseCharPosn + p -> bPos;
8208     baseBitPosn -= (int) cpu.du.CHTALLY;
8209 
8210     int bitPosn = baseBitPosn % 36;
8211     int woff = baseBitPosn / 36;
8212     while (bitPosn < 0)
8213       {
8214         bitPosn += 36;
8215         woff -= 1;
8216       }
8217 
8218 /* if (bitPosn < 0) { */
8219 /* sim_printf ("cPos %d bPos %d\n", p->cPos, p->bPos); */
8220 /* sim_printf ("baseCharPosn %d baseBitPosn %d\n", baseCharPosn, baseBitPosn); */
8221 /* sim_printf ("CHTALLY %d baseBitPosn %d\n", cpu.du.CHTALLY, baseBitPosn); */
8222 /* sim_printf ("bitPosn %d woff %d\n", bitPosn, woff); */
8223 /* sim_warn ("EISgetBitRWNR oops\n"); */
8224 /* return false; */
8225 /* } */
8226 
8227 #if defined(EIS_PTR)
8228     long eisaddr_idx = EISADDR_IDX (p);
8229 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8230     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
8231     cpu.du.Dk_PTR_W[eisaddr_idx] += (word18) woff;
8232     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8233 #else
8234     word18 saveAddr = p -> address;
8235     //p -> address += (word18) woff;
8236     //ubsan
8237     p->address = (word18) (((word18s) p->address) + (word18s) woff);
8238 #endif
8239 
8240     p -> data = EISRead (cpup, p); // read data word from memory
8241 
8242     if (p -> mode == eRWreadBit)
8243       {
8244         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
8245       }
8246     else if (p -> mode == eRWwriteBit)
8247       {
8248         //p -> data = bitfieldInsert36 (p -> data, p -> bit, bitPosn, 1);
8249         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
8250 
8251         EISWriteIdx (cpup, p, 0, p -> data, flush); // write data word to memory
8252       }
8253 
8254     p->last_bit_posn = bitPosn;
8255 
8256 #if defined(EIS_PTR)
8257     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
8258 #else
8259     p -> address = saveAddr;
8260 #endif
8261     return p -> bit;
8262   }
8263 
8264 void csr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8265   {
8266     EISstruct * e = & cpu.currentEISinstruction;
8267 
8268     // For i = bits 1, 2, ..., minimum (N1,N2)
8269     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8270     //   C(BOLR)m → C( Y-bit2)N2-i
8271     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8272     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8273     //    C(BOLR)m → C( Y-bit2)N2-i
8274     // INDICATORS: (Indicators not listed are not affected)
8275     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8276     //     Truncation If N1 > N2, then ON; otherwise OFF
8277     //
8278     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8279     // processed and the truncation indicator is set ON.
8280     //
8281     // If T = 1 and the truncation indicator is set ON by execution of the
8282     // instruction, then a truncation (overflow) fault occurs.
8283     //
8284     // BOLR
8285     // If first operand    and    second operand    then result
8286     // bit is:                    bit is:           is from bit:
8287     //        0                          0                      5
8288     //        0                          1                      6
8289     //        1                          0                      7
8290     //        1                          1                      8
8291     //
8292     // The Boolean operations most commonly used are
8293     //                  BOLR Field Bits
8294     // Operation        5      6      7      8
8295     //
8296     // MOVE             0      0      1      1
8297     // AND              0      0      0      1
8298     // OR               0      1      1      1
8299     // NAND             1      1      1      0
8300     // EXCLUSIVE OR     0      1      1      0
8301     // Clear            0      0      0      0
8302     // Invert           1      1      0      0
8303     //
8304 
8305     fault_ipr_subtype_ mod_fault = 0;
8306 
8307 #if !defined(EIS_SETUP)
8308     setupOperandDescriptor(cpup, 1, &mod_fault);
8309     setupOperandDescriptor(cpup, 2, &mod_fault);
8310 #endif
8311 
8312     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8313     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8314 
8315     L68_ (
8316       // L68 raises it immediately
8317       if (mod_fault)
8318           doFault (FAULT_IPR,
8319                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8320                    "Illegal modifier");
8321     )
8322 
8323     // Bits 1-4 and 10 MBZ
8324     if (IWB_IRODD & 0360200000000)
8325       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8326 
8327     DPS8M_ (
8328       // DPS8M raises it delayed
8329       if (mod_fault)
8330           doFault (FAULT_IPR,
8331                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8332                    "Illegal modifier");
8333     )
8334 
8335     e->ADDR1.cPos = (int) e->C1;
8336     e->ADDR2.cPos = (int) e->C2;
8337 
8338     e->ADDR1.bPos = (int) e->B1;
8339     e->ADDR2.bPos = (int) e->B2;
8340 
8341     // get new char/bit offsets
8342     int numWords1=0, numWords2=0;
8343 
8344     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8345     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8346     PNL (cpu.du.D1_PTR_W &= AMASK);
8347 #if defined(EIS_PTR)
8348     cpu.du.D1_PTR_W += (word18) numWords1;
8349     cpu.du.D1_PTR_W &= AMASK;
8350 #else
8351     e->ADDR1.address += (word18) numWords1;
8352 #endif
8353 
8354     sim_debug (DBG_TRACEEXT, & cpu_dev,
8355                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8356                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8357     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8358     sim_debug (DBG_TRACEEXT, & cpu_dev,
8359                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8360                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8361     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8362     PNL (cpu.du.D2_PTR_W &= AMASK);
8363 #if defined(EIS_PTR)
8364     cpu.du.D2_PTR_W += (word18) numWords1;
8365     cpu.du.D2_PTR_W &= AMASK;
8366 #else
8367     e->ADDR2.address += (word18) numWords2;
8368 #endif
8369 
8370     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8371     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8372 
8373     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8374     bool B5 = !! (BOLR & 8);
8375     bool B6 = !! (BOLR & 4);
8376     bool B7 = !! (BOLR & 2);
8377     bool B8 = !! (BOLR & 1);
8378 
8379     e->ADDR1.mode = eRWreadBit;
8380 
8381     CLR_I_TRUNC;     // assume N1 <= N2
8382 
8383     bool bR = false; // result bit
8384 
8385     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8386                  DU_CYCLE_FLEN_128;))
8387 
8388     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8389       {
8390         bool b1 = EISgetBitRWNR(cpup, &e->ADDR1, true);
8391 
8392         e->ADDR2.mode = eRWreadBit;
8393         bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8394 
8395         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8396 
8397         if (bR)
8398           cpu.du.Z = 0;
8399 
8400         // write out modified bit
8401         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8402         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8403         // if ADDR1 is on a word boundary, it might fault on the next loop,
8404         // so we flush the write in case.
8405         EISgetBitRWNR(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 0);
8406       }
8407 
8408     if (e->N1 < e->N2)
8409       {
8410         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8411           {
8412             bool b1 = F;
8413 
8414             e->ADDR2.mode = eRWreadBit;
8415             bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8416 
8417             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8418 
8419             if (bR)
8420               {
8421                 //CLR_I_ZERO;
8422                 cpu.du.Z = 0;
8423               }
8424 
8425             // write out modified bit
8426             e->ADDR2.bit = bR ? 1 : 0;
8427             e->ADDR2.mode = eRWwriteBit;
8428             // if ADDR1 is on a word boundary, it might fault on the next loop,
8429             // so we flush the write in case.
8430             EISgetBitRWNR(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 0);
8431           }
8432       }
8433 
8434     EISWriteCache (cpup, &e->ADDR2);
8435 
8436     cleanupOperandDescriptor (cpup, 1);
8437     cleanupOperandDescriptor (cpup, 2);
8438 
8439     SC_I_ZERO (cpu.du.Z);
8440     if (e->N1 > e->N2)
8441       {
8442         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8443         // processed and the truncation indicator is set ON.
8444         //
8445         // If T = 1 and the truncation indicator is set ON by execution of the
8446         // instruction, then a truncation (overflow) fault occurs.
8447 
8448         SET_I_TRUNC;
8449         if (T && tstOVFfault (cpup))
8450           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8451       }
8452     else
8453       {
8454         CLR_I_TRUNC;
8455       }
8456   }
8457 
8458 void sztl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8459   {
8460     // The execution of this instruction is identical to the Combine
8461     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8462     // not placed into C(Y-bit2)i-1.
8463 
8464     EISstruct * e = & cpu.currentEISinstruction;
8465 
8466     // For i = bits 1, 2, ..., minimum (N1,N2)
8467     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
8468     //   C(BOLR)m → C(Y-bit2)i-1
8469     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
8470     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
8471     //   C(BOLR)m → C(Y-bit2)i-1
8472     //
8473     // INDICATORS: (Indicators not listed are not affected)
8474     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8475     //     Truncation If N1 > N2, then ON; otherwise OFF
8476     //
8477     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8478     // processed and the truncation indicator is set ON.
8479     //
8480     // If T = 1 and the truncation indicator is set ON by execution of the
8481     // instruction, then a truncation (overflow) fault occurs.
8482     //
8483     // BOLR
8484     // If first operand    and    second operand    then result
8485     // bit is:                    bit is:           is from bit:
8486     //        0                          0                      5
8487     //        0                          1                      6
8488     //        1                          0                      7
8489     //        1                          1                      8
8490     //
8491     // The Boolean operations most commonly used are
8492     //                  BOLR Field Bits
8493     // Operation        5      6      7      8
8494     //
8495     // MOVE             0      0      1      1
8496     // AND              0      0      0      1
8497     // OR               0      1      1      1
8498     // NAND             1      1      1      0
8499     // EXCLUSIVE OR     0      1      1      0
8500     // Clear            0      0      0      0
8501     // Invert           1      1      0      0
8502     //
8503 
8504 // 0 0 0 0  Clear
8505 // 0 0 0 1  a AND b
8506 // 0 0 1 0  a AND !b
8507 // 0 0 1 1  a
8508 // 0 1 0 0  !a AND b
8509 // 0 1 0 1  b
8510 // 0 1 1 0  a XOR b
8511 // 0 1 1 1  a OR b
8512 // 1 0 0 0  !a AND !b     !(a OR b)
8513 // 1 0 0 1  a == b        !(a XOR b)
8514 // 1 0 1 0  !b
8515 // 1 0 1 1  !b OR A
8516 // 1 1 0 0  !a
8517 // 1 1 0 1  !b AND a
8518 // 1 1 1 0  a NAND b
8519 // 1 1 1 1  Set
8520 
8521     fault_ipr_subtype_ mod_fault = 0;
8522 
8523 #if !defined(EIS_SETUP)
8524     setupOperandDescriptor (cpup, 1, &mod_fault);
8525     setupOperandDescriptor (cpup, 2, &mod_fault);
8526 #endif
8527 
8528     parseBitstringOperandDescriptor (cpup, 1, &mod_fault);
8529     parseBitstringOperandDescriptor (cpup, 2, &mod_fault);
8530 
8531     L68_ (
8532       // L68 raises it immediately
8533       if (mod_fault)
8534           doFault (FAULT_IPR,
8535                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8536                    "Illegal modifier");
8537     )
8538 
8539     // Bits 1-4 and 10 MBZ
8540     if (IWB_IRODD & 0360200000000)
8541       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8542 
8543     DPS8M_ (
8544       // DPS8M raises it delayed
8545       if (mod_fault)
8546           doFault (FAULT_IPR,
8547                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8548                    "Illegal modifier");
8549     )
8550 
8551     e->ADDR1.cPos = (int) e->C1;
8552     e->ADDR2.cPos = (int) e->C2;
8553 
8554     e->ADDR1.bPos = (int) e->B1;
8555     e->ADDR2.bPos = (int) e->B2;
8556 
8557     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8558     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8559 
8560     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8561     bool B5 = !! (BOLR & 8);
8562     bool B6 = !! (BOLR & 4);
8563     bool B7 = !! (BOLR & 2);
8564     bool B8 = !! (BOLR & 1);
8565 
8566     e->ADDR1.mode = eRWreadBit;
8567     e->ADDR2.mode = eRWreadBit;
8568 
8569 #if !defined(EIS_PTR)
8570     sim_debug (DBG_TRACEEXT, & cpu_dev,
8571                "SZTL N1 %d N2 %d\n"
8572                "SZTL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8573                "SZTL BOLR %u%u%u%u\n"
8574                "SZTL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8575                "SZTL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8576                e -> N1, e -> N2,
8577                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8578                B5, B6, B7, B8,
8579                e -> addr [0].SNR, e -> addr [0].address,
8580                e -> addr [0].cPos, e -> addr [0].bPos,
8581                e -> addr [1].SNR, e -> addr [1].address,
8582                e -> addr [1].cPos, e -> addr [1].bPos);
8583 #endif
8584 
8585     bool bR = false; // result bit
8586 
8587     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8588                  DU_CYCLE_FLEN_128;))
8589 
8590     for( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY += 1)
8591     {
8592         bool b1 = EISgetBitRWN (cpup, & e->ADDR1, true);
8593         bool b2 = EISgetBitRWN (cpup, & e->ADDR2, true);
8594 
8595         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8596 
8597         if (bR)
8598           {
8599             //CLR_I_ZERO);
8600             cpu.du.Z = 0;
8601             break;
8602           }
8603       }
8604 
8605     if (e->N1 < e->N2)
8606       {
8607         for (; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8608           {
8609             bool b1 = F;
8610             bool b2 = EISgetBitRWN (cpup, & e->ADDR2, true);
8611 
8612             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8613 
8614             if (bR)
8615               {
8616                 //CLR_I_ZERO;
8617                 cpu.du.Z = 0;
8618                 break;
8619               }
8620           }
8621       }
8622 
8623     cleanupOperandDescriptor (cpup, 1);
8624     cleanupOperandDescriptor (cpup, 2);
8625 
8626     SC_I_ZERO (cpu.du.Z);
8627     if (e->N1 > e->N2)
8628       {
8629         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8630         // processed and the truncation indicator is set ON.
8631         //
8632         // If T = 1 and the truncation indicator is set ON by execution of the
8633         // instruction, then a truncation (overflow) fault occurs.
8634 
8635         SET_I_TRUNC;
8636         if (T && tstOVFfault (cpup))
8637           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8638       }
8639     else
8640       {
8641         CLR_I_TRUNC;
8642       }
8643   }
8644 
8645 void sztr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8646   {
8647     // The execution of this instruction is identical to the Combine
8648     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8649     // not placed into C(Y-bit2)i-1.
8650 
8651     EISstruct * e = & cpu.currentEISinstruction;
8652 
8653     // For i = bits 1, 2, ..., minimum (N1,N2)
8654     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8655     //   C(BOLR)m → C( Y-bit2)N2-i
8656     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8657     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8658     //    C(BOLR)m → C( Y-bit2)N2-i
8659     // INDICATORS: (Indicators not listed are not affected)
8660     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8661     //     Truncation If N1 > N2, then ON; otherwise OFF
8662     //
8663     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8664     // processed and the truncation indicator is set ON.
8665     //
8666     // If T = 1 and the truncation indicator is set ON by execution of the
8667     // instruction, then a truncation (overflow) fault occurs.
8668     //
8669     // BOLR
8670     // If first operand    and    second operand    then result
8671     // bit is:                    bit is:           is from bit:
8672     //        0                          0                      5
8673     //        0                          1                      6
8674     //        1                          0                      7
8675     //        1                          1                      8
8676     //
8677     // The Boolean operations most commonly used are
8678     //                  BOLR Field Bits
8679     // Operation        5      6      7      8
8680     //
8681     // MOVE             0      0      1      1
8682     // AND              0      0      0      1
8683     // OR               0      1      1      1
8684     // NAND             1      1      1      0
8685     // EXCLUSIVE OR     0      1      1      0
8686     // Clear            0      0      0      0
8687     // Invert           1      1      0      0
8688     //
8689 
8690     fault_ipr_subtype_ mod_fault = 0;
8691 
8692 #if !defined(EIS_SETUP)
8693     setupOperandDescriptor(cpup, 1, &mod_fault);
8694     setupOperandDescriptor(cpup, 2, &mod_fault);
8695 #endif
8696 
8697     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8698     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8699 
8700     L68_ (
8701       // L68 raises it immediately
8702       if (mod_fault)
8703           doFault (FAULT_IPR,
8704                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8705                    "Illegal modifier");
8706     )
8707 
8708     // Bits 1-4 and 10 MBZ
8709     if (IWB_IRODD & 0360200000000)
8710       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8711 
8712     DPS8M_ (
8713       // DPS8M raises it delayed
8714       if (mod_fault)
8715           doFault (FAULT_IPR,
8716                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8717                    "Illegal modifier");
8718     )
8719 
8720     e->ADDR1.cPos = (int) e->C1;
8721     e->ADDR2.cPos = (int) e->C2;
8722 
8723     e->ADDR1.bPos = (int) e->B1;
8724     e->ADDR2.bPos = (int) e->B2;
8725 
8726     // get new char/bit offsets
8727     int numWords1=0, numWords2=0;
8728 
8729     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8730     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8731     PNL (cpu.du.D1_PTR_W &= AMASK);
8732 #if defined(EIS_PTR)
8733     cpu.du.D1_PTR_W += (word18) numWords1;
8734     cpu.du.D1_PTR_W &= AMASK;
8735 #else
8736     e->ADDR1.address += (word18) numWords1;
8737 #endif
8738 
8739     sim_debug (DBG_TRACEEXT, & cpu_dev,
8740                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8741                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8742     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8743     sim_debug (DBG_TRACEEXT, & cpu_dev,
8744                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8745                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8746     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8747     PNL (cpu.du.D2_PTR_W &= AMASK);
8748 #if defined(EIS_PTR)
8749     cpu.du.D2_PTR_W += (word18) numWords1;
8750     cpu.du.D2_PTR_W &= AMASK;
8751 #else
8752     e->ADDR2.address += (word18) numWords2;
8753 #endif
8754 
8755     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8756     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8757 
8758     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8759     bool B5 = !! (BOLR & 8);
8760     bool B6 = !! (BOLR & 4);
8761     bool B7 = !! (BOLR & 2);
8762     bool B8 = !! (BOLR & 1);
8763 
8764     e->ADDR1.mode = eRWreadBit;
8765 
8766     CLR_I_TRUNC;     // assume N1 <= N2
8767 
8768     bool bR = false; // result bit
8769 
8770     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8771                  DU_CYCLE_FLEN_128;))
8772 
8773     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8774       {
8775         bool b1 = EISgetBitRWNR(cpup, &e->ADDR1, true);
8776 
8777         e->ADDR2.mode = eRWreadBit;
8778         bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8779 
8780         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8781 
8782         if (bR)
8783           {
8784             cpu.du.Z = 0;
8785             break;
8786           }
8787 
8788       }
8789 
8790     if (e->N1 < e->N2)
8791       {
8792         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8793           {
8794             bool b1 = F;
8795 
8796             e->ADDR2.mode = eRWreadBit;
8797             bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8798 
8799             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8800 
8801             if (bR)
8802             {
8803                 //CLR_I_ZERO;
8804                 cpu.du.Z = 0;
8805                 break;
8806             }
8807 
8808           }
8809       }
8810 
8811     cleanupOperandDescriptor (cpup, 1);
8812     cleanupOperandDescriptor (cpup, 2);
8813 
8814     SC_I_ZERO (cpu.du.Z);
8815     if (e->N1 > e->N2)
8816       {
8817         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8818         // processed and the truncation indicator is set ON.
8819         //
8820         // If T = 1 and the truncation indicator is set ON by execution of the
8821         // instruction, then a truncation (overflow) fault occurs.
8822 
8823         SET_I_TRUNC;
8824         if (T && tstOVFfault (cpup))
8825           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8826       }
8827     else
8828       {
8829         CLR_I_TRUNC;
8830       }
8831   }
8832 
8833 /*
8834  * CMPB - Compare Bit Strings
8835  */
8836 
8837 /*
8838  * get a bit from memory ....
8839  */
8840 // XXX this is terribly inefficient, but it'll do for now ......
8841 
8842 static bool EISgetBit(cpu_state_t * cpup, EISaddr *p, int *cpos, int *bpos)
     /* [previous][next][first][last][top][bottom][index][help] */
8843 {
8844 #if defined(EIS_PTR)
8845     long eisaddr_idx = EISADDR_IDX (p);
8846 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8847 #endif
8848 
8849     if (!p)
8850     {
8851         //lastAddress = -1;
8852         return 0;
8853     }
8854 
8855     if (*bpos > 8)      // bits 0-8
8856     {
8857         *bpos = 0;
8858         *cpos += 1;
8859         if (*cpos > 3)  // chars 0-3
8860         {
8861             *cpos = 0;
8862 #if defined(EIS_PTR)
8863             cpu.du.Dk_PTR_W[eisaddr_idx] += 1;
8864             cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8865 #else
8866             p->address += 1;
8867             p->address &= AMASK;
8868 #endif
8869         }
8870     }
8871 
8872     p->data = EISRead(cpup, p); // read data word from memory
8873 
8874     int charPosn = *cpos * 9;
8875     int bitPosn = charPosn + *bpos;
8876     bool b = getbits36_1 (p->data, (uint) bitPosn) != 0;
8877 
8878     *bpos += 1;
8879 
8880     return b;
8881 }
8882 
8883 void cmpb (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8884 {
8885     EISstruct * e = & cpu.currentEISinstruction;
8886 
8887     // For i = 1, 2, ..., minimum (N1,N2)
8888     //   C(Y-bit1)i-1 :: C(Y-bit2)i-1
8889     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
8890     //   C(FILL) :: C(Y-bit2)i-1
8891     // If N1 > N2, then for i = N2+l, N2+2, ..., N1
8892     //   C(Y-bit1)i-1 :: C(FILL)
8893     //
8894     // Indicators:
8895     //    Zero:  If C(Y-bit1)i = C(Y-bit2)i for all i, then ON; otherwise, OFF
8896     //    Carry: If C(Y-bit1)i < C(Y-bit2)i for any i, then OFF; otherwise ON
8897 
8898     fault_ipr_subtype_ mod_fault = 0;
8899 
8900 #if !defined(EIS_SETUP)
8901     setupOperandDescriptor(cpup, 1, &mod_fault);
8902     setupOperandDescriptor(cpup, 2, &mod_fault);
8903 #endif
8904 
8905     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8906     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8907 
8908     L68_ (
8909       // L68 raises it immediately
8910       if (mod_fault)
8911         {
8912           doFault (FAULT_IPR,
8913                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8914                    "Illegal modifier");
8915         }
8916     )
8917 
8918     // Bits 1-8 and 10 MBZ
8919     if (IWB_IRODD & 0377200000000)
8920       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpb 1-8,10 MBZ");
8921 
8922     DPS8M_ (
8923       // DPS8M raises it delayed
8924       if (mod_fault)
8925         {
8926           doFault (FAULT_IPR,
8927                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8928                    "Illegal modifier");
8929         }
8930     )
8931 
8932     int charPosn1 = (int) e->C1;
8933     int charPosn2 = (int) e->C2;
8934 
8935     int bitPosn1 = (int) e->B1;
8936     int bitPosn2 = (int) e->B2;
8937 
8938     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8939 
8940     SET_I_ZERO;  // assume all =
8941     SET_I_CARRY; // assume all >=
8942 
8943 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb N1 %d N2 %d\n", e -> N1, e -> N2);
8944 
8945 
8946 
8947 
8948 
8949 
8950 
8951 
8952 
8953 
8954 
8955 
8956 
8957 
8958 
8959 
8960 
8961     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8962       DU_CYCLE_FLEN_128;))
8963 
8964     uint i;
8965     for(i = 0 ; i < min(e->N1, e->N2) ; i += 1)
8966     {
8967         bool b1 = EISgetBit (cpup, &e->ADDR1, &charPosn1, &bitPosn1);
8968         bool b2 = EISgetBit (cpup, &e->ADDR2, &charPosn2, &bitPosn2);
8969 
8970 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(min(e->N1, e->N2)) i %d b1 %d b2 %d\n", i, b1, b2);
8971         if (b1 != b2)
8972         {
8973             CLR_I_ZERO;
8974             if (!b1 && b2)  // 0 < 1
8975                 CLR_I_CARRY;
8976 
8977             cleanupOperandDescriptor (cpup, 1);
8978             cleanupOperandDescriptor (cpup, 2);
8979 
8980             return;
8981         }
8982 
8983     }
8984     if (e->N1 < e->N2)
8985     {
8986         for(; i < e->N2 ; i += 1)
8987         {
8988             bool b1 = F;
8989             bool b2 = EISgetBit(cpup, &e->ADDR2, &charPosn2, &bitPosn2);
8990 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 < e->N2) i %d b1fill %d b2 %d\n", i, b1, b2);
8991 
8992             if (b1 != b2)
8993             {
8994                 CLR_I_ZERO;
8995                 if (!b1 && b2)  // 0 < 1
8996                     CLR_I_CARRY;
8997 
8998                 cleanupOperandDescriptor (cpup, 1);
8999                 cleanupOperandDescriptor (cpup, 2);
9000 
9001                 return;
9002             }
9003         }
9004     } else if (e->N1 > e->N2)
9005     {
9006         for(; i < e->N1 ; i += 1)
9007         {
9008             bool b1 = EISgetBit(cpup, &e->ADDR1, &charPosn1, &bitPosn1);
9009             bool b2 = F;
9010 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 > e->N2) i %d b1 %d b2fill %d\n", i, b1, b2);
9011 
9012             if (b1 != b2)
9013             {
9014                 CLR_I_ZERO;
9015                 if (!b1 && b2)  // 0 < 1
9016                     CLR_I_CARRY;
9017 
9018                 cleanupOperandDescriptor (cpup, 1);
9019                 cleanupOperandDescriptor (cpup, 2);
9020 
9021                 return;
9022             }
9023         }
9024     }
9025     cleanupOperandDescriptor (cpup, 1);
9026     cleanupOperandDescriptor (cpup, 2);
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 
9200 
9201 
9202 
9203 
9204 
9205 
9206 
9207 
9208 
9209 
9210 
9211 
9212 
9213 
9214 
9215 
9216 
9217 
9218 
9219 
9220 
9221 
9222 
9223 
9224 
9225 
9226 
9227 
9228 
9229 
9230 
9231 
9232 
9233 
9234 
9235 
9236 
9237 
9238 
9239 
9240 
9241 
9242 
9243 
9244 
9245 
9246 
9247 
9248 
9249 
9250 /*
9251  * determine sign of N*9-bit length word
9252  */
9253 static bool sign9n(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9254 {
9255     // sign bit of  9-bit is bit 8  (1 << 8)
9256     // sign bit of 18-bit is bit 17 (1 << 17)
9257     // .
9258     // .
9259     // .
9260     // sign bit of 72-bit is bit 71 (1 << 71)
9261 
9262     if (N < 1 || N > 8) // XXX largest int we'll play with is 72-bits? Makes sense
9263         return false;
9264 
9265 #if defined(NEED_128)
9266     word72 sgnmask = lshift_128 (construct_128 (0, 1), (uint) (N * 9 - 1));
9267     return isnonzero_128 (and_128 (sgnmask, n128));
9268 #else
9269     word72 sgnmask = (word72)1 << ((N * 9) - 1);
9270 
9271     return (bool)(sgnmask & n128);
9272 #endif /* if defined(NEED_128) */
9273 }
9274 
9275 /*
9276  * sign extend a N*9 length word to a (word72) 128-bit word
9277  */
9278 static word72s signExt9(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9279 {
9280     // ext mask for  9-bit = 037777777777777777777777777777777777777400  8 0's
9281     // ext mask for 18-bit = 037777777777777777777777777777777777400000 17 0's
9282     // ext mask for 36-bit = 037777777777777777777777777777400000000000 35 0's
9283     // etc...
9284 
9285     int bits = (N * 9) - 1;
9286     if (sign9n(n128, N))
9287     {
9288 #if defined(NEED_128)
9289         uint128 extBits = lshift_128 (construct_128 (MASK64, MASK64), (uint) bits);
9290         uint128 or = or_128 (n128, extBits);
9291         return cast_s128 (or);
9292 #else
9293         uint128 extBits = ((uint128)-1 << bits);
9294         return (word72s) (n128 | extBits);
9295 #endif /* if defined(NEED_128) */
9296     }
9297 #if defined(NEED_128)
9298     uint128 zeroBits = complement_128 (lshift_128 (construct_128 (MASK64, MASK64), (uint) bits));
9299     uint128 and = and_128 (n128, zeroBits);
9300     return cast_s128 (and);
9301 #else
9302     uint128 zeroBits = ~((uint128)-1 << bits);
9303     return (word72s) (n128 & zeroBits);
9304 #endif /* if defined(NEED_128) */
9305 }
9306 
9307 /*
9308  * load a 9*n bit integer into e->x ...
9309  */
9310 
9311 static void load9x(cpu_state_t * cpup, int n, EISaddr *addr, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
9312 {
9313     EISstruct * e = & cpu.currentEISinstruction;
9314 #if defined(NEED_128)
9315     word72 x = construct_128 (0, 0);
9316 #else
9317     word72 x = 0;
9318 #endif /* if defined(NEED_128) */
9319 #if defined(EIS_PTR)
9320     long eisaddr_idx = EISADDR_IDX (addr);
9321 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
9322 #endif
9323 
9324     word36 data = EISRead(cpup, addr);
9325 
9326     int m = n;
9327     while (m)
9328     {
9329 #if defined(NEED_128)
9330         x = lshift_128 (x, 9);
9331 #else
9332         x <<= 9;         // make room for next 9-bit byte
9333 #endif /* if defined(NEED_128) */
9334 
9335         if (pos > 3)        // overflows to next word?
9336         {   // yep....
9337             pos = 0;        // reset to 1st byte
9338 #if EIS_PTR
9339             cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;          // bump source to next address
9340 #else
9341             addr->address = (addr->address + 1) & AMASK;          // bump source to next address
9342 #endif
9343             data = EISRead(cpup, addr);    // read it from memory
9344         }
9345 
9346 #if defined(NEED_128)
9347         x = or_128 (x, construct_128 (0, GETBYTE (data, pos)));
9348 #else
9349         x |= GETBYTE(data, pos);   // fetch byte at position pos and 'or' it in
9350 #endif /* if defined(NEED_128) */
9351 
9352         pos += 1;           // onto next position
9353 
9354         m -= 1;             // decrement byte counter
9355     }
9356     e->x = signExt9(x, n);  // form proper 2's-complement integer
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 
9429 
9430 
9431 
9432 
9433 
9434 
9435 
9436 
9437 
9438 
9439 
9440 
9441 
9442 
9443 
9444 
9445 
9446 
9447 
9448 
9449 
9450 
9451 
9452 
9453 
9454 
9455 
9456 
9457 
9458 
9459 
9460 
9461 
9462 
9463 
9464 
9465 
9466 
9467 
9468 
9469 
9470 
9471 
9472 
9473 
9474 
9475 
9476 
9477 
9478 
9479 void btd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
9480 {
9481     EISstruct * e = & cpu.currentEISinstruction;
9482 
9483     // C(Y-char91) converted to decimal → C(Y-charn2)
9484     /*!
9485      * C(Y-char91) contains a twos complement binary integer aligned on 9-bit
9486      * character boundaries with length 0 < N1 <= 8.
9487      *
9488      * If TN2 and S2 specify a 4-bit signed number and P = 1, then if
9489      * C(Y-char91) is positive (bit 0 of C(Y-char91)0 = 0), then the 13(8) plus
9490      * sign character is moved to C(Y-charn2) as appropriate.
9491      *
9492      *   The scaling factor of C(Y-charn2), SF2, must be 0.
9493      *
9494      *   If N2 is not large enough to hold the digits generated by conversion
9495      *   of C(Y-char91) an overflow condition exists; the overflow indicator is
9496      *   set ON and an overflow fault occurs. This implies that an unsigned
9497      *   fixed-point receiving field has a minimum length of 1 character and a
9498      *   signed fixed- point field, 2 characters.
9499      *
9500      * If MFk.RL = 1, then Nk does not contain the operand length; instead; it
9501      * contains a register code for a register holding the operand length.
9502      *
9503      * If MFk.ID = 1, then the kth word following the instruction word does not
9504      * contain an operand descriptor; instead, it contains an indirect pointer
9505      * to the operand descriptor.
9506      *
9507      * C(Y-char91) and C(Y-charn2) may be overlapping strings; no check is made.
9508      *
9509      * Attempted conversion to a floating-point number (S2 = 0) or attempted
9510      * use of a scaling factor (SF2 ≠ 0) causes an illegal procedure fault.
9511      *
9512      * If N1 = 0 or N1 > 8 an illegal procedure fault occurs.
9513      *
9514      * Attempted execution with the xed instruction causes an illegal procedure fault.
9515      *
9516      * Attempted repetition with the rpt, rpd, or rpl instructions causes an illegal procedure fault.
9517      *
9518      */
9519 
9520     // C(string 1) -> C(string 2) (converted)
9521 
9522     // The two's complement binary integer starting at location YC1 is
9523     // converted into a signed string of decimal characters of data type TN2,
9524     // sign and decimal type S2 (S2 = 00 is illegal) and scale factor 0; and is
9525     // stored, right-justified, as a string of length L2 starting at location
9526     // YC2. If the string generated is longer than L2, the high-order excess is
9527     // truncated and the overflow indicator is set. If strings 1 and 2 are not
9528     // overlapped, the contents of string 1 remain unchanged. The length of
9529     // string 1 (L1) is given as the number of 9-bit segments that make up the
9530     // string. L1 is equal to or is less than 8. Thus, the binary string to be
9531     // converted can be 9, 18, 27, 36, 45, 54, 63, or 72 bits long. CN1
9532     // designates a 9-bit character boundary. If P=1, positive signed 4-bit
9533     // results are stored using octal 13 as the plus sign. If P=0, positive
9534     // signed 4-bit results are stored with octal 14 as the plus sign.
9535 
9536     fault_ipr_subtype_ mod_fault = 0;
9537 
9538 #if !defined(EIS_SETUP)
9539     setupOperandDescriptor(cpup, 1, &mod_fault);
9540     setupOperandDescriptor(cpup, 2, &mod_fault);
9541 #endif
9542 
9543     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
9544     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
9545 
9546     L68_ (
9547       // L68 raises it immediately
9548       if (mod_fault)
9549         {
9550           doFault (FAULT_IPR,
9551                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9552                    "Illegal modifier");
9553         }
9554     )
9555 
9556     // Bits 1-10 MBZ
9557     if (IWB_IRODD & 0377600000000)
9558       {
9559         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
9560         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "btd 0-8 MBZ");
9561       }
9562 
9563     // Bits 21-29 of OP1 MBZ
9564     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000077700)
9565       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op1 21-29 MBZ");
9566 
9567     // Bits 24-29 of OP2 MBZ
9568     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000007700)
9569       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 24-29 MBZ");
9570 
9571     if (e->S[1] == 0)
9572       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 S=0");
9573 
9574     DPS8M_ (
9575       // DPS8 raises it delayed
9576       if (mod_fault)
9577         {
9578           doFault (FAULT_IPR,
9579                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9580                    "Illegal modifier");
9581         }
9582     )
9583 
9584     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
9585 
9586     if (e->N1 == 0 || e->N1 > 8)
9587         doFault(FAULT_IPR, fst_ill_proc, "btd(1): N1 == 0 || N1 > 8");
9588 
9589     uint dstTN = e->TN2;    // type of chars in dst
9590     uint dstCN = e->CN2;    // starting at char pos CN
9591 
9592     int n2 = 0;
9593 
9594     switch(e->S2)
9595     {
9596         case CSLS:
9597         case CSTS:
9598             n2 = (int) e->N2 - 1; // 1 sign
9599             break;
9600 
9601         case CSNS:
9602             n2 = (int) e->N2;     // no sign
9603             break;          // no sign wysiwyg
9604     }
9605 
9606     sim_debug (DBG_CAC, & cpu_dev,
9607       "n2 %d\n",
9608       n2);
9609 
9610     if (n2 < 1)
9611         doFault (FAULT_IPR, fst_ill_proc, "btd adjusted n2<1");
9612 
9613     decContext set;
9614     decContextDefaultDPS8(&set);
9615     set.traps=0;
9616 
9617     load9x(cpup, (int) e->N1, &e->ADDR1, (int) e->CN1);
9618 
9619     // handle sign
9620     e->sign = 1;
9621 #if defined(NEED_128)
9622     word72 x = cast_128 (e->x);
9623     if (islt_s128 (e->x, construct_s128 (0, 0)))
9624       {
9625         e->sign = -1;
9626         x = and_128 (negate_128 (x), MASK72);
9627 
9628       }
9629 
9630     // convert to decimal string, workaround missing sprintf uint128
9631     char tmp[32];
9632     tmp[31] = 0;
9633     int i;
9634     for (i=30;i>=0;i--) {
9635         //tmp[i] = x%10 + '0';
9636         //x /= 10;
9637         uint16_t r;
9638         x = divide_128_16 (x, 10, & r);
9639         tmp[i] = (char) r + '0';
9640         if (iszero_128 (x))
9641             break;
9642     }
9643 #else
9644     word72 x = (word72)e->x;
9645     if (e->x < 0) {
9646         e->sign = -1;
9647         //x = (-x) & MASK72;
9648         // ubsan
9649         x = ((word72) (- (word72s) x)) & MASK72;
9650     }
9651 
9652     // convert to decimal string, workaround missing sprintf uint128
9653     char tmp[32];
9654     tmp[31] = 0;
9655     int i;
9656     for (i=30;i>=0;i--) {
9657         tmp[i] = x%10 + '0';
9658         x /= 10;
9659         if (x == 0)
9660             break;
9661     }
9662 #endif /* if defined(NEED_128) */
9663 
9664     decNumber _1;
9665     decNumber *op1 = decNumberFromString(&_1, tmp+i, &set);
9666     if (e->sign == -1)
9667         op1->bits |= DECNEG;
9668 
9669     bool Ovr = false, Trunc = false;
9670 
9671     uint8_t out [256];
9672     char * res = formatDecimal (out, &set, op1, n2, (int) e->S2, e->SF2, 0, &Ovr, &Trunc);
9673 
9674     // now write to memory in proper format.....
9675 
9676     //word18 dstAddr = e->dstAddr;
9677     int pos = (int) dstCN;
9678 
9679     // 1st, take care of any leading sign .......
9680     switch(e->S2)
9681     {
9682         case CSLS:  // fixed-point, leading sign
9683             switch(dstTN)
9684             {
9685                 case CTN4:
9686                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
9687                               //   then the 13(8) plus sign character is placed appropriately
9688                               //   if the result of the operation is positive.
9689                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9690                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 013);  // special +
9691                     else
9692                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9693                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 014);  // default +
9694                     break;
9695                 case CTN9:
9696                     EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9697                                (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9698                     break;
9699             }
9700             break;
9701 
9702         case CSTS:  // nuttin' to do here .....
9703         case CSNS:
9704             break;  // no sign wysiwyg
9705     }
9706 
9707     // 2nd, write the digits .....
9708     for(int i = 0 ; i < n2 ; i++)
9709         switch(dstTN)
9710         {
9711             case CTN4:
9712                 EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN, (word9) (res[i] - '0'));
9713                 break;
9714             case CTN9:
9715                 EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN, (word9) res[i]);
9716                 break;
9717         }
9718 
9719     // 3rd, take care of any trailing sign or exponent ...
9720     switch(e->S2)
9721     {
9722         case CSTS:  // write trailing sign ....
9723             switch(dstTN)
9724             {
9725                 case CTN4:
9726                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
9727                               //   then the 13(8) plus sign character is placed appropriately
9728                               //   if the result of the operation is positive.
9729                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9730                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  013);  // special +
9731                     else
9732                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9733                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  014);  // default +
9734                     break;
9735 
9736                 case CTN9:
9737                     EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9738                                (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9739                     break;
9740             }
9741             break;
9742 
9743         case CSLS:  // fixed point, leading sign - already done
9744         case CSNS:  // fixed point, unsigned - nuttin' needed to do
9745             break;
9746     }
9747 
9748     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));  // set negative indicator if op3 < 0
9749     SC_I_ZERO (decNumberIsZero(op1));     // set zero indicator if op3 == 0
9750 
9751     cleanupOperandDescriptor (cpup, 1);
9752     cleanupOperandDescriptor (cpup, 2);
9753 
9754     if (Ovr)
9755     {
9756         SET_I_OFLOW;
9757         if (tstOVFfault (cpup))
9758           doFault(FAULT_OFL, fst_zero, "btd overflow fault");
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 
9908 
9909 
9910 
9911 
9912 
9913 
9914 
9915 
9916 
9917 
9918 
9919 
9920 
9921 
9922 
9923 
9924 
9925 
9926 
9927 
9928 
9929 
9930 
9931 
9932 
9933 
9934 
9935 
9936 
9937 
9938 
9939 
9940 
9941 
9942 
9943 
9944 
9945 
9946 
9947 
9948 
9949 
9950 
9951 
9952 
9953 
9954 
9955 
9956 
9957 
9958 
9959 
9960 
9961 
9962 
9963 
9964 
9965 
9966 
9967 
9968 void dtb (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
9969 {
9970     EISstruct * e = & cpu.currentEISinstruction;
9971 
9972     fault_ipr_subtype_ mod_fault = 0;
9973 
9974 #if !defined(EIS_SETUP)
9975     setupOperandDescriptor(cpup, 1, &mod_fault);
9976     setupOperandDescriptor(cpup, 2, &mod_fault);
9977 #endif
9978 
9979     PNL (L68_ (DU_CYCLE_DGDB;))
9980 
9981     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
9982     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
9983 
9984     L68_ (
9985       // L68 raises it immediately
9986       if (mod_fault)
9987         {
9988           doFault (FAULT_IPR,
9989                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9990                    "Illegal modifier");
9991         }
9992     )
9993 
9994     // Bits 0 to 10 of the instruction Must Be Zero. So Say We ISOLTS.
9995     uint mbz = (uint) getbits36 (IWB_IRODD, 0, 11);
9996     if (mbz)
9997       {
9998         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dtb(): 0-10 MBZ");
9999       }
10000 
10001     // Bits 24-29 of OP1 MBZ
10002     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
10003       {
10004         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op1 24-29 MBZ");
10005       }
10006 
10007     // Bits 21-29 of OP2 MBZ
10008     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000077700)
10009       {
10010         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op2 21-29 MBZ");
10011        }
10012 
10013     // Attempted conversion of a floating-point number (S1 = 0) or attempted
10014     // use of a scaling factor (SF1 ≠ 0) causes an illegal procedure fault.
10015     if (e->S1 == 0 || e->SF1 != 0)
10016     {
10017         doFault(FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb():  S1=0 or SF1!=0");
10018     }
10019 
10020     DPS8M_ (
10021       // DPS8M raises it delayed
10022       if (mod_fault)
10023         {
10024           doFault (FAULT_IPR,
10025                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10026                    "Illegal modifier");
10027         }
10028     )
10029 
10030     // If N2 = 0 or N2 > 8 an illegal procedure fault occurs.
10031     if (e->N2 == 0 || e->N2 > 8)
10032     {
10033         doFault(FAULT_IPR, fst_ill_proc, "dtb():  N2 = 0 or N2 > 8 etc.");
10034     }
10035 
10036     int n1 = 0;
10037 
10038     /*
10039      * Here we need to distinguish between 4 type of numbers.
10040      *
10041      * CSFL - Floating-point, leading sign
10042      * CSLS - Scaled fixed-point, leading sign
10043      * CSTS - Scaled fixed-point, trailing sign
10044      * CSNS - Scaled fixed-point, unsigned
10045      */
10046 
10047     // determine precision
10048     switch(e->S1)
10049     {
10050         case CSLS:
10051         case CSTS:
10052             n1 = (int) e->N1 - 1; // only 1 sign
10053             break;
10054 
10055         case CSNS:
10056             n1 = (int) e->N1;     // no sign
10057             break;  // no sign wysiwyg
10058     }
10059     // RJ78: An Illegal Procedure fault occurs if:
10060     // N1 is not large enough to specify the number of characters required for the
10061     // specified sign and/or exponent, plus at least one digit.
10062 
10063     if (n1 < 1)
10064         doFault (FAULT_IPR, fst_ill_proc, "dtb adjusted n1<1");
10065 
10066     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10067 
10068     // prepare output mask
10069 #if defined(NEED_128)
10070     word72 msk = subtract_128 (lshift_128 (construct_128 (0, 1), (9*e->N2-1)),construct_128 (0, 1));
10071 #else
10072     word72 msk = ((word72)1<<(9*e->N2-1))-1; // excluding sign
10073 #endif /* if defined(NEED_128) */
10074 
10075 
10076 
10077 
10078 
10079 
10080 
10081 
10082 
10083 
10084 
10085 
10086 
10087 
10088     // input is unscaled fixed point, so just get the digits
10089     bool Ovr = false;
10090 #if defined(NEED_128)
10091     word72 x = construct_128 (0, 0);
10092     for (int i = 0; i < n1; i++) {
10093         //x *= 10;
10094         x = multiply_128 (x, construct_128 (0, 10));
10095         //x += e->inBuffer[i];
10096         x = add_128 (x, construct_128 (0, (uint) e->inBuffer[i]));
10097         //Ovr |= x>msk?1:0;
10098         Ovr |= isgt_128 (x, msk) ? 1 : 0;
10099         //x &= msk; // multiplication and addition mod msk+1
10100         x = and_128 (x, msk); // multiplication and addition mod msk+1
10101     }
10102     if (e->sign == -1)
10103         //x = -x; // no need to mask it
10104         x = negate_128 (x); // no need to mask it
10105 
10106 #else
10107     word72 x = 0;
10108     for (int i = 0; i < n1; i++) {
10109         x *= 10;
10110         x += e->inBuffer[i];
10111         //sim_printf("%d %012"PRIo64" %012"PRIo64"\n",e->inBuffer[i],(word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10112         Ovr |= x>msk?1:0;
10113         x &= msk; // multiplication and addition mod msk+1
10114     }
10115     if (e->sign == -1)
10116         //x = -x; // no need to mask it
10117         // ubsan
10118         x = (word72) (- (word72s) x); // no need to mask it
10119 
10120     //sim_printf ("dtb out %012"PRIo64" %012"PRIo64"\n", (word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10121 #endif /* if defined(NEED_128) */
10122     int pos = (int)e->CN2;
10123 
10124     // now write to memory in proper format.....
10125 
10126     int shift = 9*((int)e->N2-1);
10127     for(int i = 0; i < (int)e->N2; i++) {
10128 #if defined(NEED_128)
10129         EISwrite9(cpup, &e->ADDR2, &pos, (word9) rshift_128 (x, (uint) shift).l & 0777);
10130 #else
10131         EISwrite9(cpup, &e->ADDR2, &pos, (word9) (x >> shift )& 0777);
10132 #endif /* if defined(NEED_128) */
10133         shift -= 9;
10134     }
10135 
10136     SC_I_NEG (e->sign == -1);  // set negative indicator
10137 #if defined(NEED_128)
10138     SC_I_ZERO (iszero_128 (x)); // set zero indicator
10139 #else
10140     SC_I_ZERO (x==0);     // set zero indicator
10141 #endif /* if defined(NEED_128) */
10142 
10143     cleanupOperandDescriptor (cpup, 1);
10144     cleanupOperandDescriptor (cpup, 2);
10145 
10146     if (Ovr)
10147     {
10148         SET_I_OFLOW;
10149         if (tstOVFfault (cpup))
10150           doFault(FAULT_OFL, fst_zero, "dtb overflow fault");
10151     }
10152 }
10153 
10154 /*
10155  * decimal EIS instructions ...
10156  */
10157 
10158 #define ASC(x)  ((x) + '0')
10159 
10160 /*
10161  * ad2d - Add Using Two Decimal Operands
10162  */
10163 
10164 void ad2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10165 {
10166     EISstruct * e = & cpu.currentEISinstruction;
10167 
10168     fault_ipr_subtype_ mod_fault = 0;
10169 
10170 #if !defined(EIS_SETUP)
10171     setupOperandDescriptor(cpup, 1, &mod_fault);
10172     setupOperandDescriptor(cpup, 2, &mod_fault);
10173     setupOperandDescriptorCache(cpup,3);
10174 #endif
10175 
10176     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10177     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10178 
10179     L68_ (
10180       // L68 raises it immediately
10181       if (mod_fault)
10182         {
10183           doFault (FAULT_IPR,
10184                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10185                    "Illegal modifier");
10186         }
10187     )
10188 
10189     // Bits 1-8 MBZ
10190     if (IWB_IRODD & 0377000000000)
10191       doFault (FAULT_IPR, fst_ill_op, "ad2d 1-8 MBZ");
10192 
10193     DPS8M_ (
10194       // DPS8M raises it delayed
10195       if (mod_fault)
10196         {
10197           doFault (FAULT_IPR,
10198                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10199                    "Illegal modifier");
10200         }
10201     )
10202 
10203     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10204     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10205     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10206 
10207     PNL (L68_ (if (R)
10208       DU_CYCLE_FRND;))
10209 
10210     uint srcTN = e->TN1;    // type of chars in src
10211 
10212     uint dstTN = e->TN2;    // type of chars in dst
10213     uint dstCN = e->CN2;    // starting at char pos CN
10214 
10215     e->ADDR3 = e->ADDR2;
10216 
10217     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10218 
10219     /*
10220      * Here we need to distinguish between 4 type of numbers.
10221      *
10222      * CSFL - Floating-point, leading sign
10223      * CSLS - Scaled fixed-point, leading sign
10224      * CSTS - Scaled fixed-point, trailing sign
10225      * CSNS - Scaled fixed-point, unsigned
10226      */
10227 
10228     // determine precision
10229     switch(e->S1)
10230     {
10231         case CSFL:
10232             n1 = (int) e->N1 - 1; // need to account for the - sign
10233             if (srcTN == CTN4)
10234                 n1 -= 2;    // 2 4-bit digits exponent
10235             else
10236                 n1 -= 1;    // 1 9-bit digit exponent
10237             sc1 = 0;        // no scaling factor
10238             break;
10239 
10240         case CSLS:
10241         case CSTS:
10242             n1 = (int) e->N1 - 1; // only 1 sign
10243             sc1 = -e->SF1;
10244             break;
10245 
10246         case CSNS:
10247             n1 = (int) e->N1;     // no sign
10248             sc1 = -e->SF1;
10249             break;  // no sign wysiwyg
10250     }
10251 
10252     if (n1 < 1)
10253         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n1<1");
10254 
10255     switch(e->S2)
10256     {
10257         case CSFL:
10258             n2 = (int) e->N2 - 1; // need to account for the sign
10259             if (e->TN2 == CTN4)
10260                 n2 -= 2;    // 2 4-bit digit exponent
10261             else
10262                 n2 -= 1;    // 1 9-bit digit exponent
10263             sc2 = 0;        // no scaling factor
10264             break;
10265 
10266         case CSLS:
10267         case CSTS:
10268             n2 = (int) e->N2 - 1; // 1 sign
10269             sc2 = -e->SF2;
10270             break;
10271 
10272         case CSNS:
10273             n2 = (int) e->N2;     // no sign
10274             sc2 = -e->SF2;
10275             break;  // no sign wysiwyg
10276     }
10277 
10278     if (n2 < 1)
10279         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n2<1");
10280 
10281     decContext set;
10282     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10283     decContextDefaultDPS8(&set);
10284 
10285     set.traps=0;
10286 
10287     decNumber _1, _2, _3;
10288 
10289     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10290 
10291     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10292     if (e->sign == -1)
10293         op1->bits |= DECNEG;
10294     if (e->S1 == CSFL)
10295         op1->exponent = e->exponent;
10296 
10297     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
10298 
10299     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10300     if (e->sign == -1)
10301         op2->bits |= DECNEG;
10302     if (e->S2 == CSFL)
10303         op2->exponent = e->exponent;
10304 
10305     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10306 
10307     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
10308     bool iOvr = 0;
10309     if (op3->digits > 63) {
10310         uint8_t pr[256];
10311         // if sf<=0, trailing zeroes can't be shifted out
10312         // if sf> 0, (some of) trailing zeroes can be shifted out
10313         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10314 
10315         int ctz = 0;
10316         if (sf>0) {     // optimize: we don't care when sf>0
10317             decNumberGetBCD(op3,pr);
10318             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10319                  ctz ++;
10320         }
10321 
10322         if (op3->digits - min(max(sf,0),ctz) > 63) {
10323             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10324             int safe = set.digits;
10325             decNumber tmp;
10326 
10327             // discard MS digits
10328             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10329             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10330             decNumberPlus(&tmp, op3, &set);
10331             set.digits = safe;
10332 
10333             decNumberSubtract(op3, op3, &tmp, &set);
10334 
10335             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10336 
10337             decContextSetRounding(&set, safeR);
10338             iOvr = 1;
10339         }
10340     }
10341 
10342     bool Ovr = false, EOvr = false, Trunc = false;
10343 
10344     uint8_t out [256];
10345     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
10346 
10347     Ovr |= iOvr;
10348 
10349     if (decNumberIsZero(op3))
10350         op3->exponent = 127;
10351 
10352     //(void)printf("%s\r\n", res);
10353 
10354     // now write to memory in proper format.....
10355 
10356     //word18 dstAddr = e->dstAddr;
10357     int pos = (int) dstCN;
10358 
10359     // 1st, take care of any leading sign .......
10360     switch(e->S2)
10361     {
10362         case CSFL:  // floating-point, leading sign.
10363         case CSLS:  // fixed-point, leading sign
10364             switch(dstTN)
10365             {
10366                 case CTN4:
10367                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10368                               //   then the 13(8) plus sign character is placed appropriately
10369                               //   if the result of the operation is positive.
10370                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10371                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10372                     else
10373                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10374                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10375                     break;
10376                 case CTN9:
10377                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10378                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10379                     break;
10380             }
10381             break;
10382 
10383         case CSTS:  // nuttin' to do here .....
10384         case CSNS:
10385             break;  // no sign wysiwyg
10386     }
10387 
10388     // 2nd, write the digits .....
10389     for(int j = 0 ; j < n2 ; j++)
10390         switch(dstTN)
10391         {
10392             case CTN4:
10393                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[j] - '0'));
10394                 break;
10395             case CTN9:
10396                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[j]);
10397                 break;
10398         }
10399 
10400     // 3rd, take care of any trailing sign or exponent ...
10401     switch(e->S2)
10402     {
10403         case CSTS:  // write trailing sign ....
10404             switch(dstTN)
10405             {
10406                 case CTN4:
10407                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10408                               //   then the 13(8) plus sign character is placed appropriately
10409                               //   if the result of the operation is positive.
10410                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10411                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10412                     else
10413                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10414                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10415                     break;
10416                 case CTN9:
10417                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10418                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10419                     break;
10420             }
10421             break;
10422 
10423         case CSFL:  // floating-point, leading sign.
10424             // write the exponent
10425             switch(dstTN)
10426             {
10427                 case CTN4:
10428                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10429                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10430                     break;
10431                 case CTN9:
10432                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10433                     break;
10434             }
10435             break;
10436 
10437         case CSLS:  // fixed point, leading sign - already done
10438         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10439             break;
10440     }
10441 
10442     // set flags, etc ...
10443     if (e->S2 == CSFL)
10444     {
10445         if (op3->exponent > 127)
10446         {
10447             SET_I_EOFL;
10448             EOvr = true;
10449         }
10450         if (op3->exponent < -128)
10451         {
10452             SET_I_EUFL;
10453             EOvr = true;
10454         }
10455     }
10456 
10457     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10458     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10459 
10460     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10461 
10462     cleanupOperandDescriptor (cpup, 1);
10463     cleanupOperandDescriptor (cpup, 2);
10464     cleanupOperandDescriptor (cpup, 3);
10465 
10466     if (TST_I_TRUNC && T && tstOVFfault (cpup))
10467       doFault(FAULT_OFL, fst_zero, "ad2d truncation(overflow) fault");
10468     if (EOvr && tstOVFfault (cpup))
10469         doFault(FAULT_OFL, fst_zero, "ad2d over/underflow fault");
10470     if (Ovr)
10471     {
10472         SET_I_OFLOW;
10473         if (tstOVFfault (cpup))
10474           doFault(FAULT_OFL, fst_zero, "ad2d overflow fault");
10475     }
10476 }
10477 
10478 
10479 
10480 
10481 
10482 
10483 
10484 
10485 
10486 
10487 
10488 
10489 
10490 
10491 
10492 
10493 
10494 
10495 
10496 
10497 
10498 
10499 
10500 
10501 
10502 
10503 
10504 
10505 
10506 
10507 
10508 
10509 
10510 
10511 
10512 
10513 
10514 
10515 
10516 
10517 
10518 
10519 /*
10520  * ad3d - Add Using Three Decimal Operands
10521  */
10522 
10523 void ad3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10524 {
10525     EISstruct * e = & cpu.currentEISinstruction;
10526 
10527     fault_ipr_subtype_ mod_fault = 0;
10528 
10529 #if !defined(EIS_SETUP)
10530     setupOperandDescriptor(cpup, 1, &mod_fault);
10531     setupOperandDescriptor(cpup, 2, &mod_fault);
10532     setupOperandDescriptor(cpup, 3, &mod_fault);
10533 #endif
10534 
10535     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10536     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10537     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
10538 
10539     L68_ (
10540       // L68 raises it immediately
10541       if (mod_fault)
10542         {
10543           doFault (FAULT_IPR,
10544                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10545                    "Illegal modifier");
10546         }
10547     )
10548 
10549     // Bit 1 MBZ
10550     if (IWB_IRODD & 0200000000000)
10551       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "ad3d(): 1 MBZ");
10552 
10553     DPS8M_ (
10554       // DPS8M raises it delayed
10555       if (mod_fault)
10556         {
10557           doFault (FAULT_IPR,
10558                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10559                    "Illegal modifier");
10560         }
10561     )
10562 
10563     // initialize mop flags. Probably best done elsewhere.
10564     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10565     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10566     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10567 
10568     PNL (L68_ (if (R)
10569       DU_CYCLE_FRND;))
10570 
10571     uint srcTN = e->TN1;    // type of chars in src
10572 
10573     uint dstTN = e->TN3;    // type of chars in dst
10574     uint dstCN = e->CN3;    // starting at char pos CN
10575 
10576     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
10577 
10578     /*
10579      * Here we need to distinguish between 4 type of numbers.
10580      *
10581      * CSFL - Floating-point, leading sign
10582      * CSLS - Scaled fixed-point, leading sign
10583      * CSTS - Scaled fixed-point, trailing sign
10584      * CSNS - Scaled fixed-point, unsigned
10585      */
10586 
10587     // determine precision
10588     switch(e->S1)
10589     {
10590         case CSFL:
10591             n1 = (int) e->N1 - 1; // need to account for the - sign
10592             if (srcTN == CTN4)
10593                 n1 -= 2;    // 2 4-bit digits exponent
10594             else
10595                 n1 -= 1;    // 1 9-bit digit exponent
10596             sc1 = 0;        // no scaling factor
10597             break;
10598 
10599         case CSLS:
10600         case CSTS:
10601             n1 = (int) e->N1 - 1; // only 1 sign
10602             sc1 = -e->SF1;
10603             break;
10604 
10605         case CSNS:
10606             n1 = (int) e->N1;     // no sign
10607             sc1 = -e->SF1;
10608             break;  // no sign wysiwyg
10609     }
10610 
10611     if (n1 < 1)
10612         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n1<1");
10613 
10614     switch(e->S2)
10615     {
10616         case CSFL:
10617             n2 = (int) e->N2 - 1; // need to account for the sign
10618             if (e->TN2 == CTN4)
10619                 n2 -= 2;    // 2 4-bit digit exponent
10620             else
10621                 n2 -= 1;    // 1 9-bit digit exponent
10622             sc2 = 0;        // no scaling factor
10623             break;
10624 
10625         case CSLS:
10626         case CSTS:
10627             n2 = (int) e->N2 - 1; // 1 sign
10628             sc2 = -e->SF2;
10629             break;
10630 
10631         case CSNS:
10632             n2 = (int) e->N2;     // no sign
10633             sc2 = -e->SF2;
10634             break;  // no sign wysiwyg
10635     }
10636 
10637     if (n2 < 1)
10638         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n2<1");
10639 
10640     switch(e->S3)
10641     {
10642         case CSFL:
10643             n3 = (int) e->N3 - 1; // need to account for the sign
10644             if (dstTN == CTN4)
10645                 n3 -= 2;    // 2 4-bit digit exponent
10646             else
10647                 n3 -= 1;    // 1 9-bit digit exponent
10648             break;
10649 
10650         case CSLS:
10651         case CSTS:
10652             n3 = (int) e->N3 - 1; // 1 sign
10653             break;
10654 
10655         case CSNS:
10656             n3 = (int) e->N3;     // no sign
10657             break;  // no sign wysiwyg
10658     }
10659 
10660     if (n3 < 1)
10661         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n3<1");
10662 
10663     decContext set;
10664     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10665     decContextDefaultDPS8(&set);
10666     set.traps=0;
10667 
10668     decNumber _1, _2, _3;
10669 
10670     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10671 
10672     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10673     if (e->sign == -1)
10674         op1->bits |= DECNEG;
10675     if (e->S1 == CSFL)
10676         op1->exponent = e->exponent;
10677 
10678     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
10679 
10680     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10681     if (e->sign == -1)
10682         op2->bits |= DECNEG;
10683     if (e->S2 == CSFL)
10684         op2->exponent = e->exponent;
10685 
10686     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10687 
10688     // RJ78: significant digits in the result may be lost if:
10689     // The difference between the scaling factors (exponents) of the source
10690     // operands is large enough to cause the expected length of the intermediate
10691     // result to exceed 63 digits after decimal point alignment of source operands, followed by addition.
10692     // ISOLTS 846 07c, 10a, 11b internal register overflow
10693     // trailing zeros are not counted towards the limit
10694 
10695     // XXX it is not clear which digits are lost, but I suppose it should be the most significant.
10696     // ISOLTS doesn't check for this.
10697 
10698     // XXX the algorithm should be similar/the same as dv3d NQ? It is to some extent already...
10699     bool iOvr = 0;
10700     if (op3->digits > 63) {
10701         uint8_t pr[256];
10702         // if sf<=0, trailing zeroes can't be shifted out
10703         // if sf> 0, (some of) trailing zeroes can be shifted out
10704         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10705 
10706         int ctz = 0;
10707         if (sf>0) {     // optimize: we don't care when sf>0
10708             decNumberGetBCD(op3,pr);
10709             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10710                  ctz ++;
10711         }
10712 
10713         if (op3->digits - min(max(sf,0),ctz) > 63) {
10714             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10715             int safe = set.digits;
10716             decNumber tmp;
10717 
10718             // discard MS digits
10719             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10720             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10721             decNumberPlus(&tmp, op3, &set);
10722             set.digits = safe;
10723 
10724             decNumberSubtract(op3, op3, &tmp, &set);
10725 
10726             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10727 
10728             decContextSetRounding(&set, safeR);
10729             iOvr = 1;
10730         }
10731     }
10732 
10733     bool Ovr = false, EOvr = false, Trunc = false;
10734 
10735     uint8_t out [256];
10736     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
10737 
10738     Ovr |= iOvr;
10739 
10740     if (decNumberIsZero(op3))
10741         op3->exponent = 127;
10742 
10743     //(void)printf("%s\r\n", res);
10744 
10745     // now write to memory in proper format.....
10746 
10747     //word18 dstAddr = e->dstAddr;
10748     int pos = (int) dstCN;
10749 
10750     // 1st, take care of any leading sign .......
10751     switch(e->S3)
10752     {
10753         case CSFL:  // floating-point, leading sign.
10754         case CSLS:  // fixed-point, leading sign
10755             switch(dstTN)
10756             {
10757             case CTN4:
10758                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10759                           //   then the 13(8) plus sign character is placed appropriately
10760                           //   if the result of the operation is positive.
10761                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10762                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10763                 else
10764                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10765                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10766                 break;
10767             case CTN9:
10768                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10769                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10770                 break;
10771             }
10772             break;
10773 
10774         case CSTS:  // nuttin' to do here .....
10775         case CSNS:
10776             break;  // no sign wysiwyg
10777     }
10778 
10779     // 2nd, write the digits .....
10780     for(int i = 0 ; i < n3 ; i++)
10781         switch(dstTN)
10782         {
10783         case CTN4:
10784             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
10785             break;
10786         case CTN9:
10787             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
10788             break;
10789         }
10790 
10791     // 3rd, take care of any trailing sign or exponent ...
10792     switch(e->S3)
10793     {
10794         case CSTS:  // write trailing sign ....
10795             switch(dstTN)
10796             {
10797             case CTN4:
10798                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10799                           //   then the 13(8) plus sign character is placed appropriately
10800                           //   if the result of the operation is positive.
10801                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10802                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10803                 else
10804                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10805                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10806                 break;
10807             case CTN9:
10808                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10809                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10810                 break;
10811             }
10812             break;
10813 
10814         case CSFL:  // floating-point, leading sign.
10815             // write the exponent
10816             switch(dstTN)
10817             {
10818             case CTN4:
10819                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10820                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10821 
10822                     break;
10823             case CTN9:
10824                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10825                 break;
10826             }
10827             break;
10828 
10829         case CSLS:  // fixed point, leading sign - already done
10830         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10831             break;
10832     }
10833 
10834     // set flags, etc ...
10835     if (e->S3 == CSFL)
10836     {
10837         if (op3->exponent > 127)
10838         {
10839             SET_I_EOFL;
10840             EOvr = true;
10841         }
10842         if (op3->exponent < -128)
10843         {
10844             SET_I_EUFL;
10845             EOvr = true;
10846         }
10847     }
10848 
10849     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10850     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10851 
10852     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10853 
10854     cleanupOperandDescriptor (cpup, 1);
10855     cleanupOperandDescriptor (cpup, 2);
10856     cleanupOperandDescriptor (cpup, 3);
10857 
10858     if (TST_I_TRUNC && T && tstOVFfault (cpup))
10859       doFault(FAULT_OFL, fst_zero, "ad3d truncation(overflow) fault");
10860     if (EOvr && tstOVFfault (cpup))
10861         doFault(FAULT_OFL, fst_zero, "ad3d over/underflow fault");
10862     if (Ovr)
10863     {
10864         SET_I_OFLOW;
10865         if (tstOVFfault (cpup))
10866           doFault(FAULT_OFL, fst_zero, "ad3d overflow fault");
10867     }
10868 }
10869 
10870 /*
10871  * sb2d - Subtract Using Two Decimal Operands
10872  */
10873 
10874 void sb2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10875 {
10876     EISstruct * e = & cpu.currentEISinstruction;
10877 
10878     fault_ipr_subtype_ mod_fault = 0;
10879 
10880 #if !defined(EIS_SETUP)
10881     setupOperandDescriptor(cpup, 1, &mod_fault);
10882     setupOperandDescriptor(cpup, 2, &mod_fault);
10883     setupOperandDescriptorCache(cpup,3);
10884 #endif
10885 
10886     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10887     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10888 
10889     L68_ (
10890       // L68 raises it immediately
10891       if (mod_fault)
10892         {
10893           doFault (FAULT_IPR,
10894                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10895                    "Illegal modifier");
10896         }
10897     )
10898 
10899     // Bits 1-8 MBZ
10900     if (IWB_IRODD & 0377000000000)
10901       {
10902         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
10903         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb2d 0-8 MBZ");
10904       }
10905 
10906     DPS8M_ (
10907       // DPS8M raises it delayed
10908       if (mod_fault)
10909         {
10910           doFault (FAULT_IPR,
10911                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10912                    "Illegal modifier");
10913         }
10914     )
10915 
10916     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10917     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10918     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10919 
10920     PNL (L68_ (if (R)
10921       DU_CYCLE_FRND;))
10922 
10923     uint srcTN = e->TN1;    // type of chars in src
10924 
10925     uint dstTN = e->TN2;    // type of chars in dst
10926     uint dstCN = e->CN2;    // starting at char pos CN
10927 
10928     e->ADDR3 = e->ADDR2;
10929 
10930     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10931 
10932     /*
10933      * Here we need to distinguish between 4 type of numbers.
10934      *
10935      * CSFL - Floating-point, leading sign
10936      * CSLS - Scaled fixed-point, leading sign
10937      * CSTS - Scaled fixed-point, trailing sign
10938      * CSNS - Scaled fixed-point, unsigned
10939      */
10940 
10941     // determine precision
10942     switch(e->S1)
10943     {
10944         case CSFL:
10945             n1 = (int) e->N1 - 1; // need to account for the - sign
10946             if (srcTN == CTN4)
10947                 n1 -= 2;    // 2 4-bit digits exponent
10948             else
10949                 n1 -= 1;    // 1 9-bit digit exponent
10950             sc1 = 0;        // no scaling factor
10951             break;
10952 
10953         case CSLS:
10954         case CSTS:
10955             n1 = (int) e->N1 - 1; // only 1 sign
10956             sc1 = -e->SF1;
10957             break;
10958 
10959         case CSNS:
10960             n1 = (int) e->N1;     // no sign
10961             sc1 = -e->SF1;
10962             break;  // no sign wysiwyg
10963     }
10964 
10965     if (n1 < 1)
10966         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n1<1");
10967 
10968     switch(e->S2)
10969     {
10970         case CSFL:
10971             n2 = (int) e->N2 - 1; // need to account for the sign
10972             if (e->TN2 == CTN4)
10973                 n2 -= 2;    // 2 4-bit digit exponent
10974             else
10975                 n2 -= 1;    // 1 9-bit digit exponent
10976             sc2 = 0;        // no scaling factor
10977             break;
10978 
10979         case CSLS:
10980         case CSTS:
10981             n2 = (int) e->N2 - 1; // 1 sign
10982             sc2 = -e->SF2;
10983             break;
10984 
10985         case CSNS:
10986             n2 = (int) e->N2;     // no sign
10987             sc2 = -e->SF2;
10988             break;  // no sign wysiwyg
10989     }
10990 
10991     if (n2 < 1)
10992         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n2<1");
10993 
10994     decContext set;
10995     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10996     decContextDefaultDPS8(&set);
10997     set.traps=0;
10998 
10999     decNumber _1, _2, _3;
11000 
11001     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11002 
11003     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11004     if (e->sign == -1)
11005         op1->bits |= DECNEG;
11006     if (e->S1 == CSFL)
11007         op1->exponent = e->exponent;
11008 
11009     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11010 
11011     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11012     if (e->sign == -1)
11013         op2->bits |= DECNEG;
11014     if (e->S2 == CSFL)
11015         op2->exponent = e->exponent;
11016 
11017     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11018 
11019     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11020     bool iOvr = 0;
11021     if (op3->digits > 63) {
11022         uint8_t pr[256];
11023         // if sf<=0, trailing zeroes can't be shifted out
11024         // if sf> 0, (some of) trailing zeroes can be shifted out
11025         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11026 
11027         int ctz = 0;
11028         if (sf>0) {     // optimize: we don't care when sf>0
11029             decNumberGetBCD(op3,pr);
11030             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11031                  ctz ++;
11032         }
11033 
11034         if (op3->digits - min(max(sf,0),ctz) > 63) {
11035             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11036             int safe = set.digits;
11037             decNumber tmp;
11038 
11039             // discard MS digits
11040             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11041             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11042             decNumberPlus(&tmp, op3, &set);
11043             set.digits = safe;
11044 
11045             decNumberSubtract(op3, op3, &tmp, &set);
11046 
11047             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
11048 
11049             decContextSetRounding(&set, safeR);
11050             iOvr = 1;
11051         }
11052     }
11053 
11054     bool Ovr = false, EOvr = false, Trunc = false;
11055 
11056     uint8_t out [256];
11057     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11058 
11059     Ovr |= iOvr;
11060 
11061     if (decNumberIsZero(op3))
11062         op3->exponent = 127;
11063 
11064     //(void)printf("%s\r\n", res);
11065 
11066     // now write to memory in proper format.....
11067 
11068     //word18 dstAddr = e->dstAddr;
11069     int pos = (int) dstCN;
11070 
11071     // 1st, take care of any leading sign .......
11072     switch(e->S2)
11073     {
11074         case CSFL:  // floating-point, leading sign.
11075         case CSLS:  // fixed-point, leading sign
11076             switch(dstTN)
11077             {
11078                 case CTN4:
11079                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11080                               //   then the 13(8) plus sign character is placed appropriately
11081                               //   if the result of the operation is positive.
11082                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11083                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11084                     else
11085                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11086                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11087                     break;
11088                 case CTN9:
11089                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11090                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11091                     break;
11092             }
11093             break;
11094 
11095         case CSTS:  // nuttin' to do here .....
11096         case CSNS:
11097             break;  // no sign wysiwyg
11098     }
11099 
11100     // 2nd, write the digits .....
11101     for(int i = 0 ; i < n2 ; i++)
11102         switch(dstTN)
11103         {
11104             case CTN4:
11105                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11106                 break;
11107             case CTN9:
11108                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11109                 break;
11110         }
11111 
11112     // 3rd, take care of any trailing sign or exponent ...
11113     switch(e->S2)
11114     {
11115         case CSTS:  // write trailing sign ....
11116             switch(dstTN)
11117             {
11118                 case CTN4:
11119                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11120                               //   then the 13(8) plus sign character is placed appropriately
11121                               //   if the result of the operation is positive.
11122                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11123                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11124                     else
11125                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11126                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11127                     break;
11128                 case CTN9:
11129                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11130                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11131                     break;
11132             }
11133             break;
11134 
11135         case CSFL:  // floating-point, leading sign.
11136             // write the exponent
11137             switch(dstTN)
11138             {
11139                 case CTN4:
11140                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11141                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11142 
11143                     break;
11144                 case CTN9:
11145                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11146                     break;
11147             }
11148             break;
11149 
11150         case CSLS:  // fixed point, leading sign - already done
11151         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11152             break;
11153     }
11154 
11155     // set flags, etc ...
11156     if (e->S2 == CSFL)
11157     {
11158         if (op3->exponent > 127)
11159         {
11160             SET_I_EOFL;
11161             EOvr = true;
11162         }
11163         if (op3->exponent < -128)
11164         {
11165             SET_I_EUFL;
11166             EOvr = true;
11167         }
11168     }
11169 
11170     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11171     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11172 
11173     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11174 
11175     cleanupOperandDescriptor (cpup, 1);
11176     cleanupOperandDescriptor (cpup, 2);
11177     cleanupOperandDescriptor (cpup, 3);
11178 
11179     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11180       doFault(FAULT_OFL, fst_zero, "sb2d truncation(overflow) fault");
11181     if (EOvr && tstOVFfault (cpup))
11182         doFault(FAULT_OFL, fst_zero, "sb2d over/underflow fault");
11183     if (Ovr)
11184     {
11185         SET_I_OFLOW;
11186         if (tstOVFfault (cpup))
11187           doFault(FAULT_OFL, fst_zero, "sb2d overflow fault");
11188     }
11189 }
11190 
11191 /*
11192  * sb3d - Subtract Using Three Decimal Operands
11193  */
11194 
11195 void sb3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11196 {
11197     EISstruct * e = & cpu.currentEISinstruction;
11198 
11199     fault_ipr_subtype_ mod_fault = 0;
11200 
11201 #if !defined(EIS_SETUP)
11202     setupOperandDescriptor(cpup, 1, &mod_fault);
11203     setupOperandDescriptor(cpup, 2, &mod_fault);
11204     setupOperandDescriptor(cpup, 3, &mod_fault);
11205 #endif
11206 
11207     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11208     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11209     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
11210 
11211     L68_ (
11212       // L68 raises it immediately
11213       if (mod_fault)
11214         {
11215           doFault (FAULT_IPR,
11216                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11217                    "Illegal modifier");
11218         }
11219     )
11220 
11221     // Bit 1 MBZ
11222     if (IWB_IRODD & 0200000000000)
11223       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb3d(): 1 MBZ");
11224 
11225     DPS8M_ (
11226       // DPS8M raises it delayed
11227       if (mod_fault)
11228         {
11229           doFault (FAULT_IPR,
11230                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11231                    "Illegal modifier");
11232         }
11233     )
11234 
11235     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11236     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11237     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11238 
11239     PNL (L68_ (if (R)
11240       DU_CYCLE_FRND;))
11241 
11242     uint srcTN = e->TN1;    // type of chars in src
11243 
11244     uint dstTN = e->TN3;    // type of chars in dst
11245     uint dstCN = e->CN3;    // starting at char pos CN
11246 
11247     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11248 
11249     /*
11250      * Here we need to distinguish between 4 type of numbers.
11251      *
11252      * CSFL - Floating-point, leading sign
11253      * CSLS - Scaled fixed-point, leading sign
11254      * CSTS - Scaled fixed-point, trailing sign
11255      * CSNS - Scaled fixed-point, unsigned
11256      */
11257 
11258     // determine precision
11259     switch(e->S1)
11260     {
11261         case CSFL:
11262             n1 = (int) e->N1 - 1; // need to account for the - sign
11263             if (srcTN == CTN4)
11264                 n1 -= 2;    // 2 4-bit digits exponent
11265             else
11266                 n1 -= 1;    // 1 9-bit digit exponent
11267             sc1 = 0;        // no scaling factor
11268             break;
11269 
11270         case CSLS:
11271         case CSTS:
11272             n1 = (int) e->N1 - 1; // only 1 sign
11273             sc1 = -e->SF1;
11274             break;
11275 
11276         case CSNS:
11277             n1 = (int) e->N1;     // no sign
11278             sc1 = -e->SF1;
11279             break;  // no sign wysiwyg
11280     }
11281 
11282     if (n1 < 1)
11283         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n1<1");
11284 
11285     switch(e->S2)
11286     {
11287         case CSFL:
11288             n2 = (int) e->N2 - 1; // need to account for the sign
11289             if (e->TN2 == CTN4)
11290                 n2 -= 2;    // 2 4-bit digit exponent
11291             else
11292                 n2 -= 1;    // 1 9-bit digit exponent
11293             sc2 = 0;        // no scaling factor
11294             break;
11295 
11296         case CSLS:
11297         case CSTS:
11298             n2 = (int) e->N2 - 1; // 1 sign
11299             sc2 = -e->SF2;
11300             break;
11301 
11302         case CSNS:
11303             n2 = (int) e->N2;     // no sign
11304             sc2 = -e->SF2;
11305             break;  // no sign wysiwyg
11306     }
11307 
11308     if (n2 < 1)
11309         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n2<1");
11310 
11311     switch(e->S3)
11312     {
11313         case CSFL:
11314             n3 = (int) e->N3 - 1; // need to account for the sign
11315             if (dstTN == CTN4)
11316                 n3 -= 2;    // 2 4-bit digit exponent
11317             else
11318                 n3 -= 1;    // 1 9-bit digit exponent
11319             break;
11320 
11321         case CSLS:
11322         case CSTS:
11323             n3 = (int) e->N3 - 1; // 1 sign
11324             break;
11325 
11326         case CSNS:
11327             n3 = (int) e->N3;     // no sign
11328             break;  // no sign wysiwyg
11329     }
11330 
11331     if (n3 < 1)
11332         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n3<1");
11333 
11334     decContext set;
11335     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11336     decContextDefaultDPS8(&set);
11337 
11338     set.traps=0;
11339 
11340     decNumber _1, _2, _3;
11341 
11342     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11343 
11344     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11345     if (e->sign == -1)
11346         op1->bits |= DECNEG;
11347     if (e->S1 == CSFL)
11348         op1->exponent = e->exponent;
11349 
11350     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11351 
11352     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11353     if (e->sign == -1)
11354         op2->bits |= DECNEG;
11355     if (e->S2 == CSFL)
11356         op2->exponent = e->exponent;
11357 
11358     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11359 
11360     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11361     bool iOvr = 0;
11362     if (op3->digits > 63) {
11363         uint8_t pr[256];
11364         // if sf<=0, trailing zeroes can't be shifted out
11365         // if sf> 0, (some of) trailing zeroes can be shifted out
11366         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11367 
11368         int ctz = 0;
11369         if (sf>0) {     // optimize: we don't care when sf>0
11370             decNumberGetBCD(op3,pr);
11371             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11372                  ctz ++;
11373         }
11374 
11375         if (op3->digits - min(max(sf,0),ctz) > 63) {
11376             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11377             int safe = set.digits;
11378             decNumber tmp;
11379 
11380             // discard MS digits
11381             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11382             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11383             decNumberPlus(&tmp, op3, &set);
11384             set.digits = safe;
11385 
11386             decNumberSubtract(op3, op3, &tmp, &set);
11387 
11388             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
11389 
11390             decContextSetRounding(&set, safeR);
11391             iOvr = 1;
11392         }
11393     }
11394 
11395     bool Ovr = false, EOvr = false, Trunc = false;
11396 
11397     uint8_t out [256];
11398     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11399 
11400     Ovr |= iOvr;
11401 
11402     if (decNumberIsZero(op3))
11403         op3->exponent = 127;
11404 
11405     // now write to memory in proper format.....
11406 
11407     //word18 dstAddr = e->dstAddr;
11408     int pos = (int) dstCN;
11409 
11410     // 1st, take care of any leading sign .......
11411     switch(e->S3)
11412     {
11413         case CSFL:  // floating-point, leading sign.
11414         case CSLS:  // fixed-point, leading sign
11415             switch(dstTN)
11416         {
11417             case CTN4:
11418                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11419                           //   then the 13(8) plus sign character is placed appropriately
11420                           //   if the result of the operation is positive.
11421                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11422                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11423                 else
11424                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11425                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11426                 break;
11427             case CTN9:
11428                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11429                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11430                 break;
11431         }
11432             break;
11433 
11434         case CSTS:  // nuttin' to do here .....
11435         case CSNS:
11436             break;  // no sign wysiwyg
11437     }
11438 
11439     // 2nd, write the digits .....
11440     for(int i = 0 ; i < n3 ; i++)
11441         switch(dstTN)
11442     {
11443         case CTN4:
11444             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11445             break;
11446         case CTN9:
11447             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11448             break;
11449     }
11450 
11451     // 3rd, take care of any trailing sign or exponent ...
11452     switch(e->S3)
11453     {
11454         case CSTS:  // write trailing sign ....
11455             switch(dstTN)
11456             {
11457                 case CTN4:
11458                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11459                               //   then the 13(8) plus sign character is placed appropriately
11460                               //   if the result of the operation is positive.
11461                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11462                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11463                     else
11464                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11465                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11466                     break;
11467                 case CTN9:
11468                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11469                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11470                     break;
11471             }
11472             break;
11473 
11474         case CSFL:  // floating-point, leading sign.
11475             // write the exponent
11476             switch(dstTN)
11477             {
11478                 case CTN4:
11479                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11480                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11481 
11482                     break;
11483                 case CTN9:
11484                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11485                     break;
11486             }
11487             break;
11488 
11489         case CSLS:  // fixed point, leading sign - already done
11490         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11491             break;
11492     }
11493 
11494     // set flags, etc ...
11495     if (e->S3 == CSFL)
11496     {
11497         if (op3->exponent > 127)
11498         {
11499             SET_I_EOFL;
11500             EOvr = true;
11501         }
11502         if (op3->exponent < -128)
11503         {
11504             SET_I_EUFL;
11505             EOvr = true;
11506         }
11507     }
11508 
11509     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11510     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11511 
11512     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11513 
11514     cleanupOperandDescriptor (cpup, 1);
11515     cleanupOperandDescriptor (cpup, 2);
11516     cleanupOperandDescriptor (cpup, 3);
11517 
11518     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11519       doFault(FAULT_OFL, fst_zero, "sb3d truncation(overflow) fault");
11520     if (EOvr && tstOVFfault (cpup))
11521         doFault(FAULT_OFL, fst_zero, "sb3d over/underflow fault");
11522     if (Ovr)
11523     {
11524         SET_I_OFLOW;
11525         if (tstOVFfault (cpup))
11526           doFault(FAULT_OFL, fst_zero, "sb3d overflow fault");
11527     }
11528 }
11529 
11530 /*
11531  * mp2d - Multiply Using Two Decimal Operands
11532  */
11533 
11534 void mp2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11535 {
11536     EISstruct * e = & cpu.currentEISinstruction;
11537 
11538     fault_ipr_subtype_ mod_fault = 0;
11539 
11540 #if !defined(EIS_SETUP)
11541     setupOperandDescriptor(cpup, 1, &mod_fault);
11542     setupOperandDescriptor(cpup, 2, &mod_fault);
11543     setupOperandDescriptorCache(cpup,3);
11544 #endif
11545 
11546     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11547     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11548 
11549     L68_ (
11550       // L68 raises it immediately
11551       if (mod_fault)
11552         {
11553           doFault (FAULT_IPR,
11554                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11555                    "Illegal modifier");
11556         }
11557     )
11558 
11559     // Bits 1-8 MBZ
11560     if (IWB_IRODD & 0377000000000)
11561       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp2d 1-8 MBZ");
11562 
11563     DPS8M_ (
11564       // DPS8M raises it delayed
11565       if (mod_fault)
11566         {
11567           doFault (FAULT_IPR,
11568                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11569                    "Illegal modifier");
11570         }
11571     )
11572 
11573     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11574     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11575     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11576 
11577     PNL (L68_ (if (R)
11578       DU_CYCLE_FRND;))
11579 
11580     uint srcTN = e->TN1;    // type of chars in src
11581 
11582     uint dstTN = e->TN2;    // type of chars in dst
11583     uint dstCN = e->CN2;    // starting at char pos CN
11584 
11585     e->ADDR3 = e->ADDR2;
11586 
11587     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
11588 
11589     /*
11590      * Here we need to distinguish between 4 type of numbers.
11591      *
11592      * CSFL - Floating-point, leading sign
11593      * CSLS - Scaled fixed-point, leading sign
11594      * CSTS - Scaled fixed-point, trailing sign
11595      * CSNS - Scaled fixed-point, unsigned
11596      */
11597 
11598     // determine precision
11599     switch(e->S1)
11600     {
11601         case CSFL:
11602             n1 = (int) e->N1 - 1; // need to account for the - sign
11603             if (srcTN == CTN4)
11604                 n1 -= 2;    // 2 4-bit digits exponent
11605             else
11606                 n1 -= 1;    // 1 9-bit digit exponent
11607             sc1 = 0;        // no scaling factor
11608             break;
11609 
11610         case CSLS:
11611         case CSTS:
11612             n1 = (int) e->N1 - 1; // only 1 sign
11613             sc1 = -e->SF1;
11614             break;
11615 
11616         case CSNS:
11617             n1 = (int) e->N1;     // no sign
11618             sc1 = -e->SF1;
11619             break;  // no sign wysiwyg
11620     }
11621 
11622     if (n1 < 1)
11623         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n1<1");
11624 
11625     switch(e->S2)
11626     {
11627         case CSFL:
11628             n2 = (int) e->N2 - 1; // need to account for the sign
11629             if (e->TN2 == CTN4)
11630                 n2 -= 2;    // 2 4-bit digit exponent
11631             else
11632                 n2 -= 1;    // 1 9-bit digit exponent
11633             sc2 = 0;        // no scaling factor
11634             break;
11635 
11636         case CSLS:
11637         case CSTS:
11638             n2 = (int) e->N2 - 1; // 1 sign
11639             sc2 = -e->SF2;
11640             break;
11641 
11642         case CSNS:
11643             n2 = (int) e->N2;     // no sign
11644             sc2 = -e->SF2;
11645             break;  // no sign wysiwyg
11646     }
11647 
11648     if (n2 < 1)
11649         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n2<1");
11650 
11651     decContext set;
11652     decContextDefaultDPS8Mul(&set); // 126 digits for multiply
11653 
11654     set.traps=0;
11655 
11656     decNumber _1, _2, _3;
11657 
11658     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11659 
11660     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11661     if (e->sign == -1)
11662         op1->bits |= DECNEG;
11663     if (e->S1 == CSFL)
11664         op1->exponent = e->exponent;
11665 
11666     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11667 
11668     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11669     if (e->sign == -1)
11670         op2->bits |= DECNEG;
11671     if (e->S2 == CSFL)
11672         op2->exponent = e->exponent;
11673 
11674     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11675 
11676     bool Ovr = false, EOvr = false, Trunc = false;
11677 
11678     uint8_t out [256];
11679     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11680 
11681     if (decNumberIsZero(op3))
11682         op3->exponent = 127;
11683 
11684     // now write to memory in proper format.....
11685 
11686     //word18 dstAddr = e->dstAddr;
11687     int pos = (int) dstCN;
11688 
11689     // 1st, take care of any leading sign .......
11690     switch(e->S2)
11691     {
11692         case CSFL:  // floating-point, leading sign.
11693         case CSLS:  // fixed-point, leading sign
11694             switch(dstTN)
11695         {
11696             case CTN4:
11697                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11698                           //   then the 13(8) plus sign character is placed appropriately
11699                           //   if the result of the operation is positive.
11700                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11701                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11702                 else
11703                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11704                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11705                 break;
11706             case CTN9:
11707                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11708                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11709                 break;
11710         }
11711             break;
11712 
11713         case CSTS:  // nuttin' to do here .....
11714         case CSNS:
11715             break;  // no sign wysiwyg
11716     }
11717 
11718     // 2nd, write the digits .....
11719     for(int i = 0 ; i < n2 ; i++)
11720         switch(dstTN)
11721     {
11722         case CTN4:
11723             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11724             break;
11725         case CTN9:
11726             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11727             break;
11728     }
11729 
11730     // 3rd, take care of any trailing sign or exponent ...
11731     switch(e->S2)
11732     {
11733         case CSTS:  // write trailing sign ....
11734             switch(dstTN)
11735         {
11736             case CTN4:
11737                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11738                           //   then the 13(8) plus sign character is placed appropriately
11739                           //   if the result of the operation is positive.
11740                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11741                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11742                 else
11743                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11744                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11745                 break;
11746             case CTN9:
11747                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11748                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11749                 break;
11750         }
11751             break;
11752 
11753         case CSFL:  // floating-point, leading sign.
11754             // write the exponent
11755             switch(dstTN)
11756             {
11757                 case CTN4:
11758                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11759                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11760 
11761                     break;
11762                 case CTN9:
11763                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11764                     break;
11765             }
11766             break;
11767 
11768         case CSLS:  // fixed point, leading sign - already done
11769         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11770             break;
11771     }
11772 
11773     // set flags, etc ...
11774     if (e->S2 == CSFL)
11775     {
11776         if (op3->exponent > 127)
11777         {
11778             SET_I_EOFL;
11779             EOvr = true;
11780         }
11781         if (op3->exponent < -128)
11782         {
11783             SET_I_EUFL;
11784             EOvr = true;
11785         }
11786     }
11787 
11788     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11789     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11790 
11791     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11792 
11793     cleanupOperandDescriptor (cpup, 1);
11794     cleanupOperandDescriptor (cpup, 2);
11795     cleanupOperandDescriptor (cpup, 3);
11796 
11797     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11798       doFault(FAULT_OFL, fst_zero, "mp2d truncation(overflow) fault");
11799     if (EOvr && tstOVFfault (cpup))
11800         doFault(FAULT_OFL, fst_zero, "mp2d over/underflow fault");
11801     if (Ovr)
11802     {
11803         SET_I_OFLOW;
11804         if (tstOVFfault (cpup))
11805           doFault(FAULT_OFL, fst_zero, "mp2d overflow fault");
11806     }
11807 }
11808 
11809 /*
11810  * mp3d - Multiply Using Three Decimal Operands
11811  */
11812 
11813 void mp3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11814 {
11815     EISstruct * e = & cpu.currentEISinstruction;
11816 
11817     fault_ipr_subtype_ mod_fault = 0;
11818 
11819 #if !defined(EIS_SETUP)
11820     setupOperandDescriptor(cpup, 1, &mod_fault);
11821     setupOperandDescriptor(cpup, 2, &mod_fault);
11822     setupOperandDescriptor(cpup, 3, &mod_fault);
11823 #endif
11824 
11825     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11826     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11827     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
11828 
11829     L68_ (
11830       // L68 raises it immediately
11831       if (mod_fault)
11832         {
11833           doFault (FAULT_IPR,
11834                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11835                    "Illegal modifier");
11836         }
11837     )
11838 
11839     // Bit 1 MBZ
11840     if (IWB_IRODD & 0200000000000)
11841       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp3d(): 1 MBZ");
11842 
11843     DPS8M_ (
11844       // DPS8M raises it delayed
11845       if (mod_fault)
11846         {
11847           doFault (FAULT_IPR,
11848                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11849                    "Illegal modifier");
11850         }
11851     )
11852 
11853     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11854     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11855     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11856 
11857     PNL (L68_ (if (R)
11858       DU_CYCLE_FRND;))
11859 
11860     uint srcTN = e->TN1;    // type of chars in src
11861 
11862     uint dstTN = e->TN3;    // type of chars in dst
11863     uint dstCN = e->CN3;    // starting at char pos CN
11864 
11865     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11866 
11867     /*
11868      * Here we need to distinguish between 4 type of numbers.
11869      *
11870      * CSFL - Floating-point, leading sign
11871      * CSLS - Scaled fixed-point, leading sign
11872      * CSTS - Scaled fixed-point, trailing sign
11873      * CSNS - Scaled fixed-point, unsigned
11874      */
11875 
11876     // determine precision
11877     switch(e->S1)
11878     {
11879         case CSFL:
11880             n1 = (int) e->N1 - 1; // need to account for the - sign
11881             if (srcTN == CTN4)
11882                 n1 -= 2;    // 2 4-bit digits exponent
11883             else
11884                 n1 -= 1;    // 1 9-bit digit exponent
11885             sc1 = 0;        // no scaling factor
11886             break;
11887 
11888         case CSLS:
11889         case CSTS:
11890             n1 = (int) e->N1 - 1; // only 1 sign
11891             sc1 = -e->SF1;
11892             break;
11893 
11894         case CSNS:
11895             n1 = (int) e->N1;     // no sign
11896             sc1 = -e->SF1;
11897             break;  // no sign wysiwyg
11898     }
11899 
11900     if (n1 < 1)
11901         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n1<1");
11902 
11903     switch(e->S2)
11904     {
11905         case CSFL:
11906             n2 = (int) e->N2 - 1; // need to account for the sign
11907             if (e->TN2 == CTN4)
11908                 n2 -= 2;    // 2 4-bit digit exponent
11909             else
11910                 n2 -= 1;    // 1 9-bit digit exponent
11911             sc2 = 0;        // no scaling factor
11912             break;
11913 
11914         case CSLS:
11915         case CSTS:
11916             n2 = (int) e->N2 - 1; // 1 sign
11917             sc2 = -e->SF2;
11918             break;
11919 
11920         case CSNS:
11921             n2 = (int) e->N2;     // no sign
11922             sc2 = -e->SF2;
11923             break;  // no sign wysiwyg
11924     }
11925 
11926     if (n2 < 1)
11927         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n2<1");
11928 
11929     switch(e->S3)
11930     {
11931         case CSFL:
11932             n3 = (int) e->N3 - 1; // need to account for the sign
11933             if (dstTN == CTN4)
11934                 n3 -= 2;    // 2 4-bit digit exponent
11935             else
11936                 n3 -= 1;    // 1 9-bit digit exponent
11937             break;
11938 
11939         case CSLS:
11940         case CSTS:
11941             n3 = (int) e->N3 - 1; // 1 sign
11942             break;
11943 
11944         case CSNS:
11945             n3 = (int) e->N3;     // no sign
11946             break;  // no sign wysiwyg
11947     }
11948 
11949     if (n3 < 1)
11950         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n3<1");
11951 
11952     decContext set;
11953     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11954     decContextDefaultDPS8Mul(&set);     // 126 digits for multiply
11955 
11956     set.traps=0;
11957 
11958     decNumber _1, _2, _3;
11959 
11960     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11961 
11962     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11963     if (e->sign == -1)
11964         op1->bits |= DECNEG;
11965     if (e->S1 == CSFL)
11966         op1->exponent = e->exponent;
11967 
11968     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11969 
11970     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11971     if (e->sign == -1)
11972         op2->bits |= DECNEG;
11973     if (e->S2 == CSFL)
11974         op2->exponent = e->exponent;
11975 
11976     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11977 
11978 //    char c1[1024];
11979 //    char c2[1024];
11980 //    char c3[1024];
11981 //
11982 //    decNumberToString(op1, c1);
11983 //    sim_printf("c1:%s\n", c1);
11984 //    decNumberToString(op2, c2);
11985 //    sim_printf("c2:%s\n", c2);
11986 //    decNumberToString(op3, c3);
11987 //    sim_printf("c3:%s\n", c3);
11988 
11989     bool Ovr = false, EOvr = false, Trunc = false;
11990 
11991     uint8_t out [256];
11992     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11993 
11994     if (decNumberIsZero(op3))
11995         op3->exponent = 127;
11996 
11997     // now write to memory in proper format.....
11998 
11999     //word18 dstAddr = e->dstAddr;
12000     int pos = (int) dstCN;
12001 
12002     // 1st, take care of any leading sign .......
12003     switch(e->S3)
12004     {
12005         case CSFL:  // floating-point, leading sign.
12006         case CSLS:  // fixed-point, leading sign
12007             switch(dstTN)
12008             {
12009             case CTN4:
12010               if (e->P) // If TN2 and S2 specify a 4-bit signed number and P
12011                           // = 1, then the 13(8) plus sign character is placed
12012                           // appropriately if the result of the operation is
12013                           // positive.
12014                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12015                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
12016                 else
12017                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12018                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
12019                 break;
12020             case CTN9:
12021                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12022                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
12023                 break;
12024             }
12025             break;
12026 
12027         case CSTS:  // nuttin' to do here .....
12028         case CSNS:
12029             break;  // no sign wysiwyg
12030     }
12031 
12032     // 2nd, write the digits .....
12033     for(int i = 0 ; i < n3 ; i++)
12034         switch(dstTN)
12035         {
12036             case CTN4:
12037                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
12038                 break;
12039             case CTN9:
12040                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
12041                 break;
12042         }
12043 
12044         // 3rd, take care of any trailing sign or exponent ...
12045     switch(e->S3)
12046     {
12047         case CSTS:  // write trailing sign ....
12048             switch(dstTN)
12049             {
12050                 case CTN4:
12051                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
12052                               //  then the 13(8) plus sign character is placed appropriately
12053                               //  if the result of the operation is positive.
12054                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12055                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
12056                     else
12057                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12058                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
12059                     break;
12060                 case CTN9:
12061                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12062                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
12063                     break;
12064             }
12065             break;
12066 
12067         case CSFL:  // floating-point, leading sign.
12068             // write the exponent
12069             switch(dstTN)
12070             {
12071                 case CTN4:
12072                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
12073                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
12074                     break;
12075                 case CTN9:
12076                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
12077                     break;
12078             }
12079             break;
12080 
12081         case CSLS:  // fixed point, leading sign - already done
12082         case CSNS:  // fixed point, unsigned - nuttin' needed to do
12083             break;
12084     }
12085 
12086     // set flags, etc ...
12087     if (e->S3 == CSFL)
12088     {
12089         if (op3->exponent > 127)
12090         {
12091             SET_I_EOFL;
12092             EOvr = true;
12093         }
12094         if (op3->exponent < -128)
12095         {
12096             SET_I_EUFL;
12097             EOvr = true;
12098         }
12099     }
12100 
12101     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
12102     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
12103 
12104     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
12105 
12106     cleanupOperandDescriptor (cpup, 1);
12107     cleanupOperandDescriptor (cpup, 2);
12108     cleanupOperandDescriptor (cpup, 3);
12109 
12110     if (TST_I_TRUNC && T && tstOVFfault (cpup))
12111       doFault(FAULT_OFL, fst_zero, "mp3d truncation(overflow) fault");
12112     if (EOvr && tstOVFfault (cpup))
12113         doFault(FAULT_OFL, fst_zero, "mp3d over/underflow fault");
12114     if (Ovr)
12115     {
12116         SET_I_OFLOW;
12117         if (tstOVFfault (cpup))
12118           doFault(FAULT_OFL, fst_zero, "mp3d overflow fault");
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 
12755 
12756 
12757 
12758 
12759 
12760 
12761 
12762 
12763 
12764 
12765 
12766 
12767 
12768 
12769 
12770 
12771 
12772 
12773 
12774 
12775 
12776 
12777 
12778 
12779 
12780 
12781 
12782 
12783 
12784 
12785 
12786 
12787 
12788 
12789 
12790 
12791 
12792 
12793 
12794 
12795 
12796 
12797 
12798 
12799 
12800 
12801 
12802 
12803 
12804 
12805 
12806 
12807 
12808 
12809 
12810 
12811 
12812 
12813 
12814 
12815 
12816 
12817 
12818 
12819 
12820 
12821 
12822 
12823 
12824 
12825 
12826 
12827 
12828 
12829 
12830 
12831 
12832 
12833 
12834 
12835 
12836 
12837 
12838 
12839 
12840 
12841 
12842 
12843 
12844 
12845 
12846 
12847 
12848 
12849 
12850 
12851 
12852 
12853 
12854 
12855 
12856 
12857 
12858 
12859 
12860 
12861 
12862 
12863 
12864 
12865 
12866 
12867 
12868 
12869 
12870 
12871 /*
12872  * dv2d - Divide Using Two Decimal Operands
12873  */
12874 
12875 void dv2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
12876 {
12877     EISstruct * e = & cpu.currentEISinstruction;
12878 
12879     fault_ipr_subtype_ mod_fault = 0;
12880 
12881 #if !defined(EIS_SETUP)
12882     setupOperandDescriptor(cpup, 1, &mod_fault);
12883     setupOperandDescriptor(cpup, 2, &mod_fault);
12884     setupOperandDescriptorCache(cpup, 3);
12885 #endif
12886 
12887     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
12888     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
12889 
12890     L68_ (
12891       // L68 raises it immediately
12892       if (mod_fault)
12893         {
12894           doFault (FAULT_IPR,
12895                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12896                    "Illegal modifier");
12897         }
12898     )
12899 
12900     // Bits 1-8 MBZ
12901     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ as well
12902     if (IWB_IRODD & 0377400000000)
12903       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv2d 1-9 MBZ");
12904 
12905     DPS8M_ (
12906       // DPS8M raises it delayed
12907       if (mod_fault)
12908         {
12909           doFault (FAULT_IPR,
12910                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12911                    "Illegal modifier");
12912         }
12913     )
12914 
12915     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
12916     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
12917     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
12918 
12919     PNL (L68_ (if (R)
12920       DU_CYCLE_FRND;))
12921 
12922     uint srcTN = e->TN1;    // type of chars in src
12923 
12924     uint dstTN = e->TN2;    // type of chars in dst
12925     uint dstCN = e->CN2;    // starting at char pos CN
12926 
12927     e->ADDR3 = e->ADDR2;
12928 
12929     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
12930 
12931     /*
12932      * Here we need to distinguish between 4 type of numbers.
12933      *
12934      * CSFL - Floating-point, leading sign
12935      * CSLS - Scaled fixed-point, leading sign
12936      * CSTS - Scaled fixed-point, trailing sign
12937      * CSNS - Scaled fixed-point, unsigned
12938      */
12939 
12940     // determine precision
12941     switch(e->S1)
12942     {
12943         case CSFL:
12944             n1 = (int) e->N1 - 1; // need to account for the - sign
12945             if (srcTN == CTN4)
12946                 n1 -= 2;    // 2 4-bit digits exponent
12947             else
12948                 n1 -= 1;    // 1 9-bit digit exponent
12949             sc1 = 0;        // no scaling factor
12950             break;
12951 
12952         case CSLS:
12953         case CSTS:
12954             n1 = (int) e->N1 - 1; // only 1 sign
12955             sc1 = -e->SF1;
12956             break;
12957 
12958         case CSNS:
12959             n1 = (int) e->N1;     // no sign
12960             sc1 = -e->SF1;
12961             break;  // no sign wysiwyg
12962     }
12963 
12964     if (n1 < 1)
12965         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n1<1");
12966 
12967     switch(e->S2)
12968     {
12969         case CSFL:
12970             n2 = (int) e->N2 - 1; // need to account for the sign
12971             if (e->TN2 == CTN4)
12972                 n2 -= 2;    // 2 4-bit digit exponent
12973             else
12974                 n2 -= 1;    // 1 9-bit digit exponent
12975             sc2 = 0;        // no scaling factor
12976             break;
12977 
12978         case CSLS:
12979         case CSTS:
12980             n2 = (int) e->N2 - 1; // 1 sign
12981             sc2 = -e->SF2;
12982             break;
12983 
12984         case CSNS:
12985             n2 = (int) e->N2;     // no sign
12986             sc2 = -e->SF2;
12987             break;  // no sign wysiwyg
12988     }
12989 
12990     if (n2 < 1)
12991         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n2<1");
12992 
12993     decContext set;
12994     decContextDefaultDPS8(&set);
12995 
12996     set.traps=0;
12997 
12998     decNumber _1, _2, _3;
12999 
13000     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
13001 
13002     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);    // divisor
13003     if (e->sign == -1)
13004         op1->bits |= DECNEG;
13005     if (e->S1 == CSFL)
13006         op1->exponent = e->exponent;
13007 
13008     // check for divide by 0!
13009     if (decNumberIsZero(op1))
13010     {
13011         doFault(FAULT_DIV, fst_zero, "dv2d division by 0");
13012     }
13013 
13014     word9   inBufferop1 [64];
13015     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13016 
13017     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
13018 
13019     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);    // dividend
13020     if (e->sign == -1)
13021         op2->bits |= DECNEG;
13022     if (e->S2 == CSFL)
13023         op2->exponent = e->exponent;
13024 
13025     int NQ;
13026     if (e->S2 == CSFL)
13027     {
13028         NQ = n2;
13029     }
13030     else
13031     {
13032         // count leading zeroes
13033         // TODO optimize - can these be somehow extracted from decNumbers?
13034         int clz1, clz2, i;
13035         for (i=0; i < op1->digits; i++)
13036             if (inBufferop1[i]!=0)
13037                 break;
13038         clz1 = i;
13039         for (i=0; i < op2->digits; i++)
13040             if (e->inBuffer[i]!=0) // this still holds op2 digits
13041                 break;
13042         clz2 = i;
13043         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: clz1 %d clz2 %d\n",clz1,clz2);
13044 
13045         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13046         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13047         NQ = (n2-clz2+1) - (n1-clz1) + (-(e->S1==CSFL?op1->exponent:(int)e->SF1));
13048 
13049 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",
13050            e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF2,NQ);
13051     }
13052     if (NQ > 63)
13053         doFault(FAULT_DIV, fst_zero, "dv2d NQ>63");
13054     // Note: NQ is currently unused apart from this FAULT_DIV check.
13055     // decNumber produces more digits than required, but they are then rounded/truncated
13056 
13057     // Yes, they're switched. op1=divisor
13058     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13059     // Note DPS88 and DPS9000 are different when NQ <= 0
13060     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13061     // ISOLTS-817 05b
13062 
13063     PRINTDEC("op2", op2);
13064     PRINTDEC("op1", op1);
13065     PRINTDEC("op3", op3);
13066 
13067     // let's check division results to see for anomalous conditions
13068     if (
13069         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13070         (set.status & DEC_Invalid_operation) ||
13071         (set.status & DEC_Division_by_zero)
13072         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv2d anomalous results"); } // divide by zero has already been checked before
13073 
13074     if (e->S2 == CSFL)
13075     {
13076         // justify CSFL left
13077         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13078         // Note DPS88 and DPS9000 are different
13079         // ISOLTS-817 06c,06e
13080 
13081         decNumber _sf;
13082 
13083         if (n2 - op3->digits > 0)
13084         {
13085             decNumberFromInt32(&_sf, op3->exponent - (n2 - op3->digits));
13086             PRINTDEC("Value 1", op3)
13087             PRINTDEC("Value sf", &_sf)
13088             op3 = decNumberRescale(op3, op3, &_sf, &set);
13089             PRINTDEC("Value 2", op3)
13090         }
13091     }
13092 
13093     bool Ovr = false, EOvr = false, Trunc = false;
13094     uint8_t out[256];
13095 
13096     // CSFL: If the divisor is greater than the dividend after operand
13097     // alignment, the leading zero digit produced is counted and the effective
13098     // precision of the result is reduced by one.
13099     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13100     // Note DPS88 and DPS9000 are different
13101     //
13102     // "greater after operand alignment" means scale until most-significant digits
13103     //   are nonzero, then compare magnitudes ignoring exponents
13104     // This passes ISOLTS-817 06e, ET 458,461,483,486
13105     char *res;
13106     if (e->S2 == CSFL) {
13107         decNumber _1a;
13108         decNumber _2a;
13109         decNumber _sf;
13110         if (op1->digits >= op2->digits) {
13111             // scale op2
13112             decNumberCopy(&_1a, op1);
13113             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13114             decNumberShift(&_2a, op2, &_sf, &set);
13115         } else if (op1->digits < op2->digits) {
13116             // scale op1
13117             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13118             decNumberShift(&_1a, op1, &_sf, &set);
13119             decNumberCopy(&_2a, op2);
13120         }
13121         _1a.exponent = 0;
13122         _2a.exponent = 0;
13123 
13124         PRINTDEC("dv2d: op1a", &_1a);
13125         PRINTDEC("dv2d: op2a", &_2a);
13126         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\n",
13127                    op1->exponent,op2->exponent,op1->digits,op2->digits,_1a.digits,_2a.digits);
13128 
13129         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13130             // shorten the result field to get proper rounding
13131             res = formatDecimal(out, &set, op3, n2 -1, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13132 
13133             // prepend zero digit
13134             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13135             for (int i = n2; i > 0; i--) // incl.zero terminator
13136                  res[i] = res[i-1];
13137             res[0] = '0';
13138             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: addzero n2 %d %s exp %d\n",n2,res,op3->exponent);
13139         } else {
13140             // full n2 digits are returned
13141             res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13142         }
13143     } else {
13144         // same as all other decimal instructions
13145         res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13146     }
13147 
13148     if (decNumberIsZero(op3))
13149         op3->exponent = 127;
13150 
13151     // now write to memory in proper format.....
13152 
13153     int pos = (int) dstCN;
13154 
13155     // 1st, take care of any leading sign .......
13156     switch(e->S2)
13157     {
13158         case CSFL:  // floating-point, leading sign.
13159         case CSLS:  // fixed-point, leading sign
13160             switch(dstTN)
13161             {
13162                 case CTN4:
13163                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13164                               //   then the 13(8) plus sign character is placed appropriately
13165                               //   if the result of the operation is positive.
13166                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13167                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13168                     else
13169                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13170                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13171                     break;
13172                 case CTN9:
13173                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13174                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13175                     break;
13176             }
13177             break;
13178 
13179         case CSTS:  // nuttin' to do here .....
13180         case CSNS:
13181             break;  // no sign wysiwyg
13182     }
13183 
13184     // 2nd, write the digits .....
13185     for(int i = 0 ; i < n2 ; i++)
13186         switch(dstTN)
13187         {
13188             case CTN4:
13189                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13190                 break;
13191             case CTN9:
13192                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13193                 break;
13194         }
13195 
13196     // 3rd, take care of any trailing sign or exponent ...
13197     switch(e->S2)
13198     {
13199         case CSTS:  // write trailing sign ....
13200             switch(dstTN)
13201             {
13202                 case CTN4:
13203                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13204                               //   then the 13(8) plus sign character is placed appropriately
13205                               //   if the result of the operation is positive.
13206                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13207                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13208                     else
13209                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13210                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13211                     break;
13212                 case CTN9:
13213                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13214                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13215                     break;
13216             }
13217             break;
13218 
13219         case CSFL:  // floating-point, leading sign.
13220             // write the exponent
13221             switch(dstTN)
13222             {
13223                 case CTN4:
13224                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13225                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13226                     break;
13227                 case CTN9:
13228                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13229                     break;
13230             }
13231             break;
13232 
13233         case CSLS:  // fixed point, leading sign - already done
13234         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13235             break;
13236     }
13237 
13238     // set flags, etc ...
13239     if (e->S2 == CSFL)
13240     {
13241         if (op3->exponent > 127)
13242         {
13243             SET_I_EOFL;
13244             EOvr = true;
13245         }
13246         if (op3->exponent < -128)
13247         {
13248             SET_I_EUFL;
13249             EOvr = true;
13250         }
13251     }
13252 
13253     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13254     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13255 
13256     //SC_I_TRUNC (!R && Trunc); // no truncation flag for divide
13257 
13258     cleanupOperandDescriptor (cpup, 1);
13259     cleanupOperandDescriptor (cpup, 2);
13260     cleanupOperandDescriptor (cpup, 3);
13261 
13262     //if (TST_I_TRUNC && T && tstOVFfault (cpup))
13263     //  doFault(FAULT_OFL, fst_zero, "dv2d truncation(overflow) fault");
13264     if (EOvr && tstOVFfault (cpup))
13265         doFault(FAULT_OFL, fst_zero, "dv2d over/underflow fault");
13266     if (Ovr)
13267     {
13268         SET_I_OFLOW;
13269         if (tstOVFfault (cpup))
13270           doFault(FAULT_OFL, fst_zero, "dv2d overflow fault");
13271     }
13272 }
13273 
13274 /*
13275  * dv3d - Divide Using Three Decimal Operands
13276  */
13277 
13278 void dv3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
13279 
13280 {
13281     EISstruct * e = & cpu.currentEISinstruction;
13282 
13283     fault_ipr_subtype_ mod_fault = 0;
13284 
13285 #if !defined(EIS_SETUP)
13286     setupOperandDescriptor(cpup, 1, &mod_fault);
13287     setupOperandDescriptor(cpup, 2, &mod_fault);
13288     setupOperandDescriptor(cpup, 3, &mod_fault);
13289 #endif
13290 
13291     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
13292     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
13293     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
13294 
13295     L68_ (
13296       // L68 raises it immediately
13297       if (mod_fault)
13298         {
13299           doFault (FAULT_IPR,
13300                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13301                    "Illegal modifier");
13302         }
13303     )
13304 
13305     // Bit 1 MBZ
13306     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ
13307     if (IWB_IRODD & 0200400000000)
13308       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv3d(): 1,9 MBZ");
13309 
13310     DPS8M_ (
13311       // DPS8M raises it delayed
13312       if (mod_fault)
13313         {
13314           doFault (FAULT_IPR,
13315                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13316                    "Illegal modifier");
13317         }
13318     )
13319 
13320     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
13321     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
13322     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
13323 
13324     PNL (L68_ (if (R)
13325       DU_CYCLE_FRND;))
13326 
13327     uint srcTN = e->TN1;    // type of chars in src
13328 
13329     uint dstTN = e->TN3;    // type of chars in dst
13330     uint dstCN = e->CN3;    // starting at char pos CN
13331 
13332     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
13333 
13334     /*
13335      * Here we need to distinguish between 4 type of numbers.
13336      *
13337      * CSFL - Floating-point, leading sign
13338      * CSLS - Scaled fixed-point, leading sign
13339      * CSTS - Scaled fixed-point, trailing sign
13340      * CSNS - Scaled fixed-point, unsigned
13341      */
13342 
13343     // determine precision
13344     switch(e->S1)
13345     {
13346         case CSFL:
13347             n1 = (int) e->N1 - 1; // need to account for the - sign
13348             if (srcTN == CTN4)
13349                 n1 -= 2;    // 2 4-bit digits exponent
13350             else
13351                 n1 -= 1;    // 1 9-bit digit exponent
13352             sc1 = 0;        // no scaling factor
13353             break;
13354 
13355         case CSLS:
13356         case CSTS:
13357             n1 = (int) e->N1 - 1; // only 1 sign
13358             sc1 = -e->SF1;
13359             break;
13360 
13361         case CSNS:
13362             n1 = (int) e->N1;     // no sign
13363             sc1 = -e->SF1;
13364             break;  // no sign wysiwyg
13365     }
13366 
13367     if (n1 < 1)
13368         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n1<1");
13369 
13370     switch(e->S2)
13371     {
13372         case CSFL:
13373             n2 = (int) e->N2 - 1; // need to account for the sign
13374             if (e->TN2 == CTN4)
13375                 n2 -= 2;    // 2 4-bit digit exponent
13376             else
13377                 n2 -= 1;    // 1 9-bit digit exponent
13378             sc2 = 0;        // no scaling factor
13379             break;
13380 
13381         case CSLS:
13382         case CSTS:
13383             n2 = (int) e->N2 - 1; // 1 sign
13384             sc2 = -e->SF2;
13385             break;
13386 
13387         case CSNS:
13388             n2 = (int) e->N2;     // no sign
13389             sc2 = -e->SF2;
13390             break;  // no sign wysiwyg
13391     }
13392 
13393     if (n2 < 1)
13394         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n2<1");
13395 
13396     switch(e->S3)
13397     {
13398         case CSFL:
13399             n3 = (int) e->N3 - 1; // need to account for the sign
13400             if (dstTN == CTN4)
13401                 n3 -= 2;    // 2 4-bit digit exponent
13402             else
13403                 n3 -= 1;    // 1 9-bit digit exponent
13404             break;
13405 
13406         case CSLS:
13407         case CSTS:
13408             n3 = (int) e->N3 - 1; // 1 sign
13409             break;
13410 
13411         case CSNS:
13412             n3 = (int) e->N3;     // no sign
13413             break;  // no sign wysiwyg
13414     }
13415     if (n3 < 1)
13416         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n3<1");
13417 
13418     decContext set;
13419     decContextDefaultDPS8(&set);
13420 
13421     set.traps=0;
13422 
13423     decNumber _1, _2, _3;
13424 
13425     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
13426 
13427     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
13428     //PRINTDEC("op1", op1);
13429     if (e->sign == -1)
13430         op1->bits |= DECNEG;
13431     if (e->S1 == CSFL)
13432         op1->exponent = e->exponent;
13433 
13434     // check for divide by 0!
13435     if (decNumberIsZero(op1))
13436     {
13437         doFault(FAULT_DIV, fst_zero, "dv3d division by 0");
13438     }
13439 
13440     word9   inBufferop1 [64];
13441     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13442 
13443     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
13444 
13445     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
13446     if (e->sign == -1)
13447         op2->bits |= DECNEG;
13448     if (e->S2 == CSFL)
13449         op2->exponent = e->exponent;
13450 
13451     // The number of required quotient digits, NQ, is determined before
13452     // division begins as follows:
13453     //  1) Floating-point quotient
13454     //      NQ = N3
13455     //  2) Fixed-point quotient
13456     //    NQ = (N2-LZ2+1) - (N1-LZ1) + (E2-E1-SF3)
13457     //    where: Nn = given operand field length
13458     //        LZn = leading zero count for operand n
13459     //        En = exponent of operand n
13460     //        SF3 = scaling factor of quotient
13461     // 3) Rounding
13462     //    If rounding is specified (R = 1), then one extra quotient digit is
13463     //    produced.
13464     // Note: rule 3 is already handled by formatDecimal rounding
13465     // Nn doesn't represent full field length, but length without sign and exponent (RJ78/DH03 seems like)
13466 
13467     int NQ;
13468     if (e->S3 == CSFL)
13469     {
13470         NQ = n3;
13471     }
13472     else
13473     {
13474         // count leading zeroes
13475         // TODO optimize - can these be somehow extracted from decNumbers?
13476         int clz1, clz2, i;
13477         for (i=0; i < op1->digits; i++)
13478             if (inBufferop1[i]!=0)
13479                 break;
13480         clz1 = i;
13481         for (i=0; i < op2->digits; i++)
13482             if (e->inBuffer[i]!=0) // this still holds op2 digits
13483                 break;
13484         clz2 = i;
13485         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: clz1 %d clz2 %d\n",clz1,clz2);
13486 
13487         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13488         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13489         NQ = (n2-clz2+1) - (n1-clz1) + \
13490                 ((e->S2==CSFL?op2->exponent:(int)e->SF2)-(e->S1==CSFL?op1->exponent:(int)e->SF1)-(int)e->SF3);
13491 
13492 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",
13493            e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF3,NQ);
13494     }
13495     if (NQ > 63)
13496         doFault(FAULT_DIV, fst_zero, "dv3d NQ>63");
13497     // Note: NQ is currently unused apart from this FAULT_DIV check.
13498     //   decNumber produces more digits than required, but they are then rounded/truncated
13499 
13500     // Yes, they're switched. op1=divisor
13501     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13502     // Note DPS88 and DPS9000 are different when NQ <= 0
13503     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13504     // ISOLTS-817 05b
13505 
13506     PRINTDEC("op2", op2);
13507     PRINTDEC("op1", op1);
13508     PRINTDEC("op3", op3);
13509 
13510     // let's check division results to see for anomalous conditions
13511     if (
13512         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13513         (set.status & DEC_Invalid_operation) ||
13514         (set.status & DEC_Division_by_zero)
13515         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv3d anomalous results"); } // divide by zero has already been checked before
13516 
13517     if (e->S3 == CSFL)
13518     {
13519         // justify CSFL left
13520         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13521         // Note DPS88 and DPS9000 are different
13522         // ISOLTS-817 06c,06e
13523 
13524         decNumber _sf;
13525 
13526         if (n3 - op3->digits > 0)
13527         {
13528             decNumberFromInt32(&_sf, op3->exponent - (n3 - op3->digits));
13529             PRINTDEC("Value 1", op3)
13530             PRINTDEC("Value sf", &_sf)
13531             op3 = decNumberRescale(op3, op3, &_sf, &set);
13532             PRINTDEC("Value 2", op3)
13533         }
13534     }
13535 
13536     bool Ovr = false, EOvr = false, Trunc = false;
13537     uint8_t out[256];
13538 
13539     // CSFL: If the divisor is greater than the dividend after operand
13540     // alignment, the leading zero digit produced is counted and the effective
13541     // precision of the result is reduced by one.
13542     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13543     // Note DPS88 and DPS9000 are different
13544     //
13545     // "greater after operand alignment" means scale until most-significant digits
13546     //   are nonzero, then compare magnitudes ignoring exponents
13547     // This passes ISOLTS-817 06e, ET 458,461,483,486
13548     char *res;
13549     if (e->S3 == CSFL) {
13550         decNumber _1a;
13551         decNumber _2a;
13552         decNumber _sf;
13553         if (op1->digits >= op2->digits) {
13554             // scale op2
13555             decNumberCopy(&_1a, op1);
13556             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13557             decNumberShift(&_2a, op2, &_sf, &set);
13558         } else if (op1->digits < op2->digits) {
13559             // scale op1
13560             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13561             decNumberShift(&_1a, op1, &_sf, &set);
13562             decNumberCopy(&_2a, op2);
13563         }
13564         _1a.exponent = 0;
13565         _2a.exponent = 0;
13566 
13567         PRINTDEC("dv3d: op1a", &_1a);
13568         PRINTDEC("dv3d: op2a", &_2a);
13569         sim_debug (DBG_TRACEEXT, & cpu_dev,
13570                    "dv3d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\n",
13571                    op1->exponent ,op2->exponent, op1->digits,
13572                    op2->digits, _1a.digits, _2a.digits);
13573 
13574         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13575             // shorten the result field to get proper rounding
13576             res = formatDecimal(out, &set, op3, n3 -1, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13577 
13578             // prepend zero digit
13579             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13580             for (int i = n3; i > 0; i--) // incl.zero terminator
13581                  res[i] = res[i-1];
13582             res[0] = '0';
13583             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: addzero n3 %d %s exp %d\n",n3,res,op3->exponent);
13584         } else {
13585             // full n3 digits are returned
13586             res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13587         }
13588     } else {
13589         // same as all other decimal instructions
13590         res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13591     }
13592 
13593     if (decNumberIsZero(op3))
13594         op3->exponent = 127;
13595 
13596     //(void)printf("%s\r\n", res);
13597 
13598     // now write to memory in proper format.....
13599 
13600     int pos = (int) dstCN;
13601 
13602     // 1st, take care of any leading sign .......
13603     switch(e->S3)
13604     {
13605         case CSFL:  // floating-point, leading sign.
13606         case CSLS:  // fixed-point, leading sign
13607             switch(dstTN)
13608             {
13609                 case CTN4:
13610                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13611                               //   then the 13(8) plus sign character is placed appropriately
13612                               //   if the result of the operation is positive.
13613                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13614                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13615                     else
13616                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13617                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13618                     break;
13619                 case CTN9:
13620                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13621                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13622                     break;
13623             }
13624             break;
13625 
13626         case CSTS:  // nuttin' to do here .....
13627         case CSNS:
13628             break;  // no sign wysiwyg
13629     }
13630 
13631     // 2nd, write the digits .....
13632     for(int i = 0 ; i < n3 ; i++)
13633         switch(dstTN)
13634         {
13635             case CTN4:
13636                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13637                 break;
13638             case CTN9:
13639                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13640                 break;
13641             }
13642 
13643     // 3rd, take care of any trailing sign or exponent ...
13644     switch(e->S3)
13645     {
13646         case CSTS:  // write trailing sign ....
13647             switch(dstTN)
13648             {
13649                 case CTN4:
13650                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13651                               //   then the 13(8) plus sign character is placed appropriately if
13652                               //   the result of the operation is positive.
13653                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13654                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13655                     else
13656                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13657                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13658                     break;
13659                 case CTN9:
13660                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13661                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13662                 break;
13663             }
13664             break;
13665 
13666         case CSFL:  // floating-point, leading sign.
13667             // write the exponent
13668             switch(dstTN)
13669             {
13670                 case CTN4:
13671                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13672                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13673                     break;
13674                 case CTN9:
13675                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13676                     break;
13677             }
13678             break;
13679 
13680         case CSLS:  // fixed point, leading sign - already done
13681         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13682             break;
13683     }
13684 
13685     // set flags, etc ...
13686     if (e->S3 == CSFL)
13687     {
13688         if (op3->exponent > 127)
13689         {
13690             SET_I_EOFL;
13691             EOvr = true;
13692         }
13693         if (op3->exponent < -128)
13694         {
13695             SET_I_EUFL;
13696             EOvr = true;
13697         }
13698     }
13699 
13700     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13701     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13702 
13703     // SC_I_TRUNC(!R && Trunc); // no truncation flag for divide
13704 
13705     cleanupOperandDescriptor (cpup, 1);
13706     cleanupOperandDescriptor (cpup, 2);
13707     cleanupOperandDescriptor (cpup, 3);
13708 
13709     //if (TST_I_TRUNC && T && tstOVFfault (cpup))
13710     //  doFault(FAULT_OFL, fst_zero, "dv3d truncation(overflow) fault");
13711     if (EOvr && tstOVFfault (cpup))
13712         doFault(FAULT_OFL, fst_zero, "dv3d over/underflow fault");
13713     if (Ovr)
13714     {
13715         SET_I_OFLOW;
13716         if (tstOVFfault (cpup))
13717           doFault(FAULT_OFL, fst_zero, "dv3d overflow fault");
13718     }
13719 }

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