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     if (e->mopIF - 1 >= 0 &&
5884         e->mopIF - 1 < sizeof(e->editInsertionTable) / sizeof(e->editInsertionTable[0])) {
5885           e->editInsertionTable[e->mopIF - 1] = next;
5886     } else {
5887         e->_faults |= FAULT_IPR;
5888         sim_warn("mopIF %d OOB in %s!\r\n", e->mopIF, __func__);
5889         return 0;
5890     }
5891     sim_debug (DBG_TRACEEXT, & cpu_dev, "LTE IT[%d]<=%d\n", e -> mopIF - 1, next);
5892     return 0;
5893 }
5894 
5895 /*!
5896  * MFLC Micro Operation - Move with Floating Currency Symbol Insertion
5897  * EXPLANATION:
5898  * IF specifies the number of characters of the sending field upon which the
5899  * operation is performed, where IF = 0 specifies 16 characters.
5900  * Starting with the next available sending field character, the next IF
5901  * characters are individually fetched and the following conditional actions
5902  * occur.
5903  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
5904  * moved to the receiving field in place of the character.
5905  * − If ES is OFF and the character is not zero, then edit insertion table
5906  * entry 5 is moved to the receiving field, the character is also moved to the
5907  * receiving field, and ES is set ON.
5908  * − If ES is ON, the character is moved to the receiving field.
5909  * The number of characters placed in the receiving field is data-dependent. If
5910  * the entire sending field is zero, IF characters are placed in the receiving
5911  * field. However, if the sending field contains a nonzero character, IF+1
5912  * characters (the insertion character plus the characters from the sending
5913  * field) are placed in the receiving field.
5914  * An IPR fault occurs when the sending field is exhausted before the receiving
5915  * field is filled. In order to provide space in the receiving field for an
5916  * inserted currency symbol, the receiving field must have a string length one
5917  * character longer than the sending field. When the sending field is all
5918  * zeros, no currency symbol is inserted by the MFLC micro operation and the
5919  * receiving field is not filled when the sending field is exhausted. The user
5920  * should provide an ENF (ENF,12) micro operation after a MFLC micro operation
5921  * that has as its character count the number of characters in the sending
5922  * field. The ENF micro operation is engaged only when the MFLC micro operation
5923  * fails to fill the receiving field. Then it supplies a currency symbol to
5924  * fill the receiving field and blanks out the entire field.
5925  * FLAGS: (Flags not listed are not affected.)
5926  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
5927  * is unchanged.
5928  * NOTE: Since the number of characters moved to the receiving string is
5929  * data-dependent, a possible IPR fault may be avoided by ensuring that the Z
5930  * and BZ flags are ON.
5931  */
5932 
5933 static int mopMFLC (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5934 {
5935     EISstruct * e = & cpu.currentEISinstruction;
5936     if (e->mopIF == 0)
5937         e->mopIF = 16;
5938 
5939     //  Starting with the next available sending field character, the next IF
5940     //  characters are individually fetched and the following conditional
5941     //  actions occur.
5942     sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC IF %d, srcTally %d, dstTally %d\n", e->mopIF, e->srcTally, e->dstTally);
5943     for(int n = 0 ; n < e->mopIF ; n += 1)
5944     {
5945         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC n %d, srcTally %d, dstTally %d\n", n, e->srcTally, e->dstTally);
5946         if (e->dstTally == 0)
5947             break;
5948         if (e->srcTally == 0)
5949             return -1;
5950         // If ES is OFF and the character is zero, edit insertion table entry 1
5951         // is moved to the receiving field in place of the character.
5952         // If ES is OFF and the character is not zero, then edit insertion
5953         // table entry 5 is moved to the receiving field, the character is also
5954         // moved to the receiving field, and ES is set ON.
5955 
5956         word9 c = *(e->in);
5957         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC c %d (0%o)\n", c, c);
5958         if (!e->mopES) { // e->mopES is OFF
5959 
5960             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES off\n");
5961             if (isDecimalZero (c)) {
5962                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is zero\n");
5963                 // edit insertion table entry 1 is moved to the receiving field
5964                 // in place of the character.
5965                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5966                 e->in += 1;
5967                 e->srcTally -= 1;
5968             } else {
5969                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is not zero\n");
5970                 // then edit insertion table entry 5 is moved to the receiving
5971                 // field, the character is also moved to the receiving field,
5972                 // and ES is set ON.
5973                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5974 
5975                 writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
5976                 e->mopZ = false; // iszero() tested above.
5977                 e->in += 1;
5978                 e->srcTally -= 1;
5979 
5980                 e->mopES = true;
5981             }
5982         } else {
5983             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES on\n");
5984             // If ES is ON, the character is moved to the receiving field.
5985             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
5986 
5987             if (! isDecimalZero (c))
5988                 e->mopZ = false;
5989             e->in += 1;
5990             e->srcTally -= 1;
5991         }
5992     }
5993 
5994     return 0;
5995 }
5996 
5997 /*!
5998  * MFLS Micro Operation - Move with Floating Sign Insertion
5999  * EXPLANATION:
6000  * IF specifies the number of characters of the sending field upon which the
6001  * operation is performed, where IF = 0 specifies 16 characters.
6002  * Starting with the next available sending field character, the next IF
6003  * characters are individually fetched and the following conditional actions
6004  * occur.
6005  * − If ES is OFF and the character is zero, edit insertion table entry 1 is
6006  * moved to the receiving field in place of the character.
6007  * − If ES is OFF, the character is not zero, and SN is OFF; then edit
6008  * insertion table entry 3 is moved to the receiving field; the character is
6009  * also moved to the receiving field, and ES is set ON.
6010  * − If ES is OFF, the character is nonzero, and SN is ON; edit insertion table
6011  * entry 4 is moved to the receiving field; the character is also moved to the
6012  * receiving field, and ES is set ON.
6013  * − If ES is ON, the character is moved to the receiving field.
6014  * The number of characters placed in the receiving field is data-dependent. If
6015  * the entire sending field is zero, IF characters are placed in the receiving
6016  * field. However, if the sending field contains a nonzero character, IF+1
6017  * characters (the insertion character plus the characters from the sending
6018  * field) are placed in the receiving field.
6019  * An IPR fault occurs when the sending field is exhausted before the receiving
6020  * field is filled. In order to provide space in the receiving field for an
6021  * inserted sign, the receiving field must have a string length one character
6022  * longer than the sending field. When the sending field is all zeros, no sign
6023  * is inserted by the MFLS micro operation and the receiving field is not
6024  * filled when the sending field is exhausted. The user should provide an ENF
6025  * (ENF,4) micro operation after a MFLS micro operation that has as its
6026  * character count the number of characters in the sending field. The ENF micro
6027  * operation is engaged only when the MFLS micro operation fails to fill the
6028  * receiving field; then, it supplies a sign character to fill the receiving
6029  * field and blanks out the entire field.
6030  *
6031  * FLAGS: (Flags not listed are not affected.)
6032  *     ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6033  *     it is unchanged.
6034  * NOTE: Since the number of characters moved to the receiving string is
6035  * data-dependent, a possible Illegal Procedure fault may be avoided by
6036  * ensuring that the Z and BZ flags are ON.
6037  */
6038 
6039 static int mopMFLS (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6040 {
6041     EISstruct * e = & cpu.currentEISinstruction;
6042     if (e->mopIF == 0)
6043         e->mopIF = 16;
6044 
6045     for(int n = 0 ; n < e->mopIF; n += 1)
6046     {
6047         if (e->dstTally == 0)
6048             break;
6049         if (e->srcTally == 0)
6050             return -1;
6051 
6052         word9 c = *(e->in);
6053         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLS n %d c %o\n", n, c);
6054         if (!e->mopES) { // e->mopES is OFF
6055             if (isDecimalZero (c))
6056             {
6057                 // edit insertion table entry 1 is moved to the receiving field
6058                 // in place of the character.
6059                 sim_debug (DBG_TRACEEXT, & cpu_dev,
6060                            "ES is off, c is zero; edit insertion table entry 1"
6061                            " is moved to the receiving field in place of the character.\n");
6062                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6063                 e->in += 1;
6064                 e->srcTally -= 1;
6065             } else {
6066                 // c is non-zero
6067                 if (!e->mopSN)
6068                 {
6069                     // then edit insertion table entry 3 is moved to the
6070                     // receiving field; the character is also moved to the
6071                     // receiving field, and ES is set ON.
6072                     sim_debug (DBG_TRACEEXT, & cpu_dev,
6073                                "ES is off, c is non-zero, SN is off; edit insertion table entry 3"
6074                                " is moved to the receiving field; the character is also moved to"
6075                                " the receiving field, and ES is set ON.\n");
6076                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[2]);
6077 
6078                     e->in += 1;
6079                     e->srcTally -= 1;
6080                     e->mopZ = false; // iszero tested above
6081 
6082 
6083 
6084 
6085 
6086 
6087 
6088 
6089                     writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6090 
6091                     e->mopES = true;
6092                 } else {
6093                     //  SN is ON; edit insertion table entry 4 is moved to the
6094                     //  receiving field; the character is also moved to the
6095                     //  receiving field, and ES is set ON.
6096                     sim_debug (DBG_TRACEEXT, & cpu_dev,
6097                                "ES is off, c is non-zero, SN is OFF; edit insertion table entry 4"
6098                                " is moved to the receiving field; the character is also moved to"
6099                                " the receiving field, and ES is set ON.\n");
6100                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[3]);
6101 
6102                     e->in += 1;
6103                     e->srcTally -= 1;
6104                     e->mopZ = false; // iszero tested above
6105 
6106                     writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6107 
6108                     e->mopES = true;
6109                 }
6110             }
6111         } else {
6112             // If ES is ON, the character is moved to the receiving field.
6113             sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is ON, the character is moved to the receiving field.\n");
6114             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6115 
6116             if (! isDecimalZero (c))
6117                 e->mopZ = false;
6118             e->in += 1;
6119             e->srcTally -= 1;
6120         }
6121     }
6122 
6123     // NOTE: Since the number of characters moved to the receiving string is
6124     // data-dependent, a possible Illegal Procedure fault may be avoided by
6125     // ensuring that the Z and BZ flags are ON.
6126 
6127     return 0;
6128 }
6129 
6130 /*!
6131  * MORS Micro Operation - Move and OR Sign
6132  * EXPLANATION:
6133  * IF specifies the number of characters of the sending field upon which the
6134  * operation is performed, where IF = 0 specifies 16 characters.
6135  * Starting with the next available sending field character, the next IF
6136  * characters are individually fetched and the following conditional actions
6137  * occur.
6138  * − If SN is OFF, the next IF characters in the source data field are moved to
6139  * the receiving data field and, during the move, edit insertion table entry 3
6140  * is ORed to each character.
6141  * − If SN is ON, the next IF characters in the source data field are moved to
6142  * the receiving data field and, during the move, edit insertion table entry 4
6143  * is ORed to each character.
6144  * MORS can be used to generate a negative overpunch for a receiving field to
6145  * be used later as a sending field.
6146  * FLAGS: None affected
6147  */
6148 
6149 static int mopMORS (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6150 {
6151     EISstruct * e = & cpu.currentEISinstruction;
6152     if (e->mopIF == 0)
6153         e->mopIF = 16;
6154 
6155     sim_debug (DBG_TRACEEXT, & cpu_dev, "MORS mopIF %d src %d dst %d\n", e->mopIF, e->srcTally, e->dstTally);
6156     for(int n = 0 ; n < e->mopIF ; n += 1)
6157     {
6158 // The micro operation sequence is terminated normally when the receiving
6159 // string length becomes exhausted. The micro operation sequence is terminated
6160 // abnormally (with an illegal procedure fault) if a move from an exhausted
6161 // sending string or the use of an exhausted MOP string is attempted.
6162 
6163         if (e->dstTally == 0)
6164             break;
6165         if (e->srcTally == 0)
6166             return -1;
6167 
6168         // XXX this is probably wrong regarding the ORing, but it's a start ....
6169         word9 c = (*e->in | (!e->mopSN ? e->editInsertionTable[2] : e->editInsertionTable[3]));
6170         if (! isDecimalZero (*e->in))
6171             e->mopZ = false;
6172         e->in += 1;
6173         e->srcTally -= 1;
6174 
6175         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6176     }
6177 
6178     return 0;
6179 }
6180 
6181 /*!
6182  * MVC Micro Operation - Move Source Characters
6183  * EXPLANATION:
6184  * IF specifies the number of characters to be moved, where IF = 0 specifies 16
6185  * characters.
6186  * The next IF characters in the source data field are moved to the receiving
6187  * data field.
6188  * FLAGS: None affected
6189  */
6190 
6191 static int mopMVC (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6192 {
6193     EISstruct * e = & cpu.currentEISinstruction;
6194     if (e->mopIF == 0)
6195         e->mopIF = 16;
6196 
6197     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC mopIF %d\n", e->mopIF);
6198 
6199     for(int n = 0 ; n < e->mopIF ; n += 1)
6200     {
6201         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC n %d srcTally %d dstTally %d\n", n, e->srcTally, e->dstTally);
6202 // GD's test_float shows that data exhaustion is not a fault.
6203 //#if 0
6204         if (e->dstTally == 0)
6205             break;
6206         if (e->srcTally == 0)
6207             return -1;
6208 
6209         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC write to output buffer %o\n", *e->in);
6210         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, *e->in);
6211         if (! isDecimalZero (*e->in))
6212             e->mopZ = false;
6213         e->in += 1;
6214 
6215         e->srcTally -= 1;
6216     }
6217 
6218     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC done\n");
6219     return 0;
6220 }
6221 
6222 /*!
6223  * MSES Micro Operation - Move and Set Sign
6224  * EXPLANATION:
6225  * IF specifies the number of characters of the sending field upon which the
6226  * operation is performed, where IF = 0 specifies 16 characters. For MVE,
6227  * starting with the next available sending field character, the next IF
6228  * characters are individually fetched and the following conditional actions
6229  * occur.
6230  * Starting with the first character during the move, a comparative AND is made
6231  * first with edit insertion table entry 3. If the result is nonzero, the first
6232  * character and the rest of the characters are moved without further
6233  * comparative ANDs. If the result is zero, a comparative AND is made between
6234  * the character being moved and edit insertion table entry 4 If that result is
6235  * nonzero, the SN indicator is set ON (indicating negative) and the first
6236  * character and the rest of the characters are moved without further
6237  * comparative ANDs. If the result is zero, the second character is treated
6238  * like the first. This process continues until one of the comparative AND
6239  * results is nonzero or until all characters are moved.
6240  * For MVNE instruction, the sign (SN) flag is already set and IF characters
6241  * are moved to the destination field (MSES is equivalent to the MVC
6242  * instruction).
6243  * FLAGS: (Flags not listed are not affected.)
6244  * SN If edit insertion table entry 4 is found in C(Y-1), then ON; otherwise,
6245  * it is unchanged.
6246  */
6247 
6248 static int mopMSES (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6249 {
6250     EISstruct * e = & cpu.currentEISinstruction;
6251     if (e->mvne == true)
6252         return mopMVC (cpup);   // XXX I think!
6253 
6254     if (e->mopIF == 0)
6255         e->mopIF = 16;
6256 
6257     int overpunch = false;
6258 
6259     for(int n = 0 ; n < e->mopIF ; n += 1)
6260     {
6261         if (e->dstTally == 0)
6262             break;
6263         if (e->srcTally == 0)
6264             return -1;
6265 
6266         //Starting with the first character during the move, a comparative AND
6267         //is made first with edit insertion table entry 3. If the result is
6268         //nonzero, the first character and the rest of the characters are moved
6269         //without further comparative ANDs. If the result is zero, a
6270         //comparative AND is made between the character being moved and edit
6271         //insertion table entry 4 If that result is nonzero, the SN indicator
6272         //is set ON (indicating negative) and the first character and the rest
6273         //of the characters are moved without further comparative ANDs. If the
6274         //result is zero, the second character is treated like the first. This
6275         //process continues until one of the comparative AND results is nonzero
6276         //or until all characters are moved.
6277 
6278         word9 c = *(e->in);
6279 
6280         if (!overpunch) {
6281             if (c & e->editInsertionTable[2])  // XXX only lower 4-bits are considered
6282                 overpunch = true;
6283 
6284             else if (c & e->editInsertionTable[3])  // XXX only lower 4-bits are considered
6285             {
6286                 e->mopSN = true;
6287                 overpunch = true;
6288             }
6289         }
6290 
6291         e->in += 1;
6292         e->srcTally -= 1;   // XXX is this correct? No chars have been consumed, but ......
6293         if (! isDecimalZero (c))
6294             e->mopZ = false;
6295         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6296     }
6297 
6298     return 0;
6299 }
6300 
6301 /*!
6302  * MVZA Micro Operation - Move with Zero Suppression and Asterisk Replacement
6303  * EXPLANATION:
6304  * MVZA is the same as MVZB except that if ES is OFF and the character is zero,
6305  * then edit insertion table entry 2 is moved to the receiving field.
6306  * FLAGS: (Flags not listed are not affected.)
6307  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
6308  * is unchanged.
6309  */
6310 
6311 static int mopMVZA (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6312 {
6313     EISstruct * e = & cpu.currentEISinstruction;
6314     if (e->mopIF == 0)
6315         e->mopIF = 16;
6316 
6317     for(int n = 0 ; n < e->mopIF ; n += 1)
6318     {
6319         if (e->dstTally == 0)
6320             break;
6321         if (e->srcTally == 0)
6322             return -1;
6323 
6324         word9 c = *e->in;
6325         e->in += 1;
6326         e->srcTally -= 1;
6327 
6328         //if (!e->mopES && c == 0)
6329         // XXX See srcTA comment in MVNE
6330         if (!e->mopES && isDecimalZero (c))
6331         {
6332             //If ES is OFF and the character is zero, then edit insertion table
6333             //entry 2 is moved to the receiving field in place of the
6334             //character.
6335             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[1]);
6336         //} else if (!e->mopES && c != 0)
6337         // XXX See srcTA comment in MVNE
6338         }
6339         else if ((! e->mopES) && (! isDecimalZero (c)))
6340         {
6341             //If ES is OFF and the character is not zero, then the character is
6342             //moved to the receiving field and ES is set ON.
6343             e->mopZ = false;
6344             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6345 
6346             e->mopES = true;
6347         } else if (e->mopES)
6348         {
6349             //If ES is ON, the character is moved to the receiving field.
6350             if (! isDecimalZero (c))
6351                 e->mopZ = false;
6352             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6353         }
6354     }
6355 
6356     return 0;
6357 }
6358 
6359 /*!
6360  * MVZB Micro Operation - Move with Zero Suppression and Blank Replacement
6361  * EXPLANATION:
6362  * IF specifies the number of characters of the sending field upon which the
6363  * operation is performed, where IF = 0 specifies 16 characters.
6364  * Starting with the next available sending field character, the next IF
6365  * characters are individually fetched and the following conditional actions
6366  * occur.
6367  * − If ES is OFF and the character is zero, then edit insertion table entry 1
6368  * is moved to the receiving field in place of the character.
6369  * − If ES is OFF and the character is not zero, then the character is moved to
6370  * the receiving field and ES is set ON.
6371  * − If ES is ON, the character is moved to the receiving field.
6372  * FLAGS: (Flags not listed are not affected.)
6373  *   ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6374  *   it is unchanged.
6375  */
6376 
6377 static int mopMVZB (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6378 {
6379     EISstruct * e = & cpu.currentEISinstruction;
6380     if (e->mopIF == 0)
6381         e->mopIF = 16;
6382 
6383     for(int n = 0 ; n < e->mopIF ; n += 1)
6384     {
6385         if (e->dstTally == 0)
6386             break;
6387         if (e->srcTally == 0)
6388           return -1;
6389 
6390         word9 c = *e->in;
6391         e->srcTally -= 1;
6392         e->in += 1;
6393 
6394         //if (!e->mopES && c == 0)
6395         // XXX See srcTA comment in MVNE
6396         if ((!e->mopES) && isDecimalZero (c))
6397         {
6398             //If ES is OFF and the character is zero, then edit insertion table
6399             //entry 1 is moved to the receiving field in place of the
6400             //character.
6401             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6402         //} else if (!e->mopES && c != 0)
6403         // XXX See srcTA comment in MVNE
6404         }
6405         if ((! e->mopES) && (! isDecimalZero (c)))
6406         {
6407             //If ES is OFF and the character is not zero, then the character is
6408             //moved to the receiving field and ES is set ON.
6409             e->mopZ = false;
6410             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6411 
6412             e->mopES = true;
6413         } else if (e->mopES)
6414         {
6415             //If ES is ON, the character is moved to the receiving field.
6416             if (! isDecimalZero (c))
6417                 e->mopZ = false;
6418             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6419         }
6420     }
6421 
6422     return 0;
6423 }
6424 
6425 /*!
6426  * SES Micro Operation - Set End Suppression
6427  * EXPLANATION:
6428  * Bit 0 of IF (IF(0)) specifies the setting of the ES switch.
6429  * If IF(0) = 0, the ES flag is set OFF. If IF(0) = 1, the ES flag is set ON.
6430  * Bit 1 of IF (IF(1)) specifies the setting of the blank-when-zero option.
6431  * If IF(1) = 0, no action is taken.
6432  * If IF(1) = 1, the BZ flag is set ON.
6433  * FLAGS: (Flags not listed are not affected.)
6434  * ES set by this micro operation
6435  * BZ If bit 1 of C(IF) = 1, then ON; otherwise, it is unchanged.
6436  */
6437 
6438 static int mopSES (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6439 {
6440     EISstruct * e = & cpu.currentEISinstruction;
6441     if (e->mopIF & 010)
6442         e->mopES = true;
6443     else
6444         e->mopES = false;
6445 
6446     if (e->mopIF & 04)
6447         e->mopBZ = true;
6448 
6449     return 0;
6450 }
6451 
6452 // Table 4-9. Micro Operation Code Assignment Map
6453 #if !defined(QUIET_UNUSED)
6454 static char * mopCodes [040] =
6455   {
6456     //            0       1       2       3       4       5       6       7
6457     /* 00 */      0, "insm",  "enf",  "ses", "mvzb", "mvza", "mfls", "mflc",
6458     /* 10 */ "insb", "insa", "insn", "insp",  "ign",  "mvc", "mses", "mors",
6459     /* 20 */  "lte",  "cht",      0,      0,      0,      0,      0,      0,
6460     /* 30 */      0,      0,      0,      0,      0,      0,      0,      0
6461   };
6462 #endif
6463 
6464 static MOP_struct mopTab[040] = {
6465     {NULL, 0},
6466     {"insm", mopINSM },
6467     {"enf",  mopENF  },
6468     {"ses",  mopSES  },
6469     {"mvzb", mopMVZB },
6470     {"mvza", mopMVZA },
6471     {"mfls", mopMFLS },
6472     {"mflc", mopMFLC },
6473     {"insb", mopINSB },
6474     {"insa", mopINSA },
6475     {"insn", mopINSN },
6476     {"insp", mopINSP },
6477     {"ign",  mopIGN  },
6478     {"mvc",  mopMVC  },
6479     {"mses", mopMSES },
6480     {"mors", mopMORS },
6481     {"lte",  mopLTE  },
6482     {"cht",  mopCHT  },
6483     {NULL, 0},
6484     {NULL, 0},
6485     {NULL, 0},
6486     {NULL, 0},
6487     {NULL, 0},
6488     {NULL, 0},
6489     {NULL, 0},
6490     {NULL, 0},
6491     {NULL, 0},
6492     {NULL, 0},
6493     {NULL, 0},
6494     {NULL, 0},
6495     {NULL, 0},
6496     {NULL, 0}
6497 };
6498 
6499 /*!
6500  * fetch MOP from e->mopAddr/e->mopPos ...
6501  */
6502 
6503 static MOP_struct* EISgetMop (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6504 {
6505     EISstruct * e = & cpu.currentEISinstruction;
6506     //static word18 lastAddress;  // try to keep memory access' down
6507     //static word36 data;
6508 
6509     if (e == NULL) //-V547
6510     //{
6511     //    p->lastAddress = -1;
6512     //    p->data = 0;
6513         return NULL;
6514     //}
6515 
6516 #if defined(EIS_PTR2)
6517     EISaddr *p = &e->ADDR2;
6518 #else
6519     EISaddr *p = e->mopAddress;
6520 #endif
6521 
6522     //if (p->lastAddress != p->address)                 // read from memory if different address
6523         p->data = EISRead(cpup, p);   // read data word from memory
6524 
6525     if (e->mopPos > 3)   // overflows to next word?
6526     {   // yep....
6527         e->mopPos = 0;   // reset to 1st byte
6528 #if defined(EIS_PTR2)
6529         cpu.du.Dk_PTR_W[KMOP] = (cpu.du.Dk_PTR_W[KMOP] + 1) & AMASK;     // bump source to next address
6530         p->data = EISRead(cpup, &e->ADDR2);   // read it from memory
6531 #else
6532         PNL (cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK);     // bump source to next address
6533         PNL (p->data = EISRead(cpup, e->mopAddress));   // read it from memory
6534 # if defined(EIS_PTR)
6535         cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK;     // bump source to next address
6536         p->data = EISRead(cpup, e->mopAddress);   // read it from memory
6537 # else
6538         e->mopAddress->address = (e->mopAddress->address + 1) & AMASK;     // bump source to next address
6539         p->data = EISRead(cpup, e->mopAddress);   // read it from memory
6540 # endif
6541 #endif
6542     }
6543 
6544     word9 mop9  = (word9) get9 (p -> data, e -> mopPos); // get 9-bit mop
6545     word5 mop   = (mop9 >> 4) & 037;
6546     e->mopIF = mop9 & 0xf;
6547 
6548     MOP_struct *m = &mopTab[mop];
6549     sim_debug (DBG_TRACEEXT, & cpu_dev, "MOP %s(%o) %o\n", m -> mopName, mop, e->mopIF);
6550     e->m = m;
6551     if (e->m == NULL || e->m->f == NULL)
6552     {
6553         sim_debug (DBG_TRACEEXT, & cpu_dev, "getMop(e->m == NULL || e->m->f == NULL): mop:%d IF:%d\n", mop, e->mopIF);
6554         return NULL;
6555     }
6556 
6557     e->mopPos += 1;
6558     e->mopTally -= 1;
6559 
6560     //p->lastAddress = p->address;
6561 
6562     return m;
6563 }
6564 
6565 #if defined(EIS_PTR2)
6566 static void mopExecutor (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6567 #else
6568 static void mopExecutor (cpu_state_t * cpup, int kMop)
6569 #endif
6570   {
6571     EISstruct * e = & cpu.currentEISinstruction;
6572     PNL (L68_ (DU_CYCLE_FEXOP;))
6573 #if defined(EIS_PTR2)
6574     e->mopTally = (int) e->N[KMOP];        // number of micro-ops
6575     e->mopPos   = (int) e->CN[KMOP];        // starting at char pos CN
6576 #else
6577     e->mopAddress = &e->addr[kMop-1];
6578     e->mopTally = (int) e->N[kMop-1];        // number of micro-ops
6579     e->mopPos   = (int) e->CN[kMop-1];        // starting at char pos CN
6580 #endif
6581 
6582     word9 *p9 = e->editInsertionTable; // re-initialize edit insertion table
6583     char *q = defaultEditInsertionTable;
6584     while((*p9++ = (word9) (*q++)))
6585         ;
6586 
6587     e->in = e->inBuffer;    // reset input buffer pointer
6588     e->out = e->outBuffer;  // reset output buffer pointer
6589 
6590     e->_faults = 0; // No faults (yet!)
6591 
6592     // execute dstTally micro operations
6593     // The micro operation sequence is terminated normally when the receiving
6594     // string length becomes exhausted. The micro operation sequence is
6595     // terminated abnormally (with an illegal procedure fault) if a move from
6596     // an exhausted sending string or the use of an exhausted MOP string is
6597     // attempted.
6598 
6599     while (e->dstTally)
6600     {
6601         sim_debug (DBG_TRACEEXT, & cpu_dev,
6602                    "mopExecutor srcTally %d dstTally %d mopTally %d\n",
6603                    e->srcTally, e->dstTally, e->mopTally);
6604         MOP_struct *m = EISgetMop(cpup);
6605         if (! m)
6606           {
6607             sim_debug (DBG_TRACEEXT, & cpu_dev, "mopExecutor EISgetMop forced break\n");
6608             e->_faults |= FAULT_IPR;   // XXX ill proc fault
6609             break;
6610           }
6611         int mres = m->f(cpup);    // execute mop
6612 
6613         // PVS-Studio claims: Expression 'e->_faults & FAULT_IPR' is always false.
6614         if (e->_faults & FAULT_IPR) //-V547
6615             break; // hard IPR raised by a MOP
6616 
6617         // RJ78 specifies "if at completion of a move (L1 exhausted)", AL39
6618         // doesn't define "completion of a move".
6619         // But ISOLTS-845 asserts a case where L1 is NOT exhausted. Therefore I
6620         // assume "L2 exhausted" or "L1 or L2 exhausted" is the correct
6621         // interpretation. Both these options pass ISOLTS-845.
6622         // "L3 exhausted" is also an option but unlikely since that would fire
6623         // the BZ check even upon normal termination.
6624         // XXX DH03 7-295 suggests that there might be a difference between MVE
6625         // and MVNE. It might well be that DPS88/9000 behaves differently than
6626         // DPS8.
6627 
6628 
6629 
6630 
6631 
6632 
6633 
6634         // immediate (L1 or L2) srcTally test
6635         // perhaps more adherent to documentation
6636         if (e->mopTally == 0 || mres)
6637           {
6638             sim_debug (DBG_TRACEEXT, & cpu_dev,
6639                        "mopExecutor N1 or N2 exhausted\n");
6640 
6641             if (e->mopZ && e->mopBZ)
6642               {
6643                 e->out = e->outBuffer; //-V1048  // reset output buffer pointer
6644                 e->dstTally = (int) e->N3;       // number of chars in dst (max 63)
6645                 while (e->dstTally)
6646                   {
6647                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6648                   }
6649               }
6650             else if (mres || e->dstTally) //-V560
6651               { // N1 or N2 exhausted and BZ wasn't enabled
6652                 e->_faults |= FAULT_IPR;
6653               } // otherwise normal termination
6654             break;
6655           }
6656     }
6657 
6658     sim_debug (DBG_TRACEEXT, & cpu_dev, "mop faults %o src %d dst %d mop %d\n",
6659                e->_faults, e->srcTally, e->dstTally, e->mopTally);
6660 
6661 //"The micro-operation sequence is terminated normally when the receiving string
6662 // length is exhausted. The micro-operation sequence is terminated abnormally (with
6663 // an IPR fault) if an attempt is made to move from an exhausted sending string or to
6664 // use an exhausted MOP string.
6665 
6666 // ISOLTS 845 is happy with no check at all
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 
6700 
6701 
6702 
6703 
6704 
6705 
6706 
6707     if (e -> _faults)
6708       doFault (FAULT_IPR, fst_ill_proc, "mopExecutor");
6709 }
6710 
6711 void mve (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6712   {
6713     EISstruct * e = & cpu.currentEISinstruction;
6714 
6715     sim_debug(DBG_TRACEEXT, & cpu_dev, "mve\n");
6716 
6717     fault_ipr_subtype_ mod_fault = 0;
6718 
6719 #if !defined(EIS_SETUP)
6720     setupOperandDescriptor(cpup, 1, &mod_fault);
6721     setupOperandDescriptor(cpup, 2, &mod_fault);
6722     setupOperandDescriptor(cpup, 3, &mod_fault);
6723 #endif
6724 
6725     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
6726     parseAlphanumericOperandDescriptor(cpup, 2, 2, false, &mod_fault);
6727     parseAlphanumericOperandDescriptor(cpup, 3, 3, false, &mod_fault);
6728 
6729     L68_ (
6730       // L68 raises it immediately
6731       if (mod_fault)
6732         {
6733           doFault (FAULT_IPR,
6734                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6735                    "Illegal modifier");
6736         }
6737     )
6738 
6739     // Bits 0, 1, 9, and 10 MBZ
6740     // According to RJ78, bit 9 is T, but is not mentioned in the text.
6741     if (IWB_IRODD & 0600600000000)
6742       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mve: 0, 1, 9, 10 MBZ");
6743 
6744     // Bit 23 of OP1 MBZ
6745     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
6746       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op1 23 MBZ");
6747 
6748 
6749 
6750 
6751 
6752 
6753     // only bit 23 according to RH03. this was fixed in DPS9000
6754     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
6755       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op2 23 MBZ");
6756 
6757     // Bit 23 of OP3 MBZ
6758     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6759       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op3 23 MBZ");
6760 
6761     DPS8M_ (
6762       // DPS8M raises it delayed
6763       if (mod_fault)
6764         {
6765           doFault (FAULT_IPR,
6766                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6767                    "Illegal modifier");
6768         }
6769     )
6770 
6771     // initialize mop flags. Probably best done elsewhere.
6772     e->mopES = false; // End Suppression flag
6773     e->mopSN = false; // Sign flag
6774     e->mopBZ = false; // Blank-when-zero flag
6775     e->mopZ  = true;  // Zero flag
6776 
6777     e->srcTally = (int) e->N1;  // number of chars in src (max 63)
6778     e->dstTally = (int) e->N3;  // number of chars in dst (max 63)
6779 
6780 #if defined(EIS_PTR3)
6781     e->srcTA = (int) TA1;    // type of chars in src
6782 #else
6783     e->srcTA = (int) e->TA1;    // type of chars in src
6784 #endif
6785 
6786     switch (e -> srcTA)
6787       {
6788         case CTA4:
6789           e -> srcSZ = 4;
6790           break;
6791         case CTA6:
6792           e -> srcSZ = 6;
6793           break;
6794         case CTA9:
6795           e -> srcSZ = 9;
6796           break;
6797       }
6798 
6799 #if defined(EIS_PTR3)
6800     uint dstTA = TA3;    // type of chars in dst
6801 #else
6802     uint dstTA = e -> TA3;    // type of chars in dst
6803 #endif
6804 
6805     switch (dstTA)
6806       {
6807         case CTA4:
6808           e -> dstSZ = 4;
6809           break;
6810         case CTA6:
6811           e -> dstSZ = 6;
6812           break;
6813         case CTA9:
6814           e -> dstSZ = 9;
6815           break;
6816       }
6817 
6818     // 1. load sending string into inputBuffer
6819     EISloadInputBufferAlphnumeric (cpup, 1);   // according to MF1
6820 
6821     // 2. Execute micro operation string, starting with first (4-bit) digit.
6822     e -> mvne = false;
6823 
6824 #if defined(EIS_PTR2)
6825     mopExecutor (cpup);
6826 #else
6827     mopExecutor (cpup, 2);
6828 #endif
6829 
6830     e -> dstTally = (int) e -> N3;  // restore dstTally for output
6831 
6832     EISwriteOutputBufferToMemory (cpup, 3);
6833     cleanupOperandDescriptor (cpup, 1);
6834     cleanupOperandDescriptor (cpup, 2);
6835     cleanupOperandDescriptor (cpup, 3);
6836   }
6837 
6838 void mvne (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6839   {
6840     EISstruct * e = & cpu.currentEISinstruction;
6841 
6842     fault_ipr_subtype_ mod_fault = 0;
6843 
6844 #if !defined(EIS_SETUP)
6845     setupOperandDescriptor (cpup, 1, &mod_fault);
6846     setupOperandDescriptor (cpup, 2, &mod_fault);
6847     setupOperandDescriptor (cpup, 3, &mod_fault);
6848 #endif
6849 
6850     parseNumericOperandDescriptor (cpup, 1, &mod_fault);
6851     parseAlphanumericOperandDescriptor (cpup, 2, 2, false, &mod_fault);
6852     parseAlphanumericOperandDescriptor (cpup, 3, 3, false, &mod_fault);
6853 
6854     L68_ (
6855       // L68 raises it immediately
6856       if (mod_fault)
6857         {
6858           doFault (FAULT_IPR,
6859                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6860                    "Illegal modifier");
6861         }
6862     )
6863 
6864     // Bits 0, 1, 9, and 10 MBZ
6865     if (IWB_IRODD & 0600600000000)
6866       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvne: 0, 1, 9, 10 MBZ");
6867 
6868     // Bit 24-29 of OP1 MBZ
6869     // Multics has been observed to use 600162017511, cf RJ78
6870     //if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
6871       //doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op1 24-29 MBZ");
6872 
6873 
6874 
6875 
6876 
6877 
6878     // only bits 21-23 according to RJ78, maybe even less on DPS8
6879     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000070000)
6880       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op2 21-23 MBZ");
6881 
6882 
6883 
6884 
6885 
6886 
6887     // only bit 23 according to RJ78
6888     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6889       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op3 23 MBZ");
6890 
6891     DPS8M_ (
6892       // DPS8M raises it delayed
6893       if (mod_fault)
6894         {
6895           doFault (FAULT_IPR,
6896                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6897                    "Illegal modifier");
6898         }
6899     )
6900 
6901     uint srcTN = e -> TN1;    // type of chars in src
6902 
6903     int n1 = 0;
6904 
6905     /*
6906      * Here we need to distinguish between 4 type of numbers.
6907      *
6908      * CSFL - Floating-point, leading sign
6909      * CSLS - Scaled fixed-point, leading sign
6910      * CSTS - Scaled fixed-point, trailing sign
6911      * CSNS - Scaled fixed-point, unsigned
6912      */
6913 
6914     // determine precision
6915     switch(e->S1)
6916     {
6917         case CSFL:
6918             n1 = (int) e->N1 - 1; // need to account for the - sign
6919             if (srcTN == CTN4)
6920                 n1 -= 2;    // 2 4-bit digits exponent
6921             else
6922                 n1 -= 1;    // 1 9-bit digit exponent
6923             break;
6924 
6925         case CSLS:
6926         case CSTS:
6927             n1 = (int) e->N1 - 1; // only 1 sign
6928             break;
6929 
6930         case CSNS:
6931             n1 = (int) e->N1;     // no sign
6932             break;  // no sign wysiwyg
6933     }
6934 
6935     if (n1 < 1)
6936         doFault (FAULT_IPR, fst_ill_proc, "mvne adjusted n1<1");
6937 
6938     // Putting this check in pAOD breaks Multics boot
6939     // From DH03 it seems that DPS8 does not check this explicitly, but L2 exhaust occurs which raises IPR anyway
6940     // So we may as well keep it here.
6941     if (e->N[1] == 0)
6942       doFault (FAULT_IPR, fst_ill_proc, "mvne N2 0");
6943 
6944     // this is a flaw in DPS8/70 which was corrected in DPS88 and later
6945     // ISOLTS-841 07h, RH03 p.7-295
6946     if (e->N[2] == 0)
6947       doFault (FAULT_IPR, fst_ill_proc, "mvne N3 0");
6948 
6949 //if ((e -> op [0]  & 0000000007700) ||
6950 //    (e -> op [1]  & 0000000077700) ||
6951 //    (e -> op [2]  & 0000000017700))
6952 //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]);
6953 //if (e -> op [0]  & 0000000007700) sim_printf ("op1\n");
6954 //if (e -> op [1]  & 0000000077700) sim_printf ("op2\n");
6955 //if (e -> op [2]  & 0000000017700) sim_printf ("op3\n");
6956 //000140  aa  100 004 024 500   mvne      (pr),(ic),(pr)
6957 //000141  aa  6 00162 01 7511   desc9ls   pr6|114,9,-3
6958 //000142  aa   000236 00 0007   desc9a    158,7               000376 = 403040144040
6959 //000143  aa  6 00134 00 0012   desc9a    pr6|92,10           vcpu
6960 //
6961 // The desc8ls is sign-extending the -3.
6962 
6963     // initialize mop flags. Probably best done elsewhere.
6964     e->mopES = false; // End Suppression flag
6965     e->mopSN = false; // Sign flag
6966     e->mopBZ = false; // Blank-when-zero flag
6967     e->mopZ  = true;  // Zero flag
6968 
6969     e -> srcTally = (int) e -> N1;  // number of chars in src (max 63)
6970     e -> dstTally = (int) e -> N3;  // number of chars in dst (max 63)
6971 
6972 // XXX Temp hack to get MOP to work. Merge TA/TN?
6973 // The MOP operators look at srcTA to make 9bit/not 9-bit decisions about
6974 // the contents of inBuffer; parseNumericOperandDescriptor(cpup, ) always puts
6975 // 4 bit data in inBuffer, so signal the MOPS code of that.
6976     e->srcTA = CTA4;    // type of chars in src
6977 
6978     switch(srcTN)
6979     {
6980         case CTN4:
6981             //e->srcAddr = e->YChar41;
6982             e->srcSZ = 4; //-V1037  // stored as 4-bit decimals
6983             break;
6984         case CTN9:
6985             //e->srcAddr = e->YChar91;
6986             e->srcSZ = 4; //-V1037  // 'cause everything is stored as 4-bit decimals
6987             break;
6988     }
6989 
6990 #if defined(EIS_PTR3)
6991     uint dstTA = TA3;     // type of chars in dst
6992 #else
6993     uint dstTA = e->TA3;  // type of chars in dst
6994 #endif
6995     switch(dstTA)
6996     {
6997         case CTA4:
6998             //e->dstAddr = e->YChar43;
6999             e->dstSZ = 4;
7000             break;
7001         case CTA6:
7002             //e->dstAddr = e->YChar63;
7003             e->dstSZ = 6;
7004             break;
7005         case CTA9:
7006             //e->dstAddr = e->YChar93;
7007             e->dstSZ = 9;
7008             break;
7009     }
7010 
7011 #if defined(EIS_PTR3)
7012     sim_debug (DBG_TRACEEXT, & cpu_dev,
7013       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
7014       e->N1, e->N2, e->N3, e->TN1, e->CN1, TA3, e->CN3);
7015 #else
7016     sim_debug (DBG_TRACEEXT, & cpu_dev,
7017       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\n",
7018       e->N1, e->N2, e->N3, e->TN1, e->CN1, e->TA3, e->CN3);
7019 #endif
7020 
7021     // 1. load sending string into inputBuffer
7022     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7023 
7024     // 2. Test sign and, if required, set the SN flag. (Sign flag; initially
7025     // set OFF if the sending string has an alphanumeric descriptor or an
7026     // unsigned numeric descriptor. If the sending string has a signed numeric
7027     // descriptor, the sign is initially read from the sending string from the
7028     // digit position defined by the sign and the decimal type field (S); SN is
7029     // set OFF if positive, ON if negative. If all digits are zero, the data is
7030     // assumed positive and the SN flag is set OFF, even when the sign is
7031     // negative.)
7032 
7033     int sum = 0;
7034     for(int n = 0 ; n < e -> srcTally ; n ++)
7035         sum += e -> inBuffer [n];
7036     if ((e -> sign == -1) && sum)
7037         e -> mopSN = true;
7038 
7039     // 3. Execute micro operation string, starting with first (4-bit) digit.
7040     e -> mvne = true;
7041 
7042 #if defined(EIS_PTR2)
7043     mopExecutor (cpup);
7044 #else
7045     mopExecutor (cpup, 2);
7046 #endif
7047 
7048     e -> dstTally = (int) e -> N3;  // restore dstTally for output
7049 
7050     EISwriteOutputBufferToMemory (cpup, 3);
7051     cleanupOperandDescriptor (cpup, 1);
7052     cleanupOperandDescriptor (cpup, 2);
7053     cleanupOperandDescriptor (cpup, 3);
7054   }
7055 
7056 /*
7057  * MVT - Move Alphanumeric with Translation
7058  */
7059 
7060 void mvt (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7061   {
7062     EISstruct * e = & cpu.currentEISinstruction;
7063 
7064     // For i = 1, 2, ..., minimum (N1,N2)
7065     //    m = C(Y-charn1)i-1
7066     //    C(Y-char93)m → C(Y-charn2)i-1
7067     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7068     //    m = C(FILL)
7069     //    C(Y-char93)m → C(Y-charn2)i-1
7070 
7071     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
7072 
7073     fault_ipr_subtype_ mod_fault = 0;
7074 
7075 #if !defined(EIS_SETUP)
7076     setupOperandDescriptor (cpup, 1, &mod_fault);
7077     setupOperandDescriptor (cpup, 2, &mod_fault);
7078     setupOperandDescriptorCache (cpup,3);
7079 #endif
7080 
7081     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
7082     parseAlphanumericOperandDescriptor (cpup, 2, 2, false, &mod_fault);
7083     parseArgOperandDescriptor (cpup, 3, &mod_fault);
7084 
7085     L68_ (
7086       // L68 raises it immediately
7087       if (mod_fault)
7088         {
7089           doFault (FAULT_IPR,
7090                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7091                    "Illegal modifier");
7092         }
7093     )
7094 
7095 // ISOLTS 808 test-03b sets bit 0, 1
7096 // ISOLTS 808 test-03b sets bit 0, 1, 9
7097 
7098     // Bits 10 MBZ
7099     if (IWB_IRODD & 0000200000000)
7100       {
7101         //sim_printf ("mvt %012"PRIo64"\n", IWB_IRODD);
7102         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvt 10 MBZ");
7103       }
7104 
7105 
7106 
7107 
7108 
7109 
7110 
7111 
7112 
7113     // Bit 23 of OP1 MBZ
7114     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
7115       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op1 23 MBZ");
7116 
7117 // This breaks eis_tester mvt 110
7118 
7119 
7120 
7121 
7122 
7123 
7124     // Bits 18-28 of OP3 MBZ
7125     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777600)
7126       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op3 18-28 MBZ");
7127 
7128     DPS8M_ (
7129       // DPS8M raises it delayed
7130       if (mod_fault)
7131         {
7132           doFault (FAULT_IPR,
7133                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7134                    "Illegal modifier");
7135         }
7136     )
7137 
7138 #if defined(EIS_PTR3)
7139     e->srcTA = (int) TA1;
7140     uint dstTA = TA2;
7141 
7142     switch (TA1)
7143 #else
7144     e->srcTA = (int) e->TA1;
7145     uint dstTA = e->TA2;
7146 
7147     switch (e -> TA1)
7148 #endif
7149       {
7150         case CTA4:
7151           e -> srcSZ = 4;
7152           break;
7153         case CTA6:
7154           e -> srcSZ = 6;
7155           break;
7156         case CTA9:
7157           e -> srcSZ = 9;
7158          break;
7159       }
7160 
7161 #if defined(EIS_PTR3)
7162     switch (TA2)
7163 #else
7164     switch (e -> TA2)
7165 #endif
7166       {
7167         case CTA4:
7168           e -> dstSZ = 4;
7169           break;
7170         case CTA6:
7171           e -> dstSZ = 6;
7172           break;
7173         case CTA9:
7174           e -> dstSZ = 9;
7175           break;
7176       }
7177 
7178     //  Prepage Check in a Multiword Instruction
7179     //  The MVT, TCT, TCTR, and CMPCT instruction have a prepage check. The
7180     //  size of the translate table is determined by the TA1 data type as shown
7181     //  in the table below. Before the instruction is executed, a check is made
7182     //  for allocation in memory for the page for the translate table. If the
7183     //  page is not in memory, a Missing Page fault occurs before execution of
7184     //  the instruction. (Bull RJ78 p.7-75)
7185 
7186     // TA1              TRANSLATE TABLE SIZE
7187     // 4-BIT CHARACTER      4 WORDS
7188     // 6-BIT CHARACTER     16 WORDS
7189     // 9-BIT CHARACTER    128 WORDS
7190 
7191     uint xlatSize = 0;   // size of xlation table in words .....
7192 #if defined(EIS_PTR3)
7193     switch(TA1)
7194 #else
7195     switch(e->TA1)
7196 #endif
7197     {
7198         case CTA4:
7199             xlatSize = 4;
7200             break;
7201         case CTA6:
7202             xlatSize = 16;
7203             break;
7204         case CTA9:
7205             xlatSize = 128;
7206             break;
7207     }
7208 
7209 
7210 
7211 
7212 
7213 
7214 
7215 
7216 
7217     // ISOLTS 878 01c - op1 and xlate table are prepaged, in that order
7218     // prepage op1
7219     int lastpageidx = ((int)e->N1 + (int)e->CN1 -1) / e->srcSZ;
7220     if (lastpageidx>0)
7221         EISReadIdx(cpup, &e->ADDR1, (uint)lastpageidx);
7222     // prepage xlate table
7223     if (xlatSize > 0)
7224     {
7225         EISReadIdx(cpup, &e->ADDR3, 0);
7226         EISReadIdx(cpup, &e->ADDR3, xlatSize-1);
7227     }
7228 
7229     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7230 
7231     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
7232     word9 fillT = fill;  // possibly truncated fill pattern
7233     // play with fill if we need to use it
7234     switch(e->srcSZ)
7235     {
7236         case 4:
7237             fillT = fill & 017;    // truncate upper 5-bits
7238             break;
7239         case 6:
7240             fillT = fill & 077;    // truncate upper 3-bits
7241             break;
7242     }
7243 
7244     sim_debug (DBG_TRACEEXT, & cpu_dev,
7245       "%s srcCN:%d dstCN:%d srcSZ:%d dstSZ:%d T:%d fill:%03o/%03o N1:%d N2:%d\n",
7246       __func__, e -> CN1, e -> CN2, e -> srcSZ, e -> dstSZ, T,
7247       fill, fillT, e -> N1, e -> N2);
7248 
7249     PNL (L68_ (if (max (e->N1, e->N2) < 128)
7250       DU_CYCLE_FLEN_128;))
7251 
7252     for ( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY ++)
7253     {
7254         word9 c = EISget469(cpup, 1, cpu.du.CHTALLY); // get src char
7255         int cidx = 0;
7256 
7257 #if defined(EIS_PTR3)
7258         if (TA1 == TA2)
7259 #else
7260         if (e->TA1 == e->TA2)
7261 #endif
7262             EISput469(cpup, 2, cpu.du.CHTALLY, xlate (cpup, &e->ADDR3, dstTA, c));
7263         else
7264         {
7265             // If data types are dissimilar (TA1 ≠ TA2), each character is high-order
7266             //   truncated or zero filled, as appropriate, as it is moved.
7267             //   No character conversion takes place.
7268             cidx = c;
7269 
7270             word9 cout = xlate(cpup, &e->ADDR3, dstTA, (uint) cidx);
7271 
7272 //            switch(e->dstSZ)
7273 //            {
7274 //                case 4:
7275 //                    cout &= 017;    // truncate upper 5-bits
7276 //                    break;
7277 //                case 6:
7278 //                    cout &= 077;    // truncate upper 3-bits
7279 //                    break;
7280 //            }
7281 
7282             switch (e->srcSZ)
7283             {
7284                 case 6:
7285                     switch(e->dstSZ)
7286                     {
7287                         case 4:
7288                             cout &= 017;    // truncate upper 2-bits
7289                             break;
7290                         case 9:
7291                             break;              // should already be 0-filled
7292                     }
7293                     break;
7294                 case 9:
7295                     switch(e->dstSZ)
7296                     {
7297                         case 4:
7298                             cout &= 017;    // truncate upper 5-bits
7299                             break;
7300                         case 6:
7301                             cout &= 077;    // truncate upper 3-bits
7302                             break;
7303                     }
7304                     break;
7305             }
7306 
7307             EISput469 (cpup, 2, cpu.du.CHTALLY, cout);
7308         }
7309     }
7310 
7311     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7312     //    m = C(FILL)
7313     //    C(Y-char93)m → C(Y-charn2)N2-i
7314 
7315     if (e->N1 < e->N2)
7316     {
7317         word9 cfill = xlate(cpup, &e->ADDR3, dstTA, fillT);
7318         switch (e->srcSZ)
7319         {
7320             case 6:
7321                 switch(e->dstSZ)
7322                 {
7323                     case 4:
7324                         cfill &= 017;    // truncate upper 2-bits
7325                         break;
7326                     case 9:
7327                         break;              // should already be 0-filled
7328                 }
7329                 break;
7330             case 9:
7331                 switch(e->dstSZ)
7332                 {
7333                     case 4:
7334                         cfill &= 017;    // truncate upper 5-bits
7335                         break;
7336                     case 6:
7337                         cfill &= 077;    // truncate upper 3-bits
7338                         break;
7339                 }
7340                 break;
7341         }
7342 
7343         for( ; cpu.du.CHTALLY < e->N2 ; cpu.du.CHTALLY ++)
7344             EISput469 (cpup, 2, cpu.du.CHTALLY, cfill);
7345     }
7346 
7347     cleanupOperandDescriptor (cpup, 1);
7348     cleanupOperandDescriptor (cpup, 2);
7349     cleanupOperandDescriptor (cpup, 3);
7350 
7351     if (e->N1 > e->N2)
7352       {
7353         SET_I_TRUNC;
7354         if (T && ! TST_I_OMASK)
7355           doFault(FAULT_OFL, fst_zero, "mvt truncation fault");
7356       }
7357     else
7358       CLR_I_TRUNC;
7359   }
7360 
7361 /*
7362  * cmpn - Compare Numeric
7363  */
7364 
7365 void cmpn (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7366 {
7367     EISstruct * e = & cpu.currentEISinstruction;
7368 
7369     // C(Y-charn1) :: C(Y-charn2) as numeric values
7370 
7371     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7372     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7373     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7374 
7375     fault_ipr_subtype_ mod_fault = 0;
7376 
7377 #if !defined(EIS_SETUP)
7378     setupOperandDescriptor(cpup, 1, &mod_fault);
7379     setupOperandDescriptor(cpup, 2, &mod_fault);
7380 #endif
7381 
7382     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
7383     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
7384 
7385     L68_ (
7386       // L68 raises it immediately
7387       if (mod_fault)
7388         {
7389           doFault (FAULT_IPR,
7390                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7391                    "Illegal modifier");
7392         }
7393     )
7394 
7395     // Bits 0-10 MBZ
7396     if (IWB_IRODD & 0777600000000)
7397       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpn 0-10 MBZ");
7398 
7399     DPS8M_ (
7400       // DPS8M raises it delayed
7401       if (mod_fault)
7402         {
7403           doFault (FAULT_IPR,
7404                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7405                    "Illegal modifier");
7406         }
7407     )
7408 
7409     uint srcTN = e->TN1;    // type of chars in src
7410 
7411     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
7412 
7413     /*
7414      * Here we need to distinguish between 4 type of numbers.
7415      *
7416      * CSFL - Floating-point, leading sign
7417      * CSLS - Scaled fixed-point, leading sign
7418      * CSTS - Scaled fixed-point, trailing sign
7419      * CSNS - Scaled fixed-point, unsigned
7420      */
7421 
7422     // determine precision
7423     switch(e->S1)
7424     {
7425         case CSFL:
7426             n1 = (int) e->N1 - 1; // need to account for the - sign
7427             if (srcTN == CTN4)
7428                 n1 -= 2;    // 2 4-bit digits exponent
7429             else
7430                 n1 -= 1;    // 1 9-bit digit exponent
7431             sc1 = 0;        // no scaling factor
7432             break;
7433 
7434         case CSLS:
7435         case CSTS:
7436             n1 = (int) e->N1 - 1; // only 1 sign
7437             sc1 = -e->SF1;
7438             break;
7439 
7440         case CSNS:
7441             n1 = (int) e->N1;     // no sign
7442             sc1 = -e->SF1;
7443             break;  // no sign wysiwyg
7444     }
7445 
7446     if (n1 < 1)
7447         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n1<1");
7448 
7449     switch(e->S2)
7450     {
7451         case CSFL:
7452             n2 = (int) e->N2 - 1; // need to account for the sign
7453             if (e->TN2 == CTN4)
7454                 n2 -= 2;    // 2 4-bit digit exponent
7455             else
7456                 n2 -= 1;    // 1 9-bit digit exponent
7457             sc2 = 0;        // no scaling factor
7458             break;
7459 
7460         case CSLS:
7461         case CSTS:
7462             n2 = (int) e->N2 - 1; // 1 sign
7463             sc2 = -e->SF2;
7464             break;
7465 
7466         case CSNS:
7467             n2 = (int) e->N2;     // no sign
7468             sc2 = -e->SF2;
7469             break;  // no sign wysiwyg
7470     }
7471 
7472     if (n2 < 1)
7473         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n2<1");
7474 
7475     decContext set;
7476     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
7477     decContextDefaultDPS8(&set);
7478 
7479     set.traps=0;
7480 
7481     decNumber _1, _2, _3;
7482 
7483     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7484 
7485     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
7486     if (e->sign == -1)
7487         op1->bits |= DECNEG;
7488     if (e->S1 == CSFL)
7489         op1->exponent = e->exponent;
7490 
7491     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
7492 
7493     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
7494     if (e->sign == -1)
7495         op2->bits |= DECNEG;
7496     if (e->S2 == CSFL)
7497         op2->exponent = e->exponent;
7498 
7499     // signed-compare
7500     decNumber *cmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7501     int cSigned = decNumberToInt32(cmp, &set);
7502 
7503     // take absolute value of operands
7504     op1 = decNumberAbs(op1, op1, &set);
7505     op2 = decNumberAbs(op2, op2, &set);
7506 
7507     // magnitude-compare
7508     decNumber *mcmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7509     int cMag = decNumberToInt32(mcmp, &set);
7510 
7511     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7512     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7513     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7514 
7515     SC_I_ZERO (cSigned == 0);
7516     SC_I_NEG (cSigned == 1);
7517     SC_I_CARRY (cMag != 1);
7518 
7519     cleanupOperandDescriptor (cpup, 1);
7520     cleanupOperandDescriptor (cpup, 2);
7521 }
7522 
7523 /*
7524  * mvn - move numeric (initial version was deleted by house gnomes)
7525  */
7526 
7527 /*
7528  * write 4-bit chars to memory @ pos ...
7529  */
7530 
7531 static void EISwrite4(cpu_state_t * cpup, EISaddr *p, int *pos, word4 char4)
     /* [previous][next][first][last][top][bottom][index][help] */
7532 {
7533     word36 w;
7534     if (*pos > 7)    // out-of-range?
7535     {
7536         *pos = 0;    // reset to 1st byte
7537 #if defined(EIS_PTR)
7538         long eisaddr_idx = EISADDR_IDX (p);
7539 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7540         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7541 #else
7542         p->address = (p->address + 1) & AMASK;        // goto next dstAddr in memory
7543 #endif
7544     }
7545 
7546     w = EISRead(cpup, p);      // read dst memory into w
7547 
7548 // AL39, Figure 2-3
7549     switch (*pos)
7550     {
7551         case 0:
7552             //w = bitfieldInsert36(w, char4, 31, 5);
7553             w = setbits36_4 (w, 1, char4);
7554             break;
7555         case 1:
7556             //w = bitfieldInsert36(w, char4, 27, 4);
7557             w = setbits36_4 (w, 5, char4);
7558             break;
7559         case 2:
7560             //w = bitfieldInsert36(w, char4, 22, 5);
7561             w = setbits36_4 (w, 10, char4);
7562             break;
7563         case 3:
7564             //w = bitfieldInsert36(w, char4, 18, 4);
7565             w = setbits36_4 (w, 14, char4);
7566             break;
7567         case 4:
7568             //w = bitfieldInsert36(w, char4, 13, 5);
7569             w = setbits36_4 (w, 19, char4);
7570             break;
7571         case 5:
7572             //w = bitfieldInsert36(w, char4, 9, 4);
7573             w = setbits36_4 (w, 23, char4);
7574             break;
7575         case 6:
7576             //w = bitfieldInsert36(w, char4, 4, 5);
7577             w = setbits36_4 (w, 28, char4);
7578             break;
7579         case 7:
7580             //w = bitfieldInsert36(w, char4, 0, 4);
7581             w = setbits36_4 (w, 32, char4);
7582             break;
7583     }
7584 
7585     EISWriteIdx(cpup, p, 0, w, true); // XXX this is the inefficient part!
7586 
7587     *pos += 1;       // to next char.
7588 }
7589 
7590 /*
7591  * write 9-bit bytes to memory @ pos ...
7592  */
7593 
7594 static void EISwrite9(cpu_state_t *cpup, EISaddr *p, int *pos, word9 char9)
     /* [previous][next][first][last][top][bottom][index][help] */
7595 {
7596     word36 w;
7597     if (*pos > 3)    // out-of-range?
7598     {
7599         *pos = 0;    // reset to 1st byte
7600 #if defined(EIS_PTR)
7601         long eisaddr_idx = EISADDR_IDX (p);
7602 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7603         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7604 #else
7605         p->address = (p->address + 1) & AMASK;       // goto next dstAddr in memory
7606 #endif
7607     }
7608 
7609     w = EISRead(cpup, p);      // read dst memory into w
7610 
7611 // AL39, Figure 2-5
7612     switch (*pos)
7613     {
7614         case 0:
7615             //w = bitfieldInsert36(w, char9, 27, 9);
7616             w = setbits36_9 (w, 0, char9);
7617             break;
7618         case 1:
7619             //w = bitfieldInsert36(w, char9, 18, 9);
7620             w = setbits36_9 (w, 9, char9);
7621             break;
7622         case 2:
7623             //w = bitfieldInsert36(w, char9, 9, 9);
7624             w = setbits36_9 (w, 18, char9);
7625             break;
7626         case 3:
7627             //w = bitfieldInsert36(w, char9, 0, 9);
7628             w = setbits36_9 (w, 27, char9);
7629             break;
7630     }
7631 
7632     EISWriteIdx (cpup, p, 0, w, true); // XXX this is the inefficient part!
7633 
7634     *pos += 1;       // to next byte.
7635 }
7636 
7637 /*
7638  * write a 4-, or 9-bit numeric char to dstAddr ....
7639  */
7640 
7641 static void EISwrite49(cpu_state_t * cpup, EISaddr *p, int *pos, int tn, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
7642 {
7643     switch(tn)
7644     {
7645         case CTN4:
7646             EISwrite4(cpup, p, pos, (word4) c49);
7647             return;
7648         case CTN9:
7649             EISwrite9(cpup, p, pos, c49);
7650             return;
7651     }
7652 }
7653 
7654 void mvn (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7655 {
7656     /*
7657      * EXPLANATION:
7658      * Starting at location YC1, the decimal number of data type TN1 and sign
7659      * and decimal type S1 is moved, properly scaled, to the decimal number of
7660      * data type TN2 and sign and decimal type S2 that starts at location YC2.
7661      * If S2 indicates a fixed-point format, the results are stored as L2
7662      * digits using scale factor SF2, and thereby may cause
7663      * most-significant-digit overflow and/or least- significant-digit
7664      * truncation.
7665      * If P = 1, positive signed 4-bit results are stored using octal 13 as the
7666      * plus sign. Rounding is legal for both fixed-point and floating-point
7667      * formats. If P = 0, positive signed 4-bit results are stored using octal
7668      * 14 as the plus sign.
7669      * Provided that string 1 and string 2 are not overlapped, the contents of
7670      * the decimal number that starts in location YC1 remain unchanged.
7671      */
7672 
7673     EISstruct * e = & cpu.currentEISinstruction;
7674 
7675     fault_ipr_subtype_ mod_fault = 0;
7676 
7677 #if !defined(EIS_SETUP)
7678     setupOperandDescriptor(cpup, 1, &mod_fault);
7679     setupOperandDescriptor(cpup, 2, &mod_fault);
7680 #endif
7681 
7682     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
7683     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
7684 
7685     L68_ (
7686       // L68 raises it immediately
7687       if (mod_fault)
7688         {
7689           doFault (FAULT_IPR,
7690                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7691                    "Illegal modifier");
7692         }
7693     )
7694 
7695     // Bits 2-8 MBZ
7696     if (IWB_IRODD & 0377000000000)
7697      doFault (FAULT_IPR,
7698               (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault},
7699               "mvn 2-8 MBZ");
7700 
7701     DPS8M_ (
7702       // DPS8M raises it delayed
7703       if (mod_fault)
7704         {
7705           doFault (FAULT_IPR,
7706                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7707                    "Illegal modifier");
7708         }
7709     )
7710 
7711     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character
7712                                               //  control
7713     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7714     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
7715     PNL (L68_ (if (R)
7716       DU_CYCLE_FRND;))
7717 
7718     uint srcTN = e->TN1;    // type of chars in src
7719 
7720     uint dstTN = e->TN2;    // type of chars in dst
7721     uint dstCN = e->CN2;    // starting at char pos CN
7722 
7723     sim_debug (DBG_CAC, & cpu_dev,
7724                "mvn(1): TN1 %d CN1 %d N1 %d TN2 %d CN2 %d N2 %d\n",
7725                e->TN1, e->CN1, e->N1, e->TN2, e->CN2, e->N2);
7726     sim_debug (DBG_CAC, & cpu_dev,
7727                "mvn(2): SF1 %d              SF2 %d\n",
7728                e->SF1, e->SF2);
7729     sim_debug (DBG_CAC, & cpu_dev,
7730                "mvn(3): OP1 %012"PRIo64" OP2 %012"PRIo64"\n",
7731                e->OP1, e->OP2);
7732 
7733     int n1 = 0, n2 = 0, sc1 = 0;
7734 
7735     /*
7736      * Here we need to distinguish between 4 type of numbers.
7737      *
7738      * CSFL - Floating-point, leading sign
7739      * CSLS - Scaled fixed-point, leading sign
7740      * CSTS - Scaled fixed-point, trailing sign
7741      * CSNS - Scaled fixed-point, unsigned
7742      */
7743 
7744     // determine precision
7745     switch(e->S1)
7746     {
7747         case CSFL:
7748             n1 = (int) e->N1 - 1; // need to account for the - sign
7749             if (srcTN == CTN4)
7750                 n1 -= 2;    // 2 4-bit digits exponent
7751             else
7752                 n1 -= 1;    // 1 9-bit digit exponent
7753             sc1 = 0;        // no scaling factor
7754             break;
7755 
7756         case CSLS:
7757         case CSTS:
7758             n1 = (int) e->N1 - 1; // only 1 sign
7759             sc1 = -e->SF1;
7760             break;
7761 
7762         case CSNS:
7763             n1 = (int) e->N1;     // no sign
7764             sc1 = -e->SF1;
7765             break;  // no sign wysiwyg
7766     }
7767 
7768     sim_debug (DBG_CAC, & cpu_dev, "n1 %d sc1 %d\n", n1, sc1);
7769 
7770     // RJ78: An Illegal Procedure fault occurs if:
7771     // The values for the number of characters (N1 or N2) of the data
7772     // descriptors are not large enough to hold the number of characters
7773     // required for the specified sign and/or exponent, plus at least one
7774     // digit.
7775 
7776     if (n1 < 1)
7777         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n1<1");
7778 
7779     switch(e->S2)
7780     {
7781         case CSFL:
7782             n2 = (int) e->N2 - 1; // need to account for the sign
7783             if (dstTN == CTN4)
7784                 n2 -= 2;    // 2 4-bit digit exponent
7785             else
7786                 n2 -= 1;    // 1 9-bit digit exponent
7787             break;
7788 
7789         case CSLS:
7790         case CSTS:
7791             n2 = (int) e->N2 - 1; // 1 sign
7792             break;
7793 
7794         case CSNS:
7795             n2 = (int) e->N2;     // no sign
7796             break;          // no sign wysiwyg
7797     }
7798 
7799     sim_debug (DBG_CAC, & cpu_dev, "n2 %d\n", n2);
7800 
7801     if (n2 < 1)
7802         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n2<1");
7803 
7804     decContext set;
7805     decContextDefaultDPS8(&set);
7806     set.traps=0;
7807 
7808     decNumber _1;
7809 
7810     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7811 
7812     decNumber *op1 = decBCD9ToNumber (e->inBuffer, n1, sc1, &_1);
7813 
7814     if (e->sign == -1)
7815         op1->bits |= DECNEG;
7816     if (e->S1 == CSFL)
7817         op1->exponent = e->exponent;
7818     if (decNumberIsZero (op1))
7819         op1->exponent = 127;
7820 
7821     if_sim_debug (DBG_CAC, & cpu_dev)
7822     {
7823         PRINTDEC ("mvn input (op1)", op1);
7824     }
7825 
7826     bool Ovr = false, EOvr = false, Trunc = false;
7827 
7828     uint8_t out [256];
7829     char * res = formatDecimal (out, & set, op1, n2, (int) e->S2, e->SF2, R,
7830                                 & Ovr, & Trunc);
7831 
7832     sim_debug (DBG_CAC, & cpu_dev, "mvn res: '%s'\n", res);
7833 
7834     // now write to memory in proper format.....
7835 
7836     //word18 dstAddr = e->dstAddr;
7837     int pos = (int) dstCN;
7838 
7839     // 1st, take care of any leading sign .......
7840     switch(e->S2)
7841     {
7842         case CSFL:  // floating-point, leading sign.
7843         case CSLS:  // fixed-point, leading sign
7844             switch(dstTN)
7845             {
7846                 case CTN4:
7847  // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7848  // sign character is placed appropriately if the result of the operation is
7849  // positive.
7850                     if (e->P)
7851                         // special +
7852                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7853                                    (decNumberIsNegative (op1) &&
7854                                     ! decNumberIsZero(op1)) ? 015 : 013);
7855                     else
7856                         // default +
7857                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7858                                     (decNumberIsNegative (op1) &&
7859                                      ! decNumberIsZero (op1)) ? 015 : 014);
7860                     break;
7861                 case CTN9:
7862                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7863                                 (decNumberIsNegative (op1) &&
7864                                  ! decNumberIsZero (op1)) ? '-' : '+');
7865                     break;
7866             }
7867             break;
7868 
7869         case CSTS:  // nuttin' to do here .....
7870         case CSNS:
7871             break;  // no sign wysiwyg
7872     }
7873 
7874     // 2nd, write the digits .....
7875     for (int i = 0 ; i < n2 ; i ++)
7876         switch (dstTN)
7877         {
7878             case CTN4:
7879                 EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7880                             (word9) (res[i] - '0'));
7881                 break;
7882             case CTN9:
7883                 EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN, (word9) res[i]);
7884                 break;
7885         }
7886 
7887     // 3rd, take care of any trailing sign or exponent ...
7888     switch(e->S2)
7889     {
7890         case CSTS:  // write trailing sign ....
7891             switch(dstTN)
7892             {
7893                 case CTN4:
7894 // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7895 // sign character is placed appropriately if the result of the operation is
7896 // positive.
7897                     if (e->P)
7898                         // special +
7899                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7900                                     (decNumberIsNegative (op1) &&
7901                                      ! decNumberIsZero(op1)) ? 015 :  013);
7902                     else
7903                         // default +
7904                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7905                                     (decNumberIsNegative (op1) &&
7906                                      ! decNumberIsZero (op1)) ? 015 :  014);
7907                     break;
7908 
7909                 case CTN9:
7910                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7911                                 (decNumberIsNegative (op1) &&
7912                                  ! decNumberIsZero(op1)) ? '-' : '+');
7913                     break;
7914             }
7915             break;
7916 
7917         case CSFL:  // floating-point, leading sign.
7918             // write the exponent
7919             switch(dstTN)
7920             {
7921                 case CTN4:
7922                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7923                                 (op1->exponent >> 4) & 0xf); // upper 4-bits
7924                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7925                                 op1->exponent       & 0xf); // lower 4-bits
7926                     break;
7927                 case CTN9:
7928                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7929                                  op1->exponent & 0xff); // write 8-bit exponent
7930                 break;
7931             }
7932             break;
7933 
7934         case CSLS:  // fixed point, leading sign - already done
7935         case CSNS:  // fixed point, unsigned - nuttin' needed to do
7936             break;
7937     }
7938 
7939     // set flags, etc ...
7940     if (e->S2 == CSFL)
7941     {
7942         if (op1->exponent > 127)
7943         {
7944             SET_I_EOFL;
7945             EOvr = true;
7946         }
7947         if (op1->exponent < -128)
7948         {
7949             SET_I_EUFL;
7950             EOvr = true;
7951         }
7952     }
7953 
7954 sim_debug (DBG_CAC, & cpu_dev, "is neg %o\n", decNumberIsNegative(op1));
7955 sim_debug (DBG_CAC, & cpu_dev, "is zero %o\n", decNumberIsZero(op1));
7956 sim_debug (DBG_CAC, & cpu_dev, "R %o\n", R);
7957 sim_debug (DBG_CAC, & cpu_dev, "Trunc %o\n", Trunc);
7958 sim_debug (DBG_CAC, & cpu_dev, "TRUNC %o\n", TST_I_TRUNC);
7959 sim_debug (DBG_CAC, & cpu_dev, "OMASK %o\n", TST_I_OMASK);
7960 sim_debug (DBG_CAC, & cpu_dev, "tstOVFfault %o\n", tstOVFfault (cpup));
7961 sim_debug (DBG_CAC, & cpu_dev, "T %o\n", T);
7962 sim_debug (DBG_CAC, & cpu_dev, "EOvr %o\n", EOvr);
7963 sim_debug (DBG_CAC, & cpu_dev, "Ovr %o\n", Ovr);
7964     // set negative indicator if op3 < 0
7965     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));
7966 
7967     // set zero indicator if op3 == 0
7968     SC_I_ZERO (decNumberIsZero(op1));
7969 
7970     // If the truncation condition exists without rounding, then ON;
7971     // otherwise OFF
7972     SC_I_TRUNC (!R && Trunc);
7973 
7974     cleanupOperandDescriptor (cpup, 1);
7975     cleanupOperandDescriptor (cpup, 2);
7976 
7977     if (TST_I_TRUNC && T && tstOVFfault (cpup))
7978         doFault (FAULT_OFL, fst_zero, "mvn truncation(overflow) fault");
7979     if (EOvr && tstOVFfault (cpup))
7980         doFault (FAULT_OFL, fst_zero, "mvn over/underflow fault");
7981     if (Ovr)
7982     {
7983         SET_I_OFLOW;
7984         if (tstOVFfault (cpup))
7985           doFault (FAULT_OFL, fst_zero, "mvn overflow fault");
7986     }
7987 }
7988 
7989 void csl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7990   {
7991     EISstruct * e = & cpu.currentEISinstruction;
7992 
7993     // For i = bits 1, 2, ..., minimum (N1,N2)
7994     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
7995     //   C(BOLR)m → C(Y-bit2)i-1
7996     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
7997     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
7998     //   C(BOLR)m → C(Y-bit2)i-1
7999     //
8000     // INDICATORS: (Indicators not listed are not affected)
8001     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8002     //     Truncation If N1 > N2, then ON; otherwise OFF
8003     //
8004     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8005     // processed and the truncation indicator is set ON.
8006     //
8007     // If T = 1 and the truncation indicator is set ON by execution of the
8008     // instruction, then a truncation (overflow) fault occurs.
8009     //
8010     // BOLR
8011     // If first operand    and    second operand    then result
8012     // bit is:                    bit is:           is from bit:
8013     //        0                          0                      5
8014     //        0                          1                      6
8015     //        1                          0                      7
8016     //        1                          1                      8
8017     //
8018     // The Boolean operations most commonly used are
8019     //                  BOLR Field Bits
8020     // Operation        5      6      7      8
8021     //
8022     // MOVE             0      0      1      1
8023     // AND              0      0      0      1
8024     // OR               0      1      1      1
8025     // NAND             1      1      1      0
8026     // EXCLUSIVE OR     0      1      1      0
8027     // Clear            0      0      0      0
8028     // Invert           1      1      0      0
8029     //
8030 
8031 // 0 0 0 0  Clear
8032 // 0 0 0 1  a AND b
8033 // 0 0 1 0  a AND !b
8034 // 0 0 1 1  a
8035 // 0 1 0 0  !a AND b
8036 // 0 1 0 1  b
8037 // 0 1 1 0  a XOR b
8038 // 0 1 1 1  a OR b
8039 // 1 0 0 0  !a AND !b     !(a OR b)
8040 // 1 0 0 1  a == b        !(a XOR b)
8041 // 1 0 1 0  !b
8042 // 1 0 1 1  !b OR A
8043 // 1 1 0 0  !a
8044 // 1 1 0 1  !b AND a
8045 // 1 1 1 0  a NAND b
8046 // 1 1 1 1  Set
8047 
8048     fault_ipr_subtype_ mod_fault = 0;
8049 
8050 #if !defined(EIS_SETUP)
8051     setupOperandDescriptor (cpup, 1, & mod_fault);
8052     setupOperandDescriptor (cpup, 2, & mod_fault);
8053 #endif
8054 
8055     parseBitstringOperandDescriptor (cpup, 1, & mod_fault);
8056     parseBitstringOperandDescriptor (cpup, 2, & mod_fault);
8057 
8058     L68_ (
8059       // L68 raises it immediately
8060       if (mod_fault)
8061           doFault (FAULT_IPR,
8062                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8063                    "Illegal modifier");
8064     )
8065 
8066     // Bits 1-4 and 10 MBZ
8067     if (IWB_IRODD & 0360200000000)
8068       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8069 
8070     DPS8M_ (
8071       // DPS8M raises it delayed
8072       if (mod_fault)
8073           doFault (FAULT_IPR,
8074                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8075                    "Illegal modifier");
8076     )
8077 
8078     e->ADDR1.cPos = (int) e->C1;
8079     e->ADDR2.cPos = (int) e->C2;
8080 
8081     e->ADDR1.bPos = (int) e->B1;
8082     e->ADDR2.bPos = (int) e->B2;
8083 
8084     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8085     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8086 
8087     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8088     bool B5 = !! (BOLR & 8);
8089     bool B6 = !! (BOLR & 4);
8090     bool B7 = !! (BOLR & 2);
8091     bool B8 = !! (BOLR & 1);
8092 
8093     e->ADDR1.mode = eRWreadBit;
8094 
8095 #if !defined(EIS_PTR)
8096     sim_debug (DBG_TRACEEXT, & cpu_dev,
8097                "CSL N1 %d N2 %d\n"
8098                "CSL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8099                "CSL BOLR %u%u%u%u\n"
8100                "CSL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8101                "CSL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8102                e -> N1, e -> N2,
8103                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8104                B5, B6, B7, B8,
8105                e -> addr [0].SNR, e -> addr [0].address,
8106                e -> addr [0].cPos, e -> addr [0].bPos,
8107                e -> addr [1].SNR, e -> addr [1].address,
8108                e -> addr [1].cPos, e -> addr [1].bPos);
8109 #endif
8110 
8111     bool bR = false; // result bit
8112 
8113     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8114                  DU_CYCLE_FLEN_128;))
8115 
8116     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8117       {
8118         bool b1 = EISgetBitRWN(cpup, &e->ADDR1, true);
8119         e->ADDR2.mode = eRWreadBit;
8120         bool b2 = EISgetBitRWN(cpup, &e->ADDR2, true);
8121 
8122         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8123 
8124         if (bR)
8125           {
8126             //CLR_I_ZERO);
8127             cpu.du.Z = 0;
8128           }
8129 
8130         // write out modified bit
8131         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8132         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8133         // if ADDR1 is on a word boundary, it might fault on the next loop,
8134         // so we flush the write in case.
8135         EISgetBitRWN(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8136     }
8137 
8138     if (e->N1 < e->N2)
8139       {
8140         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8141           {
8142             bool b1 = F;
8143 
8144             e->ADDR2.mode = eRWreadBit;
8145             bool b2 = EISgetBitRWN(cpup, &e->ADDR2, true);
8146 
8147             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8148 
8149             if (bR)
8150               {
8151                 //CLR_I_ZERO;
8152                 cpu.du.Z = 0;
8153               }
8154 
8155             // write out modified bit
8156             e->ADDR2.bit = bR ? 1 : 0;
8157             e->ADDR2.mode = eRWwriteBit;
8158             // if ADDR1 is on a word boundary, it might fault on the next loop,
8159             // so we flush the write in case.
8160             EISgetBitRWN(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8161           }
8162       }
8163 
8164     EISWriteCache (cpup, &e->ADDR2);
8165 
8166     cleanupOperandDescriptor (cpup, 1);
8167     cleanupOperandDescriptor (cpup, 2);
8168 
8169     SC_I_ZERO (cpu.du.Z);
8170     if (e->N1 > e->N2)
8171       {
8172         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8173         // processed and the truncation indicator is set ON.
8174         //
8175         // If T = 1 and the truncation indicator is set ON by execution of the
8176         // instruction, then a truncation (overflow) fault occurs.
8177 
8178         SET_I_TRUNC;
8179         if (T && tstOVFfault (cpup))
8180           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8181       }
8182     else
8183       {
8184         CLR_I_TRUNC;
8185       }
8186   }
8187 
8188 /*
8189  * return B (bit position), C (char position) and word offset given:
8190  *  'length' # of bits, etc ....
8191  *  'initC' initial char position (C)
8192  *  'initB' initial bit position
8193  */
8194 
8195 static void getBitOffsets(int length, int initC, int initB, int *nWords, int *newC, int *newB)
     /* [previous][next][first][last][top][bottom][index][help] */
8196 {
8197     if (length == 0)
8198         return;
8199 
8200     int endBit = (length + 9 * initC + initB - 1) % 36;
8201 
8202     //int numWords = (length + 35) / 36;  // how many additional words will the bits take up?
8203     int numWords = (length + 9 * initC + initB + 35) / 36;  // how many additional words will the bits take up?
8204     int lastWordOffset = numWords - 1;
8205 
8206     if (lastWordOffset > 0)          // more that the 1 word needed?
8207         *nWords = lastWordOffset;  // # of additional words
8208     else
8209         *nWords = 0;    // no additional words needed
8210 
8211     *newC = endBit / 9; // last character number
8212     *newB = endBit % 9; // last bit number
8213 }
8214 
8215 static bool EISgetBitRWNR (cpu_state_t * cpup, EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
8216   {
8217     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
8218     int baseBitPosn = baseCharPosn + p -> bPos;
8219     baseBitPosn -= (int) cpu.du.CHTALLY;
8220 
8221     int bitPosn = baseBitPosn % 36;
8222     int woff = baseBitPosn / 36;
8223     while (bitPosn < 0)
8224       {
8225         bitPosn += 36;
8226         woff -= 1;
8227       }
8228 
8229 /* if (bitPosn < 0) { */
8230 /* sim_printf ("cPos %d bPos %d\n", p->cPos, p->bPos); */
8231 /* sim_printf ("baseCharPosn %d baseBitPosn %d\n", baseCharPosn, baseBitPosn); */
8232 /* sim_printf ("CHTALLY %d baseBitPosn %d\n", cpu.du.CHTALLY, baseBitPosn); */
8233 /* sim_printf ("bitPosn %d woff %d\n", bitPosn, woff); */
8234 /* sim_warn ("EISgetBitRWNR oops\n"); */
8235 /* return false; */
8236 /* } */
8237 
8238 #if defined(EIS_PTR)
8239     long eisaddr_idx = EISADDR_IDX (p);
8240 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8241     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
8242     cpu.du.Dk_PTR_W[eisaddr_idx] += (word18) woff;
8243     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8244 #else
8245     word18 saveAddr = p -> address;
8246     //p -> address += (word18) woff;
8247     //ubsan
8248     p->address = (word18) (((word18s) p->address) + (word18s) woff);
8249 #endif
8250 
8251     p -> data = EISRead (cpup, p); // read data word from memory
8252 
8253     if (p -> mode == eRWreadBit)
8254       {
8255         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
8256       }
8257     else if (p -> mode == eRWwriteBit)
8258       {
8259         //p -> data = bitfieldInsert36 (p -> data, p -> bit, bitPosn, 1);
8260         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
8261 
8262         EISWriteIdx (cpup, p, 0, p -> data, flush); // write data word to memory
8263       }
8264 
8265     p->last_bit_posn = bitPosn;
8266 
8267 #if defined(EIS_PTR)
8268     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
8269 #else
8270     p -> address = saveAddr;
8271 #endif
8272     return p -> bit;
8273   }
8274 
8275 void csr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8276   {
8277     EISstruct * e = & cpu.currentEISinstruction;
8278 
8279     // For i = bits 1, 2, ..., minimum (N1,N2)
8280     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8281     //   C(BOLR)m → C( Y-bit2)N2-i
8282     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8283     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8284     //    C(BOLR)m → C( Y-bit2)N2-i
8285     // INDICATORS: (Indicators not listed are not affected)
8286     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8287     //     Truncation If N1 > N2, then ON; otherwise OFF
8288     //
8289     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8290     // processed and the truncation indicator is set ON.
8291     //
8292     // If T = 1 and the truncation indicator is set ON by execution of the
8293     // instruction, then a truncation (overflow) fault occurs.
8294     //
8295     // BOLR
8296     // If first operand    and    second operand    then result
8297     // bit is:                    bit is:           is from bit:
8298     //        0                          0                      5
8299     //        0                          1                      6
8300     //        1                          0                      7
8301     //        1                          1                      8
8302     //
8303     // The Boolean operations most commonly used are
8304     //                  BOLR Field Bits
8305     // Operation        5      6      7      8
8306     //
8307     // MOVE             0      0      1      1
8308     // AND              0      0      0      1
8309     // OR               0      1      1      1
8310     // NAND             1      1      1      0
8311     // EXCLUSIVE OR     0      1      1      0
8312     // Clear            0      0      0      0
8313     // Invert           1      1      0      0
8314     //
8315 
8316     fault_ipr_subtype_ mod_fault = 0;
8317 
8318 #if !defined(EIS_SETUP)
8319     setupOperandDescriptor(cpup, 1, &mod_fault);
8320     setupOperandDescriptor(cpup, 2, &mod_fault);
8321 #endif
8322 
8323     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8324     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8325 
8326     L68_ (
8327       // L68 raises it immediately
8328       if (mod_fault)
8329           doFault (FAULT_IPR,
8330                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8331                    "Illegal modifier");
8332     )
8333 
8334     // Bits 1-4 and 10 MBZ
8335     if (IWB_IRODD & 0360200000000)
8336       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8337 
8338     DPS8M_ (
8339       // DPS8M raises it delayed
8340       if (mod_fault)
8341           doFault (FAULT_IPR,
8342                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8343                    "Illegal modifier");
8344     )
8345 
8346     e->ADDR1.cPos = (int) e->C1;
8347     e->ADDR2.cPos = (int) e->C2;
8348 
8349     e->ADDR1.bPos = (int) e->B1;
8350     e->ADDR2.bPos = (int) e->B2;
8351 
8352     // get new char/bit offsets
8353     int numWords1=0, numWords2=0;
8354 
8355     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8356     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8357     PNL (cpu.du.D1_PTR_W &= AMASK);
8358 #if defined(EIS_PTR)
8359     cpu.du.D1_PTR_W += (word18) numWords1;
8360     cpu.du.D1_PTR_W &= AMASK;
8361 #else
8362     e->ADDR1.address += (word18) numWords1;
8363 #endif
8364 
8365     sim_debug (DBG_TRACEEXT, & cpu_dev,
8366                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8367                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8368     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8369     sim_debug (DBG_TRACEEXT, & cpu_dev,
8370                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8371                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8372     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8373     PNL (cpu.du.D2_PTR_W &= AMASK);
8374 #if defined(EIS_PTR)
8375     cpu.du.D2_PTR_W += (word18) numWords1;
8376     cpu.du.D2_PTR_W &= AMASK;
8377 #else
8378     e->ADDR2.address += (word18) numWords2;
8379 #endif
8380 
8381     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8382     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8383 
8384     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8385     bool B5 = !! (BOLR & 8);
8386     bool B6 = !! (BOLR & 4);
8387     bool B7 = !! (BOLR & 2);
8388     bool B8 = !! (BOLR & 1);
8389 
8390     e->ADDR1.mode = eRWreadBit;
8391 
8392     CLR_I_TRUNC;     // assume N1 <= N2
8393 
8394     bool bR = false; // result bit
8395 
8396     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8397                  DU_CYCLE_FLEN_128;))
8398 
8399     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8400       {
8401         bool b1 = EISgetBitRWNR(cpup, &e->ADDR1, true);
8402 
8403         e->ADDR2.mode = eRWreadBit;
8404         bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8405 
8406         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8407 
8408         if (bR)
8409           cpu.du.Z = 0;
8410 
8411         // write out modified bit
8412         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8413         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8414         // if ADDR1 is on a word boundary, it might fault on the next loop,
8415         // so we flush the write in case.
8416         EISgetBitRWNR(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 0);
8417       }
8418 
8419     if (e->N1 < e->N2)
8420       {
8421         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8422           {
8423             bool b1 = F;
8424 
8425             e->ADDR2.mode = eRWreadBit;
8426             bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8427 
8428             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8429 
8430             if (bR)
8431               {
8432                 //CLR_I_ZERO;
8433                 cpu.du.Z = 0;
8434               }
8435 
8436             // write out modified bit
8437             e->ADDR2.bit = bR ? 1 : 0;
8438             e->ADDR2.mode = eRWwriteBit;
8439             // if ADDR1 is on a word boundary, it might fault on the next loop,
8440             // so we flush the write in case.
8441             EISgetBitRWNR(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 0);
8442           }
8443       }
8444 
8445     EISWriteCache (cpup, &e->ADDR2);
8446 
8447     cleanupOperandDescriptor (cpup, 1);
8448     cleanupOperandDescriptor (cpup, 2);
8449 
8450     SC_I_ZERO (cpu.du.Z);
8451     if (e->N1 > e->N2)
8452       {
8453         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8454         // processed and the truncation indicator is set ON.
8455         //
8456         // If T = 1 and the truncation indicator is set ON by execution of the
8457         // instruction, then a truncation (overflow) fault occurs.
8458 
8459         SET_I_TRUNC;
8460         if (T && tstOVFfault (cpup))
8461           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8462       }
8463     else
8464       {
8465         CLR_I_TRUNC;
8466       }
8467   }
8468 
8469 void sztl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8470   {
8471     // The execution of this instruction is identical to the Combine
8472     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8473     // not placed into C(Y-bit2)i-1.
8474 
8475     EISstruct * e = & cpu.currentEISinstruction;
8476 
8477     // For i = bits 1, 2, ..., minimum (N1,N2)
8478     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
8479     //   C(BOLR)m → C(Y-bit2)i-1
8480     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
8481     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
8482     //   C(BOLR)m → C(Y-bit2)i-1
8483     //
8484     // INDICATORS: (Indicators not listed are not affected)
8485     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8486     //     Truncation If N1 > N2, then ON; otherwise OFF
8487     //
8488     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8489     // processed and the truncation indicator is set ON.
8490     //
8491     // If T = 1 and the truncation indicator is set ON by execution of the
8492     // instruction, then a truncation (overflow) fault occurs.
8493     //
8494     // BOLR
8495     // If first operand    and    second operand    then result
8496     // bit is:                    bit is:           is from bit:
8497     //        0                          0                      5
8498     //        0                          1                      6
8499     //        1                          0                      7
8500     //        1                          1                      8
8501     //
8502     // The Boolean operations most commonly used are
8503     //                  BOLR Field Bits
8504     // Operation        5      6      7      8
8505     //
8506     // MOVE             0      0      1      1
8507     // AND              0      0      0      1
8508     // OR               0      1      1      1
8509     // NAND             1      1      1      0
8510     // EXCLUSIVE OR     0      1      1      0
8511     // Clear            0      0      0      0
8512     // Invert           1      1      0      0
8513     //
8514 
8515 // 0 0 0 0  Clear
8516 // 0 0 0 1  a AND b
8517 // 0 0 1 0  a AND !b
8518 // 0 0 1 1  a
8519 // 0 1 0 0  !a AND b
8520 // 0 1 0 1  b
8521 // 0 1 1 0  a XOR b
8522 // 0 1 1 1  a OR b
8523 // 1 0 0 0  !a AND !b     !(a OR b)
8524 // 1 0 0 1  a == b        !(a XOR b)
8525 // 1 0 1 0  !b
8526 // 1 0 1 1  !b OR A
8527 // 1 1 0 0  !a
8528 // 1 1 0 1  !b AND a
8529 // 1 1 1 0  a NAND b
8530 // 1 1 1 1  Set
8531 
8532     fault_ipr_subtype_ mod_fault = 0;
8533 
8534 #if !defined(EIS_SETUP)
8535     setupOperandDescriptor (cpup, 1, &mod_fault);
8536     setupOperandDescriptor (cpup, 2, &mod_fault);
8537 #endif
8538 
8539     parseBitstringOperandDescriptor (cpup, 1, &mod_fault);
8540     parseBitstringOperandDescriptor (cpup, 2, &mod_fault);
8541 
8542     L68_ (
8543       // L68 raises it immediately
8544       if (mod_fault)
8545           doFault (FAULT_IPR,
8546                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8547                    "Illegal modifier");
8548     )
8549 
8550     // Bits 1-4 and 10 MBZ
8551     if (IWB_IRODD & 0360200000000)
8552       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8553 
8554     DPS8M_ (
8555       // DPS8M raises it delayed
8556       if (mod_fault)
8557           doFault (FAULT_IPR,
8558                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8559                    "Illegal modifier");
8560     )
8561 
8562     e->ADDR1.cPos = (int) e->C1;
8563     e->ADDR2.cPos = (int) e->C2;
8564 
8565     e->ADDR1.bPos = (int) e->B1;
8566     e->ADDR2.bPos = (int) e->B2;
8567 
8568     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8569     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8570 
8571     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8572     bool B5 = !! (BOLR & 8);
8573     bool B6 = !! (BOLR & 4);
8574     bool B7 = !! (BOLR & 2);
8575     bool B8 = !! (BOLR & 1);
8576 
8577     e->ADDR1.mode = eRWreadBit;
8578     e->ADDR2.mode = eRWreadBit;
8579 
8580 #if !defined(EIS_PTR)
8581     sim_debug (DBG_TRACEEXT, & cpu_dev,
8582                "SZTL N1 %d N2 %d\n"
8583                "SZTL C1 %d C2 %d B1 %d B2 %d F %o T %d\n"
8584                "SZTL BOLR %u%u%u%u\n"
8585                "SZTL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\n"
8586                "SZTL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\n",
8587                e -> N1, e -> N2,
8588                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8589                B5, B6, B7, B8,
8590                e -> addr [0].SNR, e -> addr [0].address,
8591                e -> addr [0].cPos, e -> addr [0].bPos,
8592                e -> addr [1].SNR, e -> addr [1].address,
8593                e -> addr [1].cPos, e -> addr [1].bPos);
8594 #endif
8595 
8596     bool bR = false; // result bit
8597 
8598     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8599                  DU_CYCLE_FLEN_128;))
8600 
8601     for( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY += 1)
8602     {
8603         bool b1 = EISgetBitRWN (cpup, & e->ADDR1, true);
8604         bool b2 = EISgetBitRWN (cpup, & e->ADDR2, true);
8605 
8606         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8607 
8608         if (bR)
8609           {
8610             //CLR_I_ZERO);
8611             cpu.du.Z = 0;
8612             break;
8613           }
8614       }
8615 
8616     if (e->N1 < e->N2)
8617       {
8618         for (; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8619           {
8620             bool b1 = F;
8621             bool b2 = EISgetBitRWN (cpup, & e->ADDR2, true);
8622 
8623             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8624 
8625             if (bR)
8626               {
8627                 //CLR_I_ZERO;
8628                 cpu.du.Z = 0;
8629                 break;
8630               }
8631           }
8632       }
8633 
8634     cleanupOperandDescriptor (cpup, 1);
8635     cleanupOperandDescriptor (cpup, 2);
8636 
8637     SC_I_ZERO (cpu.du.Z);
8638     if (e->N1 > e->N2)
8639       {
8640         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8641         // processed and the truncation indicator is set ON.
8642         //
8643         // If T = 1 and the truncation indicator is set ON by execution of the
8644         // instruction, then a truncation (overflow) fault occurs.
8645 
8646         SET_I_TRUNC;
8647         if (T && tstOVFfault (cpup))
8648           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8649       }
8650     else
8651       {
8652         CLR_I_TRUNC;
8653       }
8654   }
8655 
8656 void sztr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8657   {
8658     // The execution of this instruction is identical to the Combine
8659     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8660     // not placed into C(Y-bit2)i-1.
8661 
8662     EISstruct * e = & cpu.currentEISinstruction;
8663 
8664     // For i = bits 1, 2, ..., minimum (N1,N2)
8665     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8666     //   C(BOLR)m → C( Y-bit2)N2-i
8667     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8668     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8669     //    C(BOLR)m → C( Y-bit2)N2-i
8670     // INDICATORS: (Indicators not listed are not affected)
8671     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8672     //     Truncation If N1 > N2, then ON; otherwise OFF
8673     //
8674     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8675     // processed and the truncation indicator is set ON.
8676     //
8677     // If T = 1 and the truncation indicator is set ON by execution of the
8678     // instruction, then a truncation (overflow) fault occurs.
8679     //
8680     // BOLR
8681     // If first operand    and    second operand    then result
8682     // bit is:                    bit is:           is from bit:
8683     //        0                          0                      5
8684     //        0                          1                      6
8685     //        1                          0                      7
8686     //        1                          1                      8
8687     //
8688     // The Boolean operations most commonly used are
8689     //                  BOLR Field Bits
8690     // Operation        5      6      7      8
8691     //
8692     // MOVE             0      0      1      1
8693     // AND              0      0      0      1
8694     // OR               0      1      1      1
8695     // NAND             1      1      1      0
8696     // EXCLUSIVE OR     0      1      1      0
8697     // Clear            0      0      0      0
8698     // Invert           1      1      0      0
8699     //
8700 
8701     fault_ipr_subtype_ mod_fault = 0;
8702 
8703 #if !defined(EIS_SETUP)
8704     setupOperandDescriptor(cpup, 1, &mod_fault);
8705     setupOperandDescriptor(cpup, 2, &mod_fault);
8706 #endif
8707 
8708     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8709     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8710 
8711     L68_ (
8712       // L68 raises it immediately
8713       if (mod_fault)
8714           doFault (FAULT_IPR,
8715                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8716                    "Illegal modifier");
8717     )
8718 
8719     // Bits 1-4 and 10 MBZ
8720     if (IWB_IRODD & 0360200000000)
8721       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8722 
8723     DPS8M_ (
8724       // DPS8M raises it delayed
8725       if (mod_fault)
8726           doFault (FAULT_IPR,
8727                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8728                    "Illegal modifier");
8729     )
8730 
8731     e->ADDR1.cPos = (int) e->C1;
8732     e->ADDR2.cPos = (int) e->C2;
8733 
8734     e->ADDR1.bPos = (int) e->B1;
8735     e->ADDR2.bPos = (int) e->B2;
8736 
8737     // get new char/bit offsets
8738     int numWords1=0, numWords2=0;
8739 
8740     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8741     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8742     PNL (cpu.du.D1_PTR_W &= AMASK);
8743 #if defined(EIS_PTR)
8744     cpu.du.D1_PTR_W += (word18) numWords1;
8745     cpu.du.D1_PTR_W &= AMASK;
8746 #else
8747     e->ADDR1.address += (word18) numWords1;
8748 #endif
8749 
8750     sim_debug (DBG_TRACEEXT, & cpu_dev,
8751                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\n",
8752                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8753     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8754     sim_debug (DBG_TRACEEXT, & cpu_dev,
8755                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\n",
8756                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8757     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8758     PNL (cpu.du.D2_PTR_W &= AMASK);
8759 #if defined(EIS_PTR)
8760     cpu.du.D2_PTR_W += (word18) numWords1;
8761     cpu.du.D2_PTR_W &= AMASK;
8762 #else
8763     e->ADDR2.address += (word18) numWords2;
8764 #endif
8765 
8766     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8767     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8768 
8769     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8770     bool B5 = !! (BOLR & 8);
8771     bool B6 = !! (BOLR & 4);
8772     bool B7 = !! (BOLR & 2);
8773     bool B8 = !! (BOLR & 1);
8774 
8775     e->ADDR1.mode = eRWreadBit;
8776 
8777     CLR_I_TRUNC;     // assume N1 <= N2
8778 
8779     bool bR = false; // result bit
8780 
8781     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8782                  DU_CYCLE_FLEN_128;))
8783 
8784     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8785       {
8786         bool b1 = EISgetBitRWNR(cpup, &e->ADDR1, true);
8787 
8788         e->ADDR2.mode = eRWreadBit;
8789         bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8790 
8791         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8792 
8793         if (bR)
8794           {
8795             cpu.du.Z = 0;
8796             break;
8797           }
8798 
8799       }
8800 
8801     if (e->N1 < e->N2)
8802       {
8803         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8804           {
8805             bool b1 = F;
8806 
8807             e->ADDR2.mode = eRWreadBit;
8808             bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8809 
8810             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8811 
8812             if (bR)
8813             {
8814                 //CLR_I_ZERO;
8815                 cpu.du.Z = 0;
8816                 break;
8817             }
8818 
8819           }
8820       }
8821 
8822     cleanupOperandDescriptor (cpup, 1);
8823     cleanupOperandDescriptor (cpup, 2);
8824 
8825     SC_I_ZERO (cpu.du.Z);
8826     if (e->N1 > e->N2)
8827       {
8828         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8829         // processed and the truncation indicator is set ON.
8830         //
8831         // If T = 1 and the truncation indicator is set ON by execution of the
8832         // instruction, then a truncation (overflow) fault occurs.
8833 
8834         SET_I_TRUNC;
8835         if (T && tstOVFfault (cpup))
8836           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8837       }
8838     else
8839       {
8840         CLR_I_TRUNC;
8841       }
8842   }
8843 
8844 /*
8845  * CMPB - Compare Bit Strings
8846  */
8847 
8848 /*
8849  * get a bit from memory ....
8850  */
8851 // XXX this is terribly inefficient, but it'll do for now ......
8852 
8853 static bool EISgetBit(cpu_state_t * cpup, EISaddr *p, int *cpos, int *bpos)
     /* [previous][next][first][last][top][bottom][index][help] */
8854 {
8855 #if defined(EIS_PTR)
8856     long eisaddr_idx = EISADDR_IDX (p);
8857 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8858 #endif
8859 
8860     if (!p)
8861     {
8862         //lastAddress = -1;
8863         return 0;
8864     }
8865 
8866     if (*bpos > 8)      // bits 0-8
8867     {
8868         *bpos = 0;
8869         *cpos += 1;
8870         if (*cpos > 3)  // chars 0-3
8871         {
8872             *cpos = 0;
8873 #if defined(EIS_PTR)
8874             cpu.du.Dk_PTR_W[eisaddr_idx] += 1;
8875             cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8876 #else
8877             p->address += 1;
8878             p->address &= AMASK;
8879 #endif
8880         }
8881     }
8882 
8883     p->data = EISRead(cpup, p); // read data word from memory
8884 
8885     int charPosn = *cpos * 9;
8886     int bitPosn = charPosn + *bpos;
8887     bool b = getbits36_1 (p->data, (uint) bitPosn) != 0;
8888 
8889     *bpos += 1;
8890 
8891     return b;
8892 }
8893 
8894 void cmpb (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8895 {
8896     EISstruct * e = & cpu.currentEISinstruction;
8897 
8898     // For i = 1, 2, ..., minimum (N1,N2)
8899     //   C(Y-bit1)i-1 :: C(Y-bit2)i-1
8900     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
8901     //   C(FILL) :: C(Y-bit2)i-1
8902     // If N1 > N2, then for i = N2+l, N2+2, ..., N1
8903     //   C(Y-bit1)i-1 :: C(FILL)
8904     //
8905     // Indicators:
8906     //    Zero:  If C(Y-bit1)i = C(Y-bit2)i for all i, then ON; otherwise, OFF
8907     //    Carry: If C(Y-bit1)i < C(Y-bit2)i for any i, then OFF; otherwise ON
8908 
8909     fault_ipr_subtype_ mod_fault = 0;
8910 
8911 #if !defined(EIS_SETUP)
8912     setupOperandDescriptor(cpup, 1, &mod_fault);
8913     setupOperandDescriptor(cpup, 2, &mod_fault);
8914 #endif
8915 
8916     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8917     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8918 
8919     L68_ (
8920       // L68 raises it immediately
8921       if (mod_fault)
8922         {
8923           doFault (FAULT_IPR,
8924                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8925                    "Illegal modifier");
8926         }
8927     )
8928 
8929     // Bits 1-8 and 10 MBZ
8930     if (IWB_IRODD & 0377200000000)
8931       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpb 1-8,10 MBZ");
8932 
8933     DPS8M_ (
8934       // DPS8M raises it delayed
8935       if (mod_fault)
8936         {
8937           doFault (FAULT_IPR,
8938                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8939                    "Illegal modifier");
8940         }
8941     )
8942 
8943     int charPosn1 = (int) e->C1;
8944     int charPosn2 = (int) e->C2;
8945 
8946     int bitPosn1 = (int) e->B1;
8947     int bitPosn2 = (int) e->B2;
8948 
8949     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8950 
8951     SET_I_ZERO;  // assume all =
8952     SET_I_CARRY; // assume all >=
8953 
8954 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb N1 %d N2 %d\n", e -> N1, e -> N2);
8955 
8956 
8957 
8958 
8959 
8960 
8961 
8962 
8963 
8964 
8965 
8966 
8967 
8968 
8969 
8970 
8971 
8972     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8973       DU_CYCLE_FLEN_128;))
8974 
8975     uint i;
8976     for(i = 0 ; i < min(e->N1, e->N2) ; i += 1)
8977     {
8978         bool b1 = EISgetBit (cpup, &e->ADDR1, &charPosn1, &bitPosn1);
8979         bool b2 = EISgetBit (cpup, &e->ADDR2, &charPosn2, &bitPosn2);
8980 
8981 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(min(e->N1, e->N2)) i %d b1 %d b2 %d\n", i, b1, b2);
8982         if (b1 != b2)
8983         {
8984             CLR_I_ZERO;
8985             if (!b1 && b2)  // 0 < 1
8986                 CLR_I_CARRY;
8987 
8988             cleanupOperandDescriptor (cpup, 1);
8989             cleanupOperandDescriptor (cpup, 2);
8990 
8991             return;
8992         }
8993 
8994     }
8995     if (e->N1 < e->N2)
8996     {
8997         for(; i < e->N2 ; i += 1)
8998         {
8999             bool b1 = F;
9000             bool b2 = EISgetBit(cpup, &e->ADDR2, &charPosn2, &bitPosn2);
9001 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 < e->N2) i %d b1fill %d b2 %d\n", i, b1, b2);
9002 
9003             if (b1 != b2)
9004             {
9005                 CLR_I_ZERO;
9006                 if (!b1 && b2)  // 0 < 1
9007                     CLR_I_CARRY;
9008 
9009                 cleanupOperandDescriptor (cpup, 1);
9010                 cleanupOperandDescriptor (cpup, 2);
9011 
9012                 return;
9013             }
9014         }
9015     } else if (e->N1 > e->N2)
9016     {
9017         for(; i < e->N1 ; i += 1)
9018         {
9019             bool b1 = EISgetBit(cpup, &e->ADDR1, &charPosn1, &bitPosn1);
9020             bool b2 = F;
9021 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 > e->N2) i %d b1 %d b2fill %d\n", i, b1, b2);
9022 
9023             if (b1 != b2)
9024             {
9025                 CLR_I_ZERO;
9026                 if (!b1 && b2)  // 0 < 1
9027                     CLR_I_CARRY;
9028 
9029                 cleanupOperandDescriptor (cpup, 1);
9030                 cleanupOperandDescriptor (cpup, 2);
9031 
9032                 return;
9033             }
9034         }
9035     }
9036     cleanupOperandDescriptor (cpup, 1);
9037     cleanupOperandDescriptor (cpup, 2);
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 
9252 
9253 
9254 
9255 
9256 
9257 
9258 
9259 
9260 
9261 /*
9262  * determine sign of N*9-bit length word
9263  */
9264 static bool sign9n(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9265 {
9266     // sign bit of  9-bit is bit 8  (1 << 8)
9267     // sign bit of 18-bit is bit 17 (1 << 17)
9268     // .
9269     // .
9270     // .
9271     // sign bit of 72-bit is bit 71 (1 << 71)
9272 
9273     if (N < 1 || N > 8) // XXX largest int we'll play with is 72-bits? Makes sense
9274         return false;
9275 
9276 #if defined(NEED_128)
9277     word72 sgnmask = lshift_128 (construct_128 (0, 1), (uint) (N * 9 - 1));
9278     return isnonzero_128 (and_128 (sgnmask, n128));
9279 #else
9280     word72 sgnmask = (word72)1 << ((N * 9) - 1);
9281 
9282     return (bool)(sgnmask & n128);
9283 #endif /* if defined(NEED_128) */
9284 }
9285 
9286 /*
9287  * sign extend a N*9 length word to a (word72) 128-bit word
9288  */
9289 static word72s signExt9(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9290 {
9291     // ext mask for  9-bit = 037777777777777777777777777777777777777400  8 0's
9292     // ext mask for 18-bit = 037777777777777777777777777777777777400000 17 0's
9293     // ext mask for 36-bit = 037777777777777777777777777777400000000000 35 0's
9294     // etc...
9295 
9296     int bits = (N * 9) - 1;
9297     if (sign9n(n128, N))
9298     {
9299 #if defined(NEED_128)
9300         uint128 extBits = lshift_128 (construct_128 (MASK64, MASK64), (uint) bits);
9301         uint128 or = or_128 (n128, extBits);
9302         return cast_s128 (or);
9303 #else
9304         uint128 extBits = ((uint128)-1 << bits);
9305         return (word72s) (n128 | extBits);
9306 #endif /* if defined(NEED_128) */
9307     }
9308 #if defined(NEED_128)
9309     uint128 zeroBits = complement_128 (lshift_128 (construct_128 (MASK64, MASK64), (uint) bits));
9310     uint128 and = and_128 (n128, zeroBits);
9311     return cast_s128 (and);
9312 #else
9313     uint128 zeroBits = ~((uint128)-1 << bits);
9314     return (word72s) (n128 & zeroBits);
9315 #endif /* if defined(NEED_128) */
9316 }
9317 
9318 /*
9319  * load a 9*n bit integer into e->x ...
9320  */
9321 
9322 static void load9x(cpu_state_t * cpup, int n, EISaddr *addr, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
9323 {
9324     EISstruct * e = & cpu.currentEISinstruction;
9325 #if defined(NEED_128)
9326     word72 x = construct_128 (0, 0);
9327 #else
9328     word72 x = 0;
9329 #endif /* if defined(NEED_128) */
9330 #if defined(EIS_PTR)
9331     long eisaddr_idx = EISADDR_IDX (addr);
9332 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
9333 #endif
9334 
9335     word36 data = EISRead(cpup, addr);
9336 
9337     int m = n;
9338     while (m)
9339     {
9340 #if defined(NEED_128)
9341         x = lshift_128 (x, 9);
9342 #else
9343         x <<= 9;         // make room for next 9-bit byte
9344 #endif /* if defined(NEED_128) */
9345 
9346         if (pos > 3)        // overflows to next word?
9347         {   // yep....
9348             pos = 0;        // reset to 1st byte
9349 #if EIS_PTR
9350             cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;          // bump source to next address
9351 #else
9352             addr->address = (addr->address + 1) & AMASK;          // bump source to next address
9353 #endif
9354             data = EISRead(cpup, addr);    // read it from memory
9355         }
9356 
9357 #if defined(NEED_128)
9358         x = or_128 (x, construct_128 (0, GETBYTE (data, pos)));
9359 #else
9360         x |= GETBYTE(data, pos);   // fetch byte at position pos and 'or' it in
9361 #endif /* if defined(NEED_128) */
9362 
9363         pos += 1;           // onto next position
9364 
9365         m -= 1;             // decrement byte counter
9366     }
9367     e->x = signExt9(x, n);  // form proper 2's-complement integer
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 
9480 
9481 
9482 
9483 
9484 
9485 
9486 
9487 
9488 
9489 
9490 void btd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
9491 {
9492     EISstruct * e = & cpu.currentEISinstruction;
9493 
9494     // C(Y-char91) converted to decimal → C(Y-charn2)
9495     /*!
9496      * C(Y-char91) contains a twos complement binary integer aligned on 9-bit
9497      * character boundaries with length 0 < N1 <= 8.
9498      *
9499      * If TN2 and S2 specify a 4-bit signed number and P = 1, then if
9500      * C(Y-char91) is positive (bit 0 of C(Y-char91)0 = 0), then the 13(8) plus
9501      * sign character is moved to C(Y-charn2) as appropriate.
9502      *
9503      *   The scaling factor of C(Y-charn2), SF2, must be 0.
9504      *
9505      *   If N2 is not large enough to hold the digits generated by conversion
9506      *   of C(Y-char91) an overflow condition exists; the overflow indicator is
9507      *   set ON and an overflow fault occurs. This implies that an unsigned
9508      *   fixed-point receiving field has a minimum length of 1 character and a
9509      *   signed fixed- point field, 2 characters.
9510      *
9511      * If MFk.RL = 1, then Nk does not contain the operand length; instead; it
9512      * contains a register code for a register holding the operand length.
9513      *
9514      * If MFk.ID = 1, then the kth word following the instruction word does not
9515      * contain an operand descriptor; instead, it contains an indirect pointer
9516      * to the operand descriptor.
9517      *
9518      * C(Y-char91) and C(Y-charn2) may be overlapping strings; no check is made.
9519      *
9520      * Attempted conversion to a floating-point number (S2 = 0) or attempted
9521      * use of a scaling factor (SF2 ≠ 0) causes an illegal procedure fault.
9522      *
9523      * If N1 = 0 or N1 > 8 an illegal procedure fault occurs.
9524      *
9525      * Attempted execution with the xed instruction causes an illegal procedure fault.
9526      *
9527      * Attempted repetition with the rpt, rpd, or rpl instructions causes an illegal procedure fault.
9528      *
9529      */
9530 
9531     // C(string 1) -> C(string 2) (converted)
9532 
9533     // The two's complement binary integer starting at location YC1 is
9534     // converted into a signed string of decimal characters of data type TN2,
9535     // sign and decimal type S2 (S2 = 00 is illegal) and scale factor 0; and is
9536     // stored, right-justified, as a string of length L2 starting at location
9537     // YC2. If the string generated is longer than L2, the high-order excess is
9538     // truncated and the overflow indicator is set. If strings 1 and 2 are not
9539     // overlapped, the contents of string 1 remain unchanged. The length of
9540     // string 1 (L1) is given as the number of 9-bit segments that make up the
9541     // string. L1 is equal to or is less than 8. Thus, the binary string to be
9542     // converted can be 9, 18, 27, 36, 45, 54, 63, or 72 bits long. CN1
9543     // designates a 9-bit character boundary. If P=1, positive signed 4-bit
9544     // results are stored using octal 13 as the plus sign. If P=0, positive
9545     // signed 4-bit results are stored with octal 14 as the plus sign.
9546 
9547     fault_ipr_subtype_ mod_fault = 0;
9548 
9549 #if !defined(EIS_SETUP)
9550     setupOperandDescriptor(cpup, 1, &mod_fault);
9551     setupOperandDescriptor(cpup, 2, &mod_fault);
9552 #endif
9553 
9554     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
9555     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
9556 
9557     L68_ (
9558       // L68 raises it immediately
9559       if (mod_fault)
9560         {
9561           doFault (FAULT_IPR,
9562                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9563                    "Illegal modifier");
9564         }
9565     )
9566 
9567     // Bits 1-10 MBZ
9568     if (IWB_IRODD & 0377600000000)
9569       {
9570         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
9571         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "btd 0-8 MBZ");
9572       }
9573 
9574     // Bits 21-29 of OP1 MBZ
9575     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000077700)
9576       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op1 21-29 MBZ");
9577 
9578     // Bits 24-29 of OP2 MBZ
9579     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000007700)
9580       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 24-29 MBZ");
9581 
9582     if (e->S[1] == 0)
9583       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 S=0");
9584 
9585     DPS8M_ (
9586       // DPS8 raises it delayed
9587       if (mod_fault)
9588         {
9589           doFault (FAULT_IPR,
9590                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9591                    "Illegal modifier");
9592         }
9593     )
9594 
9595     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
9596 
9597     if (e->N1 == 0 || e->N1 > 8)
9598         doFault(FAULT_IPR, fst_ill_proc, "btd(1): N1 == 0 || N1 > 8");
9599 
9600     uint dstTN = e->TN2;    // type of chars in dst
9601     uint dstCN = e->CN2;    // starting at char pos CN
9602 
9603     int n2 = 0;
9604 
9605     switch(e->S2)
9606     {
9607         case CSLS:
9608         case CSTS:
9609             n2 = (int) e->N2 - 1; // 1 sign
9610             break;
9611 
9612         case CSNS:
9613             n2 = (int) e->N2;     // no sign
9614             break;          // no sign wysiwyg
9615     }
9616 
9617     sim_debug (DBG_CAC, & cpu_dev,
9618       "n2 %d\n",
9619       n2);
9620 
9621     if (n2 < 1)
9622         doFault (FAULT_IPR, fst_ill_proc, "btd adjusted n2<1");
9623 
9624     decContext set;
9625     decContextDefaultDPS8(&set);
9626     set.traps=0;
9627 
9628     load9x(cpup, (int) e->N1, &e->ADDR1, (int) e->CN1);
9629 
9630     // handle sign
9631     e->sign = 1;
9632 #if defined(NEED_128)
9633     word72 x = cast_128 (e->x);
9634     if (islt_s128 (e->x, construct_s128 (0, 0)))
9635       {
9636         e->sign = -1;
9637         x = and_128 (negate_128 (x), MASK72);
9638 
9639       }
9640 
9641     // convert to decimal string, workaround missing sprintf uint128
9642     char tmp[32];
9643     tmp[31] = 0;
9644     int i;
9645     for (i=30;i>=0;i--) {
9646         //tmp[i] = x%10 + '0';
9647         //x /= 10;
9648         uint16_t r;
9649         x = divide_128_16 (x, 10, & r);
9650         tmp[i] = (char) r + '0';
9651         if (iszero_128 (x))
9652             break;
9653     }
9654 #else
9655     word72 x = (word72)e->x;
9656     if (e->x < 0) {
9657         e->sign = -1;
9658         //x = (-x) & MASK72;
9659         // ubsan
9660         x = ((word72) (- (word72s) x)) & MASK72;
9661     }
9662 
9663     // convert to decimal string, workaround missing sprintf uint128
9664     char tmp[32];
9665     tmp[31] = 0;
9666     int i;
9667     for (i=30;i>=0;i--) {
9668         tmp[i] = x%10 + '0';
9669         x /= 10;
9670         if (x == 0)
9671             break;
9672     }
9673 #endif /* if defined(NEED_128) */
9674 
9675     decNumber _1;
9676     decNumber *op1 = decNumberFromString(&_1, tmp+i, &set);
9677     if (e->sign == -1)
9678         op1->bits |= DECNEG;
9679 
9680     bool Ovr = false, Trunc = false;
9681 
9682     uint8_t out [256];
9683     char * res = formatDecimal (out, &set, op1, n2, (int) e->S2, e->SF2, 0, &Ovr, &Trunc);
9684 
9685     // now write to memory in proper format.....
9686 
9687     //word18 dstAddr = e->dstAddr;
9688     int pos = (int) dstCN;
9689 
9690     // 1st, take care of any leading sign .......
9691     switch(e->S2)
9692     {
9693         case CSLS:  // fixed-point, leading sign
9694             switch(dstTN)
9695             {
9696                 case CTN4:
9697                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
9698                               //   then the 13(8) plus sign character is placed appropriately
9699                               //   if the result of the operation is positive.
9700                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9701                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 013);  // special +
9702                     else
9703                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9704                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 014);  // default +
9705                     break;
9706                 case CTN9:
9707                     EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9708                                (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9709                     break;
9710             }
9711             break;
9712 
9713         case CSTS:  // nuttin' to do here .....
9714         case CSNS:
9715             break;  // no sign wysiwyg
9716     }
9717 
9718     // 2nd, write the digits .....
9719     for(int i = 0 ; i < n2 ; i++)
9720         switch(dstTN)
9721         {
9722             case CTN4:
9723                 EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN, (word9) (res[i] - '0'));
9724                 break;
9725             case CTN9:
9726                 EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN, (word9) res[i]);
9727                 break;
9728         }
9729 
9730     // 3rd, take care of any trailing sign or exponent ...
9731     switch(e->S2)
9732     {
9733         case CSTS:  // write trailing sign ....
9734             switch(dstTN)
9735             {
9736                 case CTN4:
9737                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
9738                               //   then the 13(8) plus sign character is placed appropriately
9739                               //   if the result of the operation is positive.
9740                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9741                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  013);  // special +
9742                     else
9743                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9744                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  014);  // default +
9745                     break;
9746 
9747                 case CTN9:
9748                     EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9749                                (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9750                     break;
9751             }
9752             break;
9753 
9754         case CSLS:  // fixed point, leading sign - already done
9755         case CSNS:  // fixed point, unsigned - nuttin' needed to do
9756             break;
9757     }
9758 
9759     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));  // set negative indicator if op3 < 0
9760     SC_I_ZERO (decNumberIsZero(op1));     // set zero indicator if op3 == 0
9761 
9762     cleanupOperandDescriptor (cpup, 1);
9763     cleanupOperandDescriptor (cpup, 2);
9764 
9765     if (Ovr)
9766     {
9767         SET_I_OFLOW;
9768         if (tstOVFfault (cpup))
9769           doFault(FAULT_OFL, fst_zero, "btd overflow fault");
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 
9969 
9970 
9971 
9972 
9973 
9974 
9975 
9976 
9977 
9978 
9979 void dtb (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
9980 {
9981     EISstruct * e = & cpu.currentEISinstruction;
9982 
9983     fault_ipr_subtype_ mod_fault = 0;
9984 
9985 #if !defined(EIS_SETUP)
9986     setupOperandDescriptor(cpup, 1, &mod_fault);
9987     setupOperandDescriptor(cpup, 2, &mod_fault);
9988 #endif
9989 
9990     PNL (L68_ (DU_CYCLE_DGDB;))
9991 
9992     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
9993     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
9994 
9995     L68_ (
9996       // L68 raises it immediately
9997       if (mod_fault)
9998         {
9999           doFault (FAULT_IPR,
10000                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10001                    "Illegal modifier");
10002         }
10003     )
10004 
10005     // Bits 0 to 10 of the instruction Must Be Zero. So Say We ISOLTS.
10006     uint mbz = (uint) getbits36 (IWB_IRODD, 0, 11);
10007     if (mbz)
10008       {
10009         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dtb(): 0-10 MBZ");
10010       }
10011 
10012     // Bits 24-29 of OP1 MBZ
10013     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
10014       {
10015         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op1 24-29 MBZ");
10016       }
10017 
10018     // Bits 21-29 of OP2 MBZ
10019     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000077700)
10020       {
10021         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op2 21-29 MBZ");
10022        }
10023 
10024     // Attempted conversion of a floating-point number (S1 = 0) or attempted
10025     // use of a scaling factor (SF1 ≠ 0) causes an illegal procedure fault.
10026     if (e->S1 == 0 || e->SF1 != 0)
10027     {
10028         doFault(FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb():  S1=0 or SF1!=0");
10029     }
10030 
10031     DPS8M_ (
10032       // DPS8M raises it delayed
10033       if (mod_fault)
10034         {
10035           doFault (FAULT_IPR,
10036                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10037                    "Illegal modifier");
10038         }
10039     )
10040 
10041     // If N2 = 0 or N2 > 8 an illegal procedure fault occurs.
10042     if (e->N2 == 0 || e->N2 > 8)
10043     {
10044         doFault(FAULT_IPR, fst_ill_proc, "dtb():  N2 = 0 or N2 > 8 etc.");
10045     }
10046 
10047     int n1 = 0;
10048 
10049     /*
10050      * Here we need to distinguish between 4 type of numbers.
10051      *
10052      * CSFL - Floating-point, leading sign
10053      * CSLS - Scaled fixed-point, leading sign
10054      * CSTS - Scaled fixed-point, trailing sign
10055      * CSNS - Scaled fixed-point, unsigned
10056      */
10057 
10058     // determine precision
10059     switch(e->S1)
10060     {
10061         case CSLS:
10062         case CSTS:
10063             n1 = (int) e->N1 - 1; // only 1 sign
10064             break;
10065 
10066         case CSNS:
10067             n1 = (int) e->N1;     // no sign
10068             break;  // no sign wysiwyg
10069     }
10070     // RJ78: An Illegal Procedure fault occurs if:
10071     // N1 is not large enough to specify the number of characters required for the
10072     // specified sign and/or exponent, plus at least one digit.
10073 
10074     if (n1 < 1)
10075         doFault (FAULT_IPR, fst_ill_proc, "dtb adjusted n1<1");
10076 
10077     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10078 
10079     // prepare output mask
10080 #if defined(NEED_128)
10081     word72 msk = subtract_128 (lshift_128 (construct_128 (0, 1), (9*e->N2-1)),construct_128 (0, 1));
10082 #else
10083     word72 msk = ((word72)1<<(9*e->N2-1))-1; // excluding sign
10084 #endif /* if defined(NEED_128) */
10085 
10086 
10087 
10088 
10089 
10090 
10091 
10092 
10093 
10094 
10095 
10096 
10097 
10098 
10099     // input is unscaled fixed point, so just get the digits
10100     bool Ovr = false;
10101 #if defined(NEED_128)
10102     word72 x = construct_128 (0, 0);
10103     for (int i = 0; i < n1; i++) {
10104         //x *= 10;
10105         x = multiply_128 (x, construct_128 (0, 10));
10106         //x += e->inBuffer[i];
10107         x = add_128 (x, construct_128 (0, (uint) e->inBuffer[i]));
10108         //Ovr |= x>msk?1:0;
10109         Ovr |= isgt_128 (x, msk) ? 1 : 0;
10110         //x &= msk; // multiplication and addition mod msk+1
10111         x = and_128 (x, msk); // multiplication and addition mod msk+1
10112     }
10113     if (e->sign == -1)
10114         //x = -x; // no need to mask it
10115         x = negate_128 (x); // no need to mask it
10116 
10117 #else
10118     word72 x = 0;
10119     for (int i = 0; i < n1; i++) {
10120         x *= 10;
10121         x += e->inBuffer[i];
10122         //sim_printf("%d %012"PRIo64" %012"PRIo64"\n",e->inBuffer[i],(word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10123         Ovr |= x>msk?1:0;
10124         x &= msk; // multiplication and addition mod msk+1
10125     }
10126     if (e->sign == -1)
10127         //x = -x; // no need to mask it
10128         // ubsan
10129         x = (word72) (- (word72s) x); // no need to mask it
10130 
10131     //sim_printf ("dtb out %012"PRIo64" %012"PRIo64"\n", (word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10132 #endif /* if defined(NEED_128) */
10133     int pos = (int)e->CN2;
10134 
10135     // now write to memory in proper format.....
10136 
10137     int shift = 9*((int)e->N2-1);
10138     for(int i = 0; i < (int)e->N2; i++) {
10139 #if defined(NEED_128)
10140         EISwrite9(cpup, &e->ADDR2, &pos, (word9) rshift_128 (x, (uint) shift).l & 0777);
10141 #else
10142         EISwrite9(cpup, &e->ADDR2, &pos, (word9) (x >> shift )& 0777);
10143 #endif /* if defined(NEED_128) */
10144         shift -= 9;
10145     }
10146 
10147     SC_I_NEG (e->sign == -1);  // set negative indicator
10148 #if defined(NEED_128)
10149     SC_I_ZERO (iszero_128 (x)); // set zero indicator
10150 #else
10151     SC_I_ZERO (x==0);     // set zero indicator
10152 #endif /* if defined(NEED_128) */
10153 
10154     cleanupOperandDescriptor (cpup, 1);
10155     cleanupOperandDescriptor (cpup, 2);
10156 
10157     if (Ovr)
10158     {
10159         SET_I_OFLOW;
10160         if (tstOVFfault (cpup))
10161           doFault(FAULT_OFL, fst_zero, "dtb overflow fault");
10162     }
10163 }
10164 
10165 /*
10166  * decimal EIS instructions ...
10167  */
10168 
10169 #define ASC(x)  ((x) + '0')
10170 
10171 /*
10172  * ad2d - Add Using Two Decimal Operands
10173  */
10174 
10175 void ad2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10176 {
10177     EISstruct * e = & cpu.currentEISinstruction;
10178 
10179     fault_ipr_subtype_ mod_fault = 0;
10180 
10181 #if !defined(EIS_SETUP)
10182     setupOperandDescriptor(cpup, 1, &mod_fault);
10183     setupOperandDescriptor(cpup, 2, &mod_fault);
10184     setupOperandDescriptorCache(cpup,3);
10185 #endif
10186 
10187     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10188     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10189 
10190     L68_ (
10191       // L68 raises it immediately
10192       if (mod_fault)
10193         {
10194           doFault (FAULT_IPR,
10195                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10196                    "Illegal modifier");
10197         }
10198     )
10199 
10200     // Bits 1-8 MBZ
10201     if (IWB_IRODD & 0377000000000)
10202       doFault (FAULT_IPR, fst_ill_op, "ad2d 1-8 MBZ");
10203 
10204     DPS8M_ (
10205       // DPS8M raises it delayed
10206       if (mod_fault)
10207         {
10208           doFault (FAULT_IPR,
10209                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10210                    "Illegal modifier");
10211         }
10212     )
10213 
10214     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10215     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10216     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10217 
10218     PNL (L68_ (if (R)
10219       DU_CYCLE_FRND;))
10220 
10221     uint srcTN = e->TN1;    // type of chars in src
10222 
10223     uint dstTN = e->TN2;    // type of chars in dst
10224     uint dstCN = e->CN2;    // starting at char pos CN
10225 
10226     e->ADDR3 = e->ADDR2;
10227 
10228     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10229 
10230     /*
10231      * Here we need to distinguish between 4 type of numbers.
10232      *
10233      * CSFL - Floating-point, leading sign
10234      * CSLS - Scaled fixed-point, leading sign
10235      * CSTS - Scaled fixed-point, trailing sign
10236      * CSNS - Scaled fixed-point, unsigned
10237      */
10238 
10239     // determine precision
10240     switch(e->S1)
10241     {
10242         case CSFL:
10243             n1 = (int) e->N1 - 1; // need to account for the - sign
10244             if (srcTN == CTN4)
10245                 n1 -= 2;    // 2 4-bit digits exponent
10246             else
10247                 n1 -= 1;    // 1 9-bit digit exponent
10248             sc1 = 0;        // no scaling factor
10249             break;
10250 
10251         case CSLS:
10252         case CSTS:
10253             n1 = (int) e->N1 - 1; // only 1 sign
10254             sc1 = -e->SF1;
10255             break;
10256 
10257         case CSNS:
10258             n1 = (int) e->N1;     // no sign
10259             sc1 = -e->SF1;
10260             break;  // no sign wysiwyg
10261     }
10262 
10263     if (n1 < 1)
10264         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n1<1");
10265 
10266     switch(e->S2)
10267     {
10268         case CSFL:
10269             n2 = (int) e->N2 - 1; // need to account for the sign
10270             if (e->TN2 == CTN4)
10271                 n2 -= 2;    // 2 4-bit digit exponent
10272             else
10273                 n2 -= 1;    // 1 9-bit digit exponent
10274             sc2 = 0;        // no scaling factor
10275             break;
10276 
10277         case CSLS:
10278         case CSTS:
10279             n2 = (int) e->N2 - 1; // 1 sign
10280             sc2 = -e->SF2;
10281             break;
10282 
10283         case CSNS:
10284             n2 = (int) e->N2;     // no sign
10285             sc2 = -e->SF2;
10286             break;  // no sign wysiwyg
10287     }
10288 
10289     if (n2 < 1)
10290         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n2<1");
10291 
10292     decContext set;
10293     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10294     decContextDefaultDPS8(&set);
10295 
10296     set.traps=0;
10297 
10298     decNumber _1, _2, _3;
10299 
10300     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10301 
10302     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10303     if (e->sign == -1)
10304         op1->bits |= DECNEG;
10305     if (e->S1 == CSFL)
10306         op1->exponent = e->exponent;
10307 
10308     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
10309 
10310     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10311     if (e->sign == -1)
10312         op2->bits |= DECNEG;
10313     if (e->S2 == CSFL)
10314         op2->exponent = e->exponent;
10315 
10316     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10317 
10318     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
10319     bool iOvr = 0;
10320     if (op3->digits > 63) {
10321         uint8_t pr[256];
10322         // if sf<=0, trailing zeroes can't be shifted out
10323         // if sf> 0, (some of) trailing zeroes can be shifted out
10324         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10325 
10326         int ctz = 0;
10327         if (sf>0) {     // optimize: we don't care when sf>0
10328             decNumberGetBCD(op3,pr);
10329             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10330                  ctz ++;
10331         }
10332 
10333         if (op3->digits - min(max(sf,0),ctz) > 63) {
10334             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10335             int safe = set.digits;
10336             decNumber tmp;
10337 
10338             // discard MS digits
10339             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10340             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10341             decNumberPlus(&tmp, op3, &set);
10342             set.digits = safe;
10343 
10344             decNumberSubtract(op3, op3, &tmp, &set);
10345 
10346             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10347 
10348             decContextSetRounding(&set, safeR);
10349             iOvr = 1;
10350         }
10351     }
10352 
10353     bool Ovr = false, EOvr = false, Trunc = false;
10354 
10355     uint8_t out [256];
10356     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
10357 
10358     Ovr |= iOvr;
10359 
10360     if (decNumberIsZero(op3))
10361         op3->exponent = 127;
10362 
10363     //(void)printf("%s\r\n", res);
10364 
10365     // now write to memory in proper format.....
10366 
10367     //word18 dstAddr = e->dstAddr;
10368     int pos = (int) dstCN;
10369 
10370     // 1st, take care of any leading sign .......
10371     switch(e->S2)
10372     {
10373         case CSFL:  // floating-point, leading sign.
10374         case CSLS:  // fixed-point, leading sign
10375             switch(dstTN)
10376             {
10377                 case CTN4:
10378                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10379                               //   then the 13(8) plus sign character is placed appropriately
10380                               //   if the result of the operation is positive.
10381                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10382                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10383                     else
10384                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10385                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10386                     break;
10387                 case CTN9:
10388                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10389                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10390                     break;
10391             }
10392             break;
10393 
10394         case CSTS:  // nuttin' to do here .....
10395         case CSNS:
10396             break;  // no sign wysiwyg
10397     }
10398 
10399     // 2nd, write the digits .....
10400     for(int j = 0 ; j < n2 ; j++)
10401         switch(dstTN)
10402         {
10403             case CTN4:
10404                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[j] - '0'));
10405                 break;
10406             case CTN9:
10407                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[j]);
10408                 break;
10409         }
10410 
10411     // 3rd, take care of any trailing sign or exponent ...
10412     switch(e->S2)
10413     {
10414         case CSTS:  // write trailing sign ....
10415             switch(dstTN)
10416             {
10417                 case CTN4:
10418                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10419                               //   then the 13(8) plus sign character is placed appropriately
10420                               //   if the result of the operation is positive.
10421                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10422                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10423                     else
10424                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10425                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10426                     break;
10427                 case CTN9:
10428                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10429                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10430                     break;
10431             }
10432             break;
10433 
10434         case CSFL:  // floating-point, leading sign.
10435             // write the exponent
10436             switch(dstTN)
10437             {
10438                 case CTN4:
10439                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10440                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10441                     break;
10442                 case CTN9:
10443                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10444                     break;
10445             }
10446             break;
10447 
10448         case CSLS:  // fixed point, leading sign - already done
10449         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10450             break;
10451     }
10452 
10453     // set flags, etc ...
10454     if (e->S2 == CSFL)
10455     {
10456         if (op3->exponent > 127)
10457         {
10458             SET_I_EOFL;
10459             EOvr = true;
10460         }
10461         if (op3->exponent < -128)
10462         {
10463             SET_I_EUFL;
10464             EOvr = true;
10465         }
10466     }
10467 
10468     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10469     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10470 
10471     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10472 
10473     cleanupOperandDescriptor (cpup, 1);
10474     cleanupOperandDescriptor (cpup, 2);
10475     cleanupOperandDescriptor (cpup, 3);
10476 
10477     if (TST_I_TRUNC && T && tstOVFfault (cpup))
10478       doFault(FAULT_OFL, fst_zero, "ad2d truncation(overflow) fault");
10479     if (EOvr && tstOVFfault (cpup))
10480         doFault(FAULT_OFL, fst_zero, "ad2d over/underflow fault");
10481     if (Ovr)
10482     {
10483         SET_I_OFLOW;
10484         if (tstOVFfault (cpup))
10485           doFault(FAULT_OFL, fst_zero, "ad2d overflow fault");
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 
10521 
10522 
10523 
10524 
10525 
10526 
10527 
10528 
10529 
10530 /*
10531  * ad3d - Add Using Three Decimal Operands
10532  */
10533 
10534 void ad3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10535 {
10536     EISstruct * e = & cpu.currentEISinstruction;
10537 
10538     fault_ipr_subtype_ mod_fault = 0;
10539 
10540 #if !defined(EIS_SETUP)
10541     setupOperandDescriptor(cpup, 1, &mod_fault);
10542     setupOperandDescriptor(cpup, 2, &mod_fault);
10543     setupOperandDescriptor(cpup, 3, &mod_fault);
10544 #endif
10545 
10546     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10547     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10548     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
10549 
10550     L68_ (
10551       // L68 raises it immediately
10552       if (mod_fault)
10553         {
10554           doFault (FAULT_IPR,
10555                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10556                    "Illegal modifier");
10557         }
10558     )
10559 
10560     // Bit 1 MBZ
10561     if (IWB_IRODD & 0200000000000)
10562       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "ad3d(): 1 MBZ");
10563 
10564     DPS8M_ (
10565       // DPS8M raises it delayed
10566       if (mod_fault)
10567         {
10568           doFault (FAULT_IPR,
10569                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10570                    "Illegal modifier");
10571         }
10572     )
10573 
10574     // initialize mop flags. Probably best done elsewhere.
10575     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10576     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10577     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10578 
10579     PNL (L68_ (if (R)
10580       DU_CYCLE_FRND;))
10581 
10582     uint srcTN = e->TN1;    // type of chars in src
10583 
10584     uint dstTN = e->TN3;    // type of chars in dst
10585     uint dstCN = e->CN3;    // starting at char pos CN
10586 
10587     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
10588 
10589     /*
10590      * Here we need to distinguish between 4 type of numbers.
10591      *
10592      * CSFL - Floating-point, leading sign
10593      * CSLS - Scaled fixed-point, leading sign
10594      * CSTS - Scaled fixed-point, trailing sign
10595      * CSNS - Scaled fixed-point, unsigned
10596      */
10597 
10598     // determine precision
10599     switch(e->S1)
10600     {
10601         case CSFL:
10602             n1 = (int) e->N1 - 1; // need to account for the - sign
10603             if (srcTN == CTN4)
10604                 n1 -= 2;    // 2 4-bit digits exponent
10605             else
10606                 n1 -= 1;    // 1 9-bit digit exponent
10607             sc1 = 0;        // no scaling factor
10608             break;
10609 
10610         case CSLS:
10611         case CSTS:
10612             n1 = (int) e->N1 - 1; // only 1 sign
10613             sc1 = -e->SF1;
10614             break;
10615 
10616         case CSNS:
10617             n1 = (int) e->N1;     // no sign
10618             sc1 = -e->SF1;
10619             break;  // no sign wysiwyg
10620     }
10621 
10622     if (n1 < 1)
10623         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n1<1");
10624 
10625     switch(e->S2)
10626     {
10627         case CSFL:
10628             n2 = (int) e->N2 - 1; // need to account for the sign
10629             if (e->TN2 == CTN4)
10630                 n2 -= 2;    // 2 4-bit digit exponent
10631             else
10632                 n2 -= 1;    // 1 9-bit digit exponent
10633             sc2 = 0;        // no scaling factor
10634             break;
10635 
10636         case CSLS:
10637         case CSTS:
10638             n2 = (int) e->N2 - 1; // 1 sign
10639             sc2 = -e->SF2;
10640             break;
10641 
10642         case CSNS:
10643             n2 = (int) e->N2;     // no sign
10644             sc2 = -e->SF2;
10645             break;  // no sign wysiwyg
10646     }
10647 
10648     if (n2 < 1)
10649         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n2<1");
10650 
10651     switch(e->S3)
10652     {
10653         case CSFL:
10654             n3 = (int) e->N3 - 1; // need to account for the sign
10655             if (dstTN == CTN4)
10656                 n3 -= 2;    // 2 4-bit digit exponent
10657             else
10658                 n3 -= 1;    // 1 9-bit digit exponent
10659             break;
10660 
10661         case CSLS:
10662         case CSTS:
10663             n3 = (int) e->N3 - 1; // 1 sign
10664             break;
10665 
10666         case CSNS:
10667             n3 = (int) e->N3;     // no sign
10668             break;  // no sign wysiwyg
10669     }
10670 
10671     if (n3 < 1)
10672         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n3<1");
10673 
10674     decContext set;
10675     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10676     decContextDefaultDPS8(&set);
10677     set.traps=0;
10678 
10679     decNumber _1, _2, _3;
10680 
10681     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10682 
10683     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10684     if (e->sign == -1)
10685         op1->bits |= DECNEG;
10686     if (e->S1 == CSFL)
10687         op1->exponent = e->exponent;
10688 
10689     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
10690 
10691     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10692     if (e->sign == -1)
10693         op2->bits |= DECNEG;
10694     if (e->S2 == CSFL)
10695         op2->exponent = e->exponent;
10696 
10697     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10698 
10699     // RJ78: significant digits in the result may be lost if:
10700     // The difference between the scaling factors (exponents) of the source
10701     // operands is large enough to cause the expected length of the intermediate
10702     // result to exceed 63 digits after decimal point alignment of source operands, followed by addition.
10703     // ISOLTS 846 07c, 10a, 11b internal register overflow
10704     // trailing zeros are not counted towards the limit
10705 
10706     // XXX it is not clear which digits are lost, but I suppose it should be the most significant.
10707     // ISOLTS doesn't check for this.
10708 
10709     // XXX the algorithm should be similar/the same as dv3d NQ? It is to some extent already...
10710     bool iOvr = 0;
10711     if (op3->digits > 63) {
10712         uint8_t pr[256];
10713         // if sf<=0, trailing zeroes can't be shifted out
10714         // if sf> 0, (some of) trailing zeroes can be shifted out
10715         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10716 
10717         int ctz = 0;
10718         if (sf>0) {     // optimize: we don't care when sf>0
10719             decNumberGetBCD(op3,pr);
10720             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10721                  ctz ++;
10722         }
10723 
10724         if (op3->digits - min(max(sf,0),ctz) > 63) {
10725             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10726             int safe = set.digits;
10727             decNumber tmp;
10728 
10729             // discard MS digits
10730             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10731             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10732             decNumberPlus(&tmp, op3, &set);
10733             set.digits = safe;
10734 
10735             decNumberSubtract(op3, op3, &tmp, &set);
10736 
10737             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
10738 
10739             decContextSetRounding(&set, safeR);
10740             iOvr = 1;
10741         }
10742     }
10743 
10744     bool Ovr = false, EOvr = false, Trunc = false;
10745 
10746     uint8_t out [256];
10747     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
10748 
10749     Ovr |= iOvr;
10750 
10751     if (decNumberIsZero(op3))
10752         op3->exponent = 127;
10753 
10754     //(void)printf("%s\r\n", res);
10755 
10756     // now write to memory in proper format.....
10757 
10758     //word18 dstAddr = e->dstAddr;
10759     int pos = (int) dstCN;
10760 
10761     // 1st, take care of any leading sign .......
10762     switch(e->S3)
10763     {
10764         case CSFL:  // floating-point, leading sign.
10765         case CSLS:  // fixed-point, leading sign
10766             switch(dstTN)
10767             {
10768             case CTN4:
10769                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10770                           //   then the 13(8) plus sign character is placed appropriately
10771                           //   if the result of the operation is positive.
10772                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10773                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10774                 else
10775                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10776                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10777                 break;
10778             case CTN9:
10779                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10780                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10781                 break;
10782             }
10783             break;
10784 
10785         case CSTS:  // nuttin' to do here .....
10786         case CSNS:
10787             break;  // no sign wysiwyg
10788     }
10789 
10790     // 2nd, write the digits .....
10791     for(int i = 0 ; i < n3 ; i++)
10792         switch(dstTN)
10793         {
10794         case CTN4:
10795             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
10796             break;
10797         case CTN9:
10798             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
10799             break;
10800         }
10801 
10802     // 3rd, take care of any trailing sign or exponent ...
10803     switch(e->S3)
10804     {
10805         case CSTS:  // write trailing sign ....
10806             switch(dstTN)
10807             {
10808             case CTN4:
10809                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10810                           //   then the 13(8) plus sign character is placed appropriately
10811                           //   if the result of the operation is positive.
10812                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10813                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10814                 else
10815                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10816                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10817                 break;
10818             case CTN9:
10819                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10820                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10821                 break;
10822             }
10823             break;
10824 
10825         case CSFL:  // floating-point, leading sign.
10826             // write the exponent
10827             switch(dstTN)
10828             {
10829             case CTN4:
10830                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10831                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10832 
10833                     break;
10834             case CTN9:
10835                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10836                 break;
10837             }
10838             break;
10839 
10840         case CSLS:  // fixed point, leading sign - already done
10841         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10842             break;
10843     }
10844 
10845     // set flags, etc ...
10846     if (e->S3 == CSFL)
10847     {
10848         if (op3->exponent > 127)
10849         {
10850             SET_I_EOFL;
10851             EOvr = true;
10852         }
10853         if (op3->exponent < -128)
10854         {
10855             SET_I_EUFL;
10856             EOvr = true;
10857         }
10858     }
10859 
10860     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10861     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10862 
10863     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10864 
10865     cleanupOperandDescriptor (cpup, 1);
10866     cleanupOperandDescriptor (cpup, 2);
10867     cleanupOperandDescriptor (cpup, 3);
10868 
10869     if (TST_I_TRUNC && T && tstOVFfault (cpup))
10870       doFault(FAULT_OFL, fst_zero, "ad3d truncation(overflow) fault");
10871     if (EOvr && tstOVFfault (cpup))
10872         doFault(FAULT_OFL, fst_zero, "ad3d over/underflow fault");
10873     if (Ovr)
10874     {
10875         SET_I_OFLOW;
10876         if (tstOVFfault (cpup))
10877           doFault(FAULT_OFL, fst_zero, "ad3d overflow fault");
10878     }
10879 }
10880 
10881 /*
10882  * sb2d - Subtract Using Two Decimal Operands
10883  */
10884 
10885 void sb2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10886 {
10887     EISstruct * e = & cpu.currentEISinstruction;
10888 
10889     fault_ipr_subtype_ mod_fault = 0;
10890 
10891 #if !defined(EIS_SETUP)
10892     setupOperandDescriptor(cpup, 1, &mod_fault);
10893     setupOperandDescriptor(cpup, 2, &mod_fault);
10894     setupOperandDescriptorCache(cpup,3);
10895 #endif
10896 
10897     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10898     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10899 
10900     L68_ (
10901       // L68 raises it immediately
10902       if (mod_fault)
10903         {
10904           doFault (FAULT_IPR,
10905                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10906                    "Illegal modifier");
10907         }
10908     )
10909 
10910     // Bits 1-8 MBZ
10911     if (IWB_IRODD & 0377000000000)
10912       {
10913         //sim_printf ("sb2d %012"PRIo64"\n", IWB_IRODD);
10914         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb2d 0-8 MBZ");
10915       }
10916 
10917     DPS8M_ (
10918       // DPS8M raises it delayed
10919       if (mod_fault)
10920         {
10921           doFault (FAULT_IPR,
10922                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10923                    "Illegal modifier");
10924         }
10925     )
10926 
10927     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10928     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10929     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10930 
10931     PNL (L68_ (if (R)
10932       DU_CYCLE_FRND;))
10933 
10934     uint srcTN = e->TN1;    // type of chars in src
10935 
10936     uint dstTN = e->TN2;    // type of chars in dst
10937     uint dstCN = e->CN2;    // starting at char pos CN
10938 
10939     e->ADDR3 = e->ADDR2;
10940 
10941     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10942 
10943     /*
10944      * Here we need to distinguish between 4 type of numbers.
10945      *
10946      * CSFL - Floating-point, leading sign
10947      * CSLS - Scaled fixed-point, leading sign
10948      * CSTS - Scaled fixed-point, trailing sign
10949      * CSNS - Scaled fixed-point, unsigned
10950      */
10951 
10952     // determine precision
10953     switch(e->S1)
10954     {
10955         case CSFL:
10956             n1 = (int) e->N1 - 1; // need to account for the - sign
10957             if (srcTN == CTN4)
10958                 n1 -= 2;    // 2 4-bit digits exponent
10959             else
10960                 n1 -= 1;    // 1 9-bit digit exponent
10961             sc1 = 0;        // no scaling factor
10962             break;
10963 
10964         case CSLS:
10965         case CSTS:
10966             n1 = (int) e->N1 - 1; // only 1 sign
10967             sc1 = -e->SF1;
10968             break;
10969 
10970         case CSNS:
10971             n1 = (int) e->N1;     // no sign
10972             sc1 = -e->SF1;
10973             break;  // no sign wysiwyg
10974     }
10975 
10976     if (n1 < 1)
10977         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n1<1");
10978 
10979     switch(e->S2)
10980     {
10981         case CSFL:
10982             n2 = (int) e->N2 - 1; // need to account for the sign
10983             if (e->TN2 == CTN4)
10984                 n2 -= 2;    // 2 4-bit digit exponent
10985             else
10986                 n2 -= 1;    // 1 9-bit digit exponent
10987             sc2 = 0;        // no scaling factor
10988             break;
10989 
10990         case CSLS:
10991         case CSTS:
10992             n2 = (int) e->N2 - 1; // 1 sign
10993             sc2 = -e->SF2;
10994             break;
10995 
10996         case CSNS:
10997             n2 = (int) e->N2;     // no sign
10998             sc2 = -e->SF2;
10999             break;  // no sign wysiwyg
11000     }
11001 
11002     if (n2 < 1)
11003         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n2<1");
11004 
11005     decContext set;
11006     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11007     decContextDefaultDPS8(&set);
11008     set.traps=0;
11009 
11010     decNumber _1, _2, _3;
11011 
11012     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11013 
11014     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11015     if (e->sign == -1)
11016         op1->bits |= DECNEG;
11017     if (e->S1 == CSFL)
11018         op1->exponent = e->exponent;
11019 
11020     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11021 
11022     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11023     if (e->sign == -1)
11024         op2->bits |= DECNEG;
11025     if (e->S2 == CSFL)
11026         op2->exponent = e->exponent;
11027 
11028     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11029 
11030     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11031     bool iOvr = 0;
11032     if (op3->digits > 63) {
11033         uint8_t pr[256];
11034         // if sf<=0, trailing zeroes can't be shifted out
11035         // if sf> 0, (some of) trailing zeroes can be shifted out
11036         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11037 
11038         int ctz = 0;
11039         if (sf>0) {     // optimize: we don't care when sf>0
11040             decNumberGetBCD(op3,pr);
11041             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11042                  ctz ++;
11043         }
11044 
11045         if (op3->digits - min(max(sf,0),ctz) > 63) {
11046             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11047             int safe = set.digits;
11048             decNumber tmp;
11049 
11050             // discard MS digits
11051             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11052             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11053             decNumberPlus(&tmp, op3, &set);
11054             set.digits = safe;
11055 
11056             decNumberSubtract(op3, op3, &tmp, &set);
11057 
11058             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
11059 
11060             decContextSetRounding(&set, safeR);
11061             iOvr = 1;
11062         }
11063     }
11064 
11065     bool Ovr = false, EOvr = false, Trunc = false;
11066 
11067     uint8_t out [256];
11068     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11069 
11070     Ovr |= iOvr;
11071 
11072     if (decNumberIsZero(op3))
11073         op3->exponent = 127;
11074 
11075     //(void)printf("%s\r\n", res);
11076 
11077     // now write to memory in proper format.....
11078 
11079     //word18 dstAddr = e->dstAddr;
11080     int pos = (int) dstCN;
11081 
11082     // 1st, take care of any leading sign .......
11083     switch(e->S2)
11084     {
11085         case CSFL:  // floating-point, leading sign.
11086         case CSLS:  // fixed-point, leading sign
11087             switch(dstTN)
11088             {
11089                 case CTN4:
11090                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11091                               //   then the 13(8) plus sign character is placed appropriately
11092                               //   if the result of the operation is positive.
11093                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11094                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11095                     else
11096                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11097                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11098                     break;
11099                 case CTN9:
11100                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11101                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11102                     break;
11103             }
11104             break;
11105 
11106         case CSTS:  // nuttin' to do here .....
11107         case CSNS:
11108             break;  // no sign wysiwyg
11109     }
11110 
11111     // 2nd, write the digits .....
11112     for(int i = 0 ; i < n2 ; i++)
11113         switch(dstTN)
11114         {
11115             case CTN4:
11116                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11117                 break;
11118             case CTN9:
11119                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11120                 break;
11121         }
11122 
11123     // 3rd, take care of any trailing sign or exponent ...
11124     switch(e->S2)
11125     {
11126         case CSTS:  // write trailing sign ....
11127             switch(dstTN)
11128             {
11129                 case CTN4:
11130                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11131                               //   then the 13(8) plus sign character is placed appropriately
11132                               //   if the result of the operation is positive.
11133                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11134                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11135                     else
11136                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11137                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11138                     break;
11139                 case CTN9:
11140                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11141                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11142                     break;
11143             }
11144             break;
11145 
11146         case CSFL:  // floating-point, leading sign.
11147             // write the exponent
11148             switch(dstTN)
11149             {
11150                 case CTN4:
11151                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11152                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11153 
11154                     break;
11155                 case CTN9:
11156                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11157                     break;
11158             }
11159             break;
11160 
11161         case CSLS:  // fixed point, leading sign - already done
11162         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11163             break;
11164     }
11165 
11166     // set flags, etc ...
11167     if (e->S2 == CSFL)
11168     {
11169         if (op3->exponent > 127)
11170         {
11171             SET_I_EOFL;
11172             EOvr = true;
11173         }
11174         if (op3->exponent < -128)
11175         {
11176             SET_I_EUFL;
11177             EOvr = true;
11178         }
11179     }
11180 
11181     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11182     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11183 
11184     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11185 
11186     cleanupOperandDescriptor (cpup, 1);
11187     cleanupOperandDescriptor (cpup, 2);
11188     cleanupOperandDescriptor (cpup, 3);
11189 
11190     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11191       doFault(FAULT_OFL, fst_zero, "sb2d truncation(overflow) fault");
11192     if (EOvr && tstOVFfault (cpup))
11193         doFault(FAULT_OFL, fst_zero, "sb2d over/underflow fault");
11194     if (Ovr)
11195     {
11196         SET_I_OFLOW;
11197         if (tstOVFfault (cpup))
11198           doFault(FAULT_OFL, fst_zero, "sb2d overflow fault");
11199     }
11200 }
11201 
11202 /*
11203  * sb3d - Subtract Using Three Decimal Operands
11204  */
11205 
11206 void sb3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11207 {
11208     EISstruct * e = & cpu.currentEISinstruction;
11209 
11210     fault_ipr_subtype_ mod_fault = 0;
11211 
11212 #if !defined(EIS_SETUP)
11213     setupOperandDescriptor(cpup, 1, &mod_fault);
11214     setupOperandDescriptor(cpup, 2, &mod_fault);
11215     setupOperandDescriptor(cpup, 3, &mod_fault);
11216 #endif
11217 
11218     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11219     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11220     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
11221 
11222     L68_ (
11223       // L68 raises it immediately
11224       if (mod_fault)
11225         {
11226           doFault (FAULT_IPR,
11227                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11228                    "Illegal modifier");
11229         }
11230     )
11231 
11232     // Bit 1 MBZ
11233     if (IWB_IRODD & 0200000000000)
11234       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb3d(): 1 MBZ");
11235 
11236     DPS8M_ (
11237       // DPS8M raises it delayed
11238       if (mod_fault)
11239         {
11240           doFault (FAULT_IPR,
11241                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11242                    "Illegal modifier");
11243         }
11244     )
11245 
11246     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11247     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11248     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11249 
11250     PNL (L68_ (if (R)
11251       DU_CYCLE_FRND;))
11252 
11253     uint srcTN = e->TN1;    // type of chars in src
11254 
11255     uint dstTN = e->TN3;    // type of chars in dst
11256     uint dstCN = e->CN3;    // starting at char pos CN
11257 
11258     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11259 
11260     /*
11261      * Here we need to distinguish between 4 type of numbers.
11262      *
11263      * CSFL - Floating-point, leading sign
11264      * CSLS - Scaled fixed-point, leading sign
11265      * CSTS - Scaled fixed-point, trailing sign
11266      * CSNS - Scaled fixed-point, unsigned
11267      */
11268 
11269     // determine precision
11270     switch(e->S1)
11271     {
11272         case CSFL:
11273             n1 = (int) e->N1 - 1; // need to account for the - sign
11274             if (srcTN == CTN4)
11275                 n1 -= 2;    // 2 4-bit digits exponent
11276             else
11277                 n1 -= 1;    // 1 9-bit digit exponent
11278             sc1 = 0;        // no scaling factor
11279             break;
11280 
11281         case CSLS:
11282         case CSTS:
11283             n1 = (int) e->N1 - 1; // only 1 sign
11284             sc1 = -e->SF1;
11285             break;
11286 
11287         case CSNS:
11288             n1 = (int) e->N1;     // no sign
11289             sc1 = -e->SF1;
11290             break;  // no sign wysiwyg
11291     }
11292 
11293     if (n1 < 1)
11294         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n1<1");
11295 
11296     switch(e->S2)
11297     {
11298         case CSFL:
11299             n2 = (int) e->N2 - 1; // need to account for the sign
11300             if (e->TN2 == CTN4)
11301                 n2 -= 2;    // 2 4-bit digit exponent
11302             else
11303                 n2 -= 1;    // 1 9-bit digit exponent
11304             sc2 = 0;        // no scaling factor
11305             break;
11306 
11307         case CSLS:
11308         case CSTS:
11309             n2 = (int) e->N2 - 1; // 1 sign
11310             sc2 = -e->SF2;
11311             break;
11312 
11313         case CSNS:
11314             n2 = (int) e->N2;     // no sign
11315             sc2 = -e->SF2;
11316             break;  // no sign wysiwyg
11317     }
11318 
11319     if (n2 < 1)
11320         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n2<1");
11321 
11322     switch(e->S3)
11323     {
11324         case CSFL:
11325             n3 = (int) e->N3 - 1; // need to account for the sign
11326             if (dstTN == CTN4)
11327                 n3 -= 2;    // 2 4-bit digit exponent
11328             else
11329                 n3 -= 1;    // 1 9-bit digit exponent
11330             break;
11331 
11332         case CSLS:
11333         case CSTS:
11334             n3 = (int) e->N3 - 1; // 1 sign
11335             break;
11336 
11337         case CSNS:
11338             n3 = (int) e->N3;     // no sign
11339             break;  // no sign wysiwyg
11340     }
11341 
11342     if (n3 < 1)
11343         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n3<1");
11344 
11345     decContext set;
11346     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11347     decContextDefaultDPS8(&set);
11348 
11349     set.traps=0;
11350 
11351     decNumber _1, _2, _3;
11352 
11353     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11354 
11355     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11356     if (e->sign == -1)
11357         op1->bits |= DECNEG;
11358     if (e->S1 == CSFL)
11359         op1->exponent = e->exponent;
11360 
11361     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11362 
11363     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11364     if (e->sign == -1)
11365         op2->bits |= DECNEG;
11366     if (e->S2 == CSFL)
11367         op2->exponent = e->exponent;
11368 
11369     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11370 
11371     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11372     bool iOvr = 0;
11373     if (op3->digits > 63) {
11374         uint8_t pr[256];
11375         // if sf<=0, trailing zeroes can't be shifted out
11376         // if sf> 0, (some of) trailing zeroes can be shifted out
11377         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11378 
11379         int ctz = 0;
11380         if (sf>0) {     // optimize: we don't care when sf>0
11381             decNumberGetBCD(op3,pr);
11382             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11383                  ctz ++;
11384         }
11385 
11386         if (op3->digits - min(max(sf,0),ctz) > 63) {
11387             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11388             int safe = set.digits;
11389             decNumber tmp;
11390 
11391             // discard MS digits
11392             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11393             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11394             decNumberPlus(&tmp, op3, &set);
11395             set.digits = safe;
11396 
11397             decNumberSubtract(op3, op3, &tmp, &set);
11398 
11399             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\n",pr);
11400 
11401             decContextSetRounding(&set, safeR);
11402             iOvr = 1;
11403         }
11404     }
11405 
11406     bool Ovr = false, EOvr = false, Trunc = false;
11407 
11408     uint8_t out [256];
11409     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11410 
11411     Ovr |= iOvr;
11412 
11413     if (decNumberIsZero(op3))
11414         op3->exponent = 127;
11415 
11416     // now write to memory in proper format.....
11417 
11418     //word18 dstAddr = e->dstAddr;
11419     int pos = (int) dstCN;
11420 
11421     // 1st, take care of any leading sign .......
11422     switch(e->S3)
11423     {
11424         case CSFL:  // floating-point, leading sign.
11425         case CSLS:  // fixed-point, leading sign
11426             switch(dstTN)
11427         {
11428             case CTN4:
11429                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11430                           //   then the 13(8) plus sign character is placed appropriately
11431                           //   if the result of the operation is positive.
11432                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11433                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11434                 else
11435                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11436                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11437                 break;
11438             case CTN9:
11439                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11440                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11441                 break;
11442         }
11443             break;
11444 
11445         case CSTS:  // nuttin' to do here .....
11446         case CSNS:
11447             break;  // no sign wysiwyg
11448     }
11449 
11450     // 2nd, write the digits .....
11451     for(int i = 0 ; i < n3 ; i++)
11452         switch(dstTN)
11453     {
11454         case CTN4:
11455             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11456             break;
11457         case CTN9:
11458             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11459             break;
11460     }
11461 
11462     // 3rd, take care of any trailing sign or exponent ...
11463     switch(e->S3)
11464     {
11465         case CSTS:  // write trailing sign ....
11466             switch(dstTN)
11467             {
11468                 case CTN4:
11469                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11470                               //   then the 13(8) plus sign character is placed appropriately
11471                               //   if the result of the operation is positive.
11472                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11473                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11474                     else
11475                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11476                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11477                     break;
11478                 case CTN9:
11479                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11480                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11481                     break;
11482             }
11483             break;
11484 
11485         case CSFL:  // floating-point, leading sign.
11486             // write the exponent
11487             switch(dstTN)
11488             {
11489                 case CTN4:
11490                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11491                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11492 
11493                     break;
11494                 case CTN9:
11495                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11496                     break;
11497             }
11498             break;
11499 
11500         case CSLS:  // fixed point, leading sign - already done
11501         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11502             break;
11503     }
11504 
11505     // set flags, etc ...
11506     if (e->S3 == CSFL)
11507     {
11508         if (op3->exponent > 127)
11509         {
11510             SET_I_EOFL;
11511             EOvr = true;
11512         }
11513         if (op3->exponent < -128)
11514         {
11515             SET_I_EUFL;
11516             EOvr = true;
11517         }
11518     }
11519 
11520     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11521     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11522 
11523     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11524 
11525     cleanupOperandDescriptor (cpup, 1);
11526     cleanupOperandDescriptor (cpup, 2);
11527     cleanupOperandDescriptor (cpup, 3);
11528 
11529     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11530       doFault(FAULT_OFL, fst_zero, "sb3d truncation(overflow) fault");
11531     if (EOvr && tstOVFfault (cpup))
11532         doFault(FAULT_OFL, fst_zero, "sb3d over/underflow fault");
11533     if (Ovr)
11534     {
11535         SET_I_OFLOW;
11536         if (tstOVFfault (cpup))
11537           doFault(FAULT_OFL, fst_zero, "sb3d overflow fault");
11538     }
11539 }
11540 
11541 /*
11542  * mp2d - Multiply Using Two Decimal Operands
11543  */
11544 
11545 void mp2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11546 {
11547     EISstruct * e = & cpu.currentEISinstruction;
11548 
11549     fault_ipr_subtype_ mod_fault = 0;
11550 
11551 #if !defined(EIS_SETUP)
11552     setupOperandDescriptor(cpup, 1, &mod_fault);
11553     setupOperandDescriptor(cpup, 2, &mod_fault);
11554     setupOperandDescriptorCache(cpup,3);
11555 #endif
11556 
11557     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11558     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11559 
11560     L68_ (
11561       // L68 raises it immediately
11562       if (mod_fault)
11563         {
11564           doFault (FAULT_IPR,
11565                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11566                    "Illegal modifier");
11567         }
11568     )
11569 
11570     // Bits 1-8 MBZ
11571     if (IWB_IRODD & 0377000000000)
11572       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp2d 1-8 MBZ");
11573 
11574     DPS8M_ (
11575       // DPS8M raises it delayed
11576       if (mod_fault)
11577         {
11578           doFault (FAULT_IPR,
11579                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11580                    "Illegal modifier");
11581         }
11582     )
11583 
11584     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11585     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11586     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11587 
11588     PNL (L68_ (if (R)
11589       DU_CYCLE_FRND;))
11590 
11591     uint srcTN = e->TN1;    // type of chars in src
11592 
11593     uint dstTN = e->TN2;    // type of chars in dst
11594     uint dstCN = e->CN2;    // starting at char pos CN
11595 
11596     e->ADDR3 = e->ADDR2;
11597 
11598     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
11599 
11600     /*
11601      * Here we need to distinguish between 4 type of numbers.
11602      *
11603      * CSFL - Floating-point, leading sign
11604      * CSLS - Scaled fixed-point, leading sign
11605      * CSTS - Scaled fixed-point, trailing sign
11606      * CSNS - Scaled fixed-point, unsigned
11607      */
11608 
11609     // determine precision
11610     switch(e->S1)
11611     {
11612         case CSFL:
11613             n1 = (int) e->N1 - 1; // need to account for the - sign
11614             if (srcTN == CTN4)
11615                 n1 -= 2;    // 2 4-bit digits exponent
11616             else
11617                 n1 -= 1;    // 1 9-bit digit exponent
11618             sc1 = 0;        // no scaling factor
11619             break;
11620 
11621         case CSLS:
11622         case CSTS:
11623             n1 = (int) e->N1 - 1; // only 1 sign
11624             sc1 = -e->SF1;
11625             break;
11626 
11627         case CSNS:
11628             n1 = (int) e->N1;     // no sign
11629             sc1 = -e->SF1;
11630             break;  // no sign wysiwyg
11631     }
11632 
11633     if (n1 < 1)
11634         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n1<1");
11635 
11636     switch(e->S2)
11637     {
11638         case CSFL:
11639             n2 = (int) e->N2 - 1; // need to account for the sign
11640             if (e->TN2 == CTN4)
11641                 n2 -= 2;    // 2 4-bit digit exponent
11642             else
11643                 n2 -= 1;    // 1 9-bit digit exponent
11644             sc2 = 0;        // no scaling factor
11645             break;
11646 
11647         case CSLS:
11648         case CSTS:
11649             n2 = (int) e->N2 - 1; // 1 sign
11650             sc2 = -e->SF2;
11651             break;
11652 
11653         case CSNS:
11654             n2 = (int) e->N2;     // no sign
11655             sc2 = -e->SF2;
11656             break;  // no sign wysiwyg
11657     }
11658 
11659     if (n2 < 1)
11660         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n2<1");
11661 
11662     decContext set;
11663     decContextDefaultDPS8Mul(&set); // 126 digits for multiply
11664 
11665     set.traps=0;
11666 
11667     decNumber _1, _2, _3;
11668 
11669     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11670 
11671     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11672     if (e->sign == -1)
11673         op1->bits |= DECNEG;
11674     if (e->S1 == CSFL)
11675         op1->exponent = e->exponent;
11676 
11677     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11678 
11679     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11680     if (e->sign == -1)
11681         op2->bits |= DECNEG;
11682     if (e->S2 == CSFL)
11683         op2->exponent = e->exponent;
11684 
11685     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11686 
11687     bool Ovr = false, EOvr = false, Trunc = false;
11688 
11689     uint8_t out [256];
11690     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11691 
11692     if (decNumberIsZero(op3))
11693         op3->exponent = 127;
11694 
11695     // now write to memory in proper format.....
11696 
11697     //word18 dstAddr = e->dstAddr;
11698     int pos = (int) dstCN;
11699 
11700     // 1st, take care of any leading sign .......
11701     switch(e->S2)
11702     {
11703         case CSFL:  // floating-point, leading sign.
11704         case CSLS:  // fixed-point, leading sign
11705             switch(dstTN)
11706         {
11707             case CTN4:
11708                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11709                           //   then the 13(8) plus sign character is placed appropriately
11710                           //   if the result of the operation is positive.
11711                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11712                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11713                 else
11714                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11715                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11716                 break;
11717             case CTN9:
11718                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11719                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11720                 break;
11721         }
11722             break;
11723 
11724         case CSTS:  // nuttin' to do here .....
11725         case CSNS:
11726             break;  // no sign wysiwyg
11727     }
11728 
11729     // 2nd, write the digits .....
11730     for(int i = 0 ; i < n2 ; i++)
11731         switch(dstTN)
11732     {
11733         case CTN4:
11734             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11735             break;
11736         case CTN9:
11737             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11738             break;
11739     }
11740 
11741     // 3rd, take care of any trailing sign or exponent ...
11742     switch(e->S2)
11743     {
11744         case CSTS:  // write trailing sign ....
11745             switch(dstTN)
11746         {
11747             case CTN4:
11748                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11749                           //   then the 13(8) plus sign character is placed appropriately
11750                           //   if the result of the operation is positive.
11751                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11752                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11753                 else
11754                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11755                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11756                 break;
11757             case CTN9:
11758                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11759                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11760                 break;
11761         }
11762             break;
11763 
11764         case CSFL:  // floating-point, leading sign.
11765             // write the exponent
11766             switch(dstTN)
11767             {
11768                 case CTN4:
11769                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11770                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11771 
11772                     break;
11773                 case CTN9:
11774                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11775                     break;
11776             }
11777             break;
11778 
11779         case CSLS:  // fixed point, leading sign - already done
11780         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11781             break;
11782     }
11783 
11784     // set flags, etc ...
11785     if (e->S2 == CSFL)
11786     {
11787         if (op3->exponent > 127)
11788         {
11789             SET_I_EOFL;
11790             EOvr = true;
11791         }
11792         if (op3->exponent < -128)
11793         {
11794             SET_I_EUFL;
11795             EOvr = true;
11796         }
11797     }
11798 
11799     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11800     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11801 
11802     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11803 
11804     cleanupOperandDescriptor (cpup, 1);
11805     cleanupOperandDescriptor (cpup, 2);
11806     cleanupOperandDescriptor (cpup, 3);
11807 
11808     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11809       doFault(FAULT_OFL, fst_zero, "mp2d truncation(overflow) fault");
11810     if (EOvr && tstOVFfault (cpup))
11811         doFault(FAULT_OFL, fst_zero, "mp2d over/underflow fault");
11812     if (Ovr)
11813     {
11814         SET_I_OFLOW;
11815         if (tstOVFfault (cpup))
11816           doFault(FAULT_OFL, fst_zero, "mp2d overflow fault");
11817     }
11818 }
11819 
11820 /*
11821  * mp3d - Multiply Using Three Decimal Operands
11822  */
11823 
11824 void mp3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11825 {
11826     EISstruct * e = & cpu.currentEISinstruction;
11827 
11828     fault_ipr_subtype_ mod_fault = 0;
11829 
11830 #if !defined(EIS_SETUP)
11831     setupOperandDescriptor(cpup, 1, &mod_fault);
11832     setupOperandDescriptor(cpup, 2, &mod_fault);
11833     setupOperandDescriptor(cpup, 3, &mod_fault);
11834 #endif
11835 
11836     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11837     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11838     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
11839 
11840     L68_ (
11841       // L68 raises it immediately
11842       if (mod_fault)
11843         {
11844           doFault (FAULT_IPR,
11845                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11846                    "Illegal modifier");
11847         }
11848     )
11849 
11850     // Bit 1 MBZ
11851     if (IWB_IRODD & 0200000000000)
11852       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp3d(): 1 MBZ");
11853 
11854     DPS8M_ (
11855       // DPS8M raises it delayed
11856       if (mod_fault)
11857         {
11858           doFault (FAULT_IPR,
11859                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11860                    "Illegal modifier");
11861         }
11862     )
11863 
11864     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11865     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11866     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11867 
11868     PNL (L68_ (if (R)
11869       DU_CYCLE_FRND;))
11870 
11871     uint srcTN = e->TN1;    // type of chars in src
11872 
11873     uint dstTN = e->TN3;    // type of chars in dst
11874     uint dstCN = e->CN3;    // starting at char pos CN
11875 
11876     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11877 
11878     /*
11879      * Here we need to distinguish between 4 type of numbers.
11880      *
11881      * CSFL - Floating-point, leading sign
11882      * CSLS - Scaled fixed-point, leading sign
11883      * CSTS - Scaled fixed-point, trailing sign
11884      * CSNS - Scaled fixed-point, unsigned
11885      */
11886 
11887     // determine precision
11888     switch(e->S1)
11889     {
11890         case CSFL:
11891             n1 = (int) e->N1 - 1; // need to account for the - sign
11892             if (srcTN == CTN4)
11893                 n1 -= 2;    // 2 4-bit digits exponent
11894             else
11895                 n1 -= 1;    // 1 9-bit digit exponent
11896             sc1 = 0;        // no scaling factor
11897             break;
11898 
11899         case CSLS:
11900         case CSTS:
11901             n1 = (int) e->N1 - 1; // only 1 sign
11902             sc1 = -e->SF1;
11903             break;
11904 
11905         case CSNS:
11906             n1 = (int) e->N1;     // no sign
11907             sc1 = -e->SF1;
11908             break;  // no sign wysiwyg
11909     }
11910 
11911     if (n1 < 1)
11912         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n1<1");
11913 
11914     switch(e->S2)
11915     {
11916         case CSFL:
11917             n2 = (int) e->N2 - 1; // need to account for the sign
11918             if (e->TN2 == CTN4)
11919                 n2 -= 2;    // 2 4-bit digit exponent
11920             else
11921                 n2 -= 1;    // 1 9-bit digit exponent
11922             sc2 = 0;        // no scaling factor
11923             break;
11924 
11925         case CSLS:
11926         case CSTS:
11927             n2 = (int) e->N2 - 1; // 1 sign
11928             sc2 = -e->SF2;
11929             break;
11930 
11931         case CSNS:
11932             n2 = (int) e->N2;     // no sign
11933             sc2 = -e->SF2;
11934             break;  // no sign wysiwyg
11935     }
11936 
11937     if (n2 < 1)
11938         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n2<1");
11939 
11940     switch(e->S3)
11941     {
11942         case CSFL:
11943             n3 = (int) e->N3 - 1; // need to account for the sign
11944             if (dstTN == CTN4)
11945                 n3 -= 2;    // 2 4-bit digit exponent
11946             else
11947                 n3 -= 1;    // 1 9-bit digit exponent
11948             break;
11949 
11950         case CSLS:
11951         case CSTS:
11952             n3 = (int) e->N3 - 1; // 1 sign
11953             break;
11954 
11955         case CSNS:
11956             n3 = (int) e->N3;     // no sign
11957             break;  // no sign wysiwyg
11958     }
11959 
11960     if (n3 < 1)
11961         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n3<1");
11962 
11963     decContext set;
11964     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11965     decContextDefaultDPS8Mul(&set);     // 126 digits for multiply
11966 
11967     set.traps=0;
11968 
11969     decNumber _1, _2, _3;
11970 
11971     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11972 
11973     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11974     if (e->sign == -1)
11975         op1->bits |= DECNEG;
11976     if (e->S1 == CSFL)
11977         op1->exponent = e->exponent;
11978 
11979     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11980 
11981     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11982     if (e->sign == -1)
11983         op2->bits |= DECNEG;
11984     if (e->S2 == CSFL)
11985         op2->exponent = e->exponent;
11986 
11987     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11988 
11989 //    char c1[1024];
11990 //    char c2[1024];
11991 //    char c3[1024];
11992 //
11993 //    decNumberToString(op1, c1);
11994 //    sim_printf("c1:%s\n", c1);
11995 //    decNumberToString(op2, c2);
11996 //    sim_printf("c2:%s\n", c2);
11997 //    decNumberToString(op3, c3);
11998 //    sim_printf("c3:%s\n", c3);
11999 
12000     bool Ovr = false, EOvr = false, Trunc = false;
12001 
12002     uint8_t out [256];
12003     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
12004 
12005     if (decNumberIsZero(op3))
12006         op3->exponent = 127;
12007 
12008     // now write to memory in proper format.....
12009 
12010     //word18 dstAddr = e->dstAddr;
12011     int pos = (int) dstCN;
12012 
12013     // 1st, take care of any leading sign .......
12014     switch(e->S3)
12015     {
12016         case CSFL:  // floating-point, leading sign.
12017         case CSLS:  // fixed-point, leading sign
12018             switch(dstTN)
12019             {
12020             case CTN4:
12021               if (e->P) // If TN2 and S2 specify a 4-bit signed number and P
12022                           // = 1, then the 13(8) plus sign character is placed
12023                           // appropriately if the result of the operation is
12024                           // positive.
12025                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12026                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
12027                 else
12028                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12029                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
12030                 break;
12031             case CTN9:
12032                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12033                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
12034                 break;
12035             }
12036             break;
12037 
12038         case CSTS:  // nuttin' to do here .....
12039         case CSNS:
12040             break;  // no sign wysiwyg
12041     }
12042 
12043     // 2nd, write the digits .....
12044     for(int i = 0 ; i < n3 ; i++)
12045         switch(dstTN)
12046         {
12047             case CTN4:
12048                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
12049                 break;
12050             case CTN9:
12051                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
12052                 break;
12053         }
12054 
12055         // 3rd, take care of any trailing sign or exponent ...
12056     switch(e->S3)
12057     {
12058         case CSTS:  // write trailing sign ....
12059             switch(dstTN)
12060             {
12061                 case CTN4:
12062                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
12063                               //  then the 13(8) plus sign character is placed appropriately
12064                               //  if the result of the operation is positive.
12065                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12066                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
12067                     else
12068                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12069                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
12070                     break;
12071                 case CTN9:
12072                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12073                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
12074                     break;
12075             }
12076             break;
12077 
12078         case CSFL:  // floating-point, leading sign.
12079             // write the exponent
12080             switch(dstTN)
12081             {
12082                 case CTN4:
12083                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
12084                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
12085                     break;
12086                 case CTN9:
12087                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
12088                     break;
12089             }
12090             break;
12091 
12092         case CSLS:  // fixed point, leading sign - already done
12093         case CSNS:  // fixed point, unsigned - nuttin' needed to do
12094             break;
12095     }
12096 
12097     // set flags, etc ...
12098     if (e->S3 == CSFL)
12099     {
12100         if (op3->exponent > 127)
12101         {
12102             SET_I_EOFL;
12103             EOvr = true;
12104         }
12105         if (op3->exponent < -128)
12106         {
12107             SET_I_EUFL;
12108             EOvr = true;
12109         }
12110     }
12111 
12112     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
12113     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
12114 
12115     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
12116 
12117     cleanupOperandDescriptor (cpup, 1);
12118     cleanupOperandDescriptor (cpup, 2);
12119     cleanupOperandDescriptor (cpup, 3);
12120 
12121     if (TST_I_TRUNC && T && tstOVFfault (cpup))
12122       doFault(FAULT_OFL, fst_zero, "mp3d truncation(overflow) fault");
12123     if (EOvr && tstOVFfault (cpup))
12124         doFault(FAULT_OFL, fst_zero, "mp3d over/underflow fault");
12125     if (Ovr)
12126     {
12127         SET_I_OFLOW;
12128         if (tstOVFfault (cpup))
12129           doFault(FAULT_OFL, fst_zero, "mp3d overflow fault");
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 
12873 
12874 
12875 
12876 
12877 
12878 
12879 
12880 
12881 
12882 /*
12883  * dv2d - Divide Using Two Decimal Operands
12884  */
12885 
12886 void dv2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
12887 {
12888     EISstruct * e = & cpu.currentEISinstruction;
12889 
12890     fault_ipr_subtype_ mod_fault = 0;
12891 
12892 #if !defined(EIS_SETUP)
12893     setupOperandDescriptor(cpup, 1, &mod_fault);
12894     setupOperandDescriptor(cpup, 2, &mod_fault);
12895     setupOperandDescriptorCache(cpup, 3);
12896 #endif
12897 
12898     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
12899     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
12900 
12901     L68_ (
12902       // L68 raises it immediately
12903       if (mod_fault)
12904         {
12905           doFault (FAULT_IPR,
12906                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12907                    "Illegal modifier");
12908         }
12909     )
12910 
12911     // Bits 1-8 MBZ
12912     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ as well
12913     if (IWB_IRODD & 0377400000000)
12914       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv2d 1-9 MBZ");
12915 
12916     DPS8M_ (
12917       // DPS8M raises it delayed
12918       if (mod_fault)
12919         {
12920           doFault (FAULT_IPR,
12921                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
12922                    "Illegal modifier");
12923         }
12924     )
12925 
12926     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
12927     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
12928     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
12929 
12930     PNL (L68_ (if (R)
12931       DU_CYCLE_FRND;))
12932 
12933     uint srcTN = e->TN1;    // type of chars in src
12934 
12935     uint dstTN = e->TN2;    // type of chars in dst
12936     uint dstCN = e->CN2;    // starting at char pos CN
12937 
12938     e->ADDR3 = e->ADDR2;
12939 
12940     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
12941 
12942     /*
12943      * Here we need to distinguish between 4 type of numbers.
12944      *
12945      * CSFL - Floating-point, leading sign
12946      * CSLS - Scaled fixed-point, leading sign
12947      * CSTS - Scaled fixed-point, trailing sign
12948      * CSNS - Scaled fixed-point, unsigned
12949      */
12950 
12951     // determine precision
12952     switch(e->S1)
12953     {
12954         case CSFL:
12955             n1 = (int) e->N1 - 1; // need to account for the - sign
12956             if (srcTN == CTN4)
12957                 n1 -= 2;    // 2 4-bit digits exponent
12958             else
12959                 n1 -= 1;    // 1 9-bit digit exponent
12960             sc1 = 0;        // no scaling factor
12961             break;
12962 
12963         case CSLS:
12964         case CSTS:
12965             n1 = (int) e->N1 - 1; // only 1 sign
12966             sc1 = -e->SF1;
12967             break;
12968 
12969         case CSNS:
12970             n1 = (int) e->N1;     // no sign
12971             sc1 = -e->SF1;
12972             break;  // no sign wysiwyg
12973     }
12974 
12975     if (n1 < 1)
12976         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n1<1");
12977 
12978     switch(e->S2)
12979     {
12980         case CSFL:
12981             n2 = (int) e->N2 - 1; // need to account for the sign
12982             if (e->TN2 == CTN4)
12983                 n2 -= 2;    // 2 4-bit digit exponent
12984             else
12985                 n2 -= 1;    // 1 9-bit digit exponent
12986             sc2 = 0;        // no scaling factor
12987             break;
12988 
12989         case CSLS:
12990         case CSTS:
12991             n2 = (int) e->N2 - 1; // 1 sign
12992             sc2 = -e->SF2;
12993             break;
12994 
12995         case CSNS:
12996             n2 = (int) e->N2;     // no sign
12997             sc2 = -e->SF2;
12998             break;  // no sign wysiwyg
12999     }
13000 
13001     if (n2 < 1)
13002         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n2<1");
13003 
13004     decContext set;
13005     decContextDefaultDPS8(&set);
13006 
13007     set.traps=0;
13008 
13009     decNumber _1, _2, _3;
13010 
13011     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
13012 
13013     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);    // divisor
13014     if (e->sign == -1)
13015         op1->bits |= DECNEG;
13016     if (e->S1 == CSFL)
13017         op1->exponent = e->exponent;
13018 
13019     // check for divide by 0!
13020     if (decNumberIsZero(op1))
13021     {
13022         doFault(FAULT_DIV, fst_zero, "dv2d division by 0");
13023     }
13024 
13025     word9   inBufferop1 [64];
13026     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13027 
13028     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
13029 
13030     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);    // dividend
13031     if (e->sign == -1)
13032         op2->bits |= DECNEG;
13033     if (e->S2 == CSFL)
13034         op2->exponent = e->exponent;
13035 
13036     int NQ;
13037     if (e->S2 == CSFL)
13038     {
13039         NQ = n2;
13040     }
13041     else
13042     {
13043         // count leading zeroes
13044         // TODO optimize - can these be somehow extracted from decNumbers?
13045         int clz1, clz2, i;
13046         for (i=0; i < op1->digits; i++)
13047             if (inBufferop1[i]!=0)
13048                 break;
13049         clz1 = i;
13050         for (i=0; i < op2->digits; i++)
13051             if (e->inBuffer[i]!=0) // this still holds op2 digits
13052                 break;
13053         clz2 = i;
13054         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: clz1 %d clz2 %d\n",clz1,clz2);
13055 
13056         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13057         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13058         NQ = (n2-clz2+1) - (n1-clz1) + (-(e->S1==CSFL?op1->exponent:(int)e->SF1));
13059 
13060 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",
13061            e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF2,NQ);
13062     }
13063     if (NQ > 63)
13064         doFault(FAULT_DIV, fst_zero, "dv2d NQ>63");
13065     // Note: NQ is currently unused apart from this FAULT_DIV check.
13066     // decNumber produces more digits than required, but they are then rounded/truncated
13067 
13068     // Yes, they're switched. op1=divisor
13069     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13070     // Note DPS88 and DPS9000 are different when NQ <= 0
13071     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13072     // ISOLTS-817 05b
13073 
13074     PRINTDEC("op2", op2);
13075     PRINTDEC("op1", op1);
13076     PRINTDEC("op3", op3);
13077 
13078     // let's check division results to see for anomalous conditions
13079     if (
13080         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13081         (set.status & DEC_Invalid_operation) ||
13082         (set.status & DEC_Division_by_zero)
13083         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv2d anomalous results"); } // divide by zero has already been checked before
13084 
13085     if (e->S2 == CSFL)
13086     {
13087         // justify CSFL left
13088         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13089         // Note DPS88 and DPS9000 are different
13090         // ISOLTS-817 06c,06e
13091 
13092         decNumber _sf;
13093 
13094         if (n2 - op3->digits > 0)
13095         {
13096             decNumberFromInt32(&_sf, op3->exponent - (n2 - op3->digits));
13097             PRINTDEC("Value 1", op3)
13098             PRINTDEC("Value sf", &_sf)
13099             op3 = decNumberRescale(op3, op3, &_sf, &set);
13100             PRINTDEC("Value 2", op3)
13101         }
13102     }
13103 
13104     bool Ovr = false, EOvr = false, Trunc = false;
13105     uint8_t out[256];
13106 
13107     // CSFL: If the divisor is greater than the dividend after operand
13108     // alignment, the leading zero digit produced is counted and the effective
13109     // precision of the result is reduced by one.
13110     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13111     // Note DPS88 and DPS9000 are different
13112     //
13113     // "greater after operand alignment" means scale until most-significant digits
13114     //   are nonzero, then compare magnitudes ignoring exponents
13115     // This passes ISOLTS-817 06e, ET 458,461,483,486
13116     char *res;
13117     if (e->S2 == CSFL) {
13118         decNumber _1a;
13119         decNumber _2a;
13120         decNumber _sf;
13121         if (op1->digits >= op2->digits) {
13122             // scale op2
13123             decNumberCopy(&_1a, op1);
13124             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13125             decNumberShift(&_2a, op2, &_sf, &set);
13126         } else if (op1->digits < op2->digits) {
13127             // scale op1
13128             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13129             decNumberShift(&_1a, op1, &_sf, &set);
13130             decNumberCopy(&_2a, op2);
13131         }
13132         _1a.exponent = 0;
13133         _2a.exponent = 0;
13134 
13135         PRINTDEC("dv2d: op1a", &_1a);
13136         PRINTDEC("dv2d: op2a", &_2a);
13137         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\n",
13138                    op1->exponent,op2->exponent,op1->digits,op2->digits,_1a.digits,_2a.digits);
13139 
13140         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13141             // shorten the result field to get proper rounding
13142             res = formatDecimal(out, &set, op3, n2 -1, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13143 
13144             // prepend zero digit
13145             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13146             for (int i = n2; i > 0; i--) // incl.zero terminator
13147                  res[i] = res[i-1];
13148             res[0] = '0';
13149             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: addzero n2 %d %s exp %d\n",n2,res,op3->exponent);
13150         } else {
13151             // full n2 digits are returned
13152             res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13153         }
13154     } else {
13155         // same as all other decimal instructions
13156         res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13157     }
13158 
13159     if (decNumberIsZero(op3))
13160         op3->exponent = 127;
13161 
13162     // now write to memory in proper format.....
13163 
13164     int pos = (int) dstCN;
13165 
13166     // 1st, take care of any leading sign .......
13167     switch(e->S2)
13168     {
13169         case CSFL:  // floating-point, leading sign.
13170         case CSLS:  // fixed-point, leading sign
13171             switch(dstTN)
13172             {
13173                 case CTN4:
13174                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13175                               //   then the 13(8) plus sign character is placed appropriately
13176                               //   if the result of the operation is positive.
13177                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13178                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13179                     else
13180                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13181                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13182                     break;
13183                 case CTN9:
13184                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13185                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13186                     break;
13187             }
13188             break;
13189 
13190         case CSTS:  // nuttin' to do here .....
13191         case CSNS:
13192             break;  // no sign wysiwyg
13193     }
13194 
13195     // 2nd, write the digits .....
13196     for(int i = 0 ; i < n2 ; i++)
13197         switch(dstTN)
13198         {
13199             case CTN4:
13200                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13201                 break;
13202             case CTN9:
13203                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13204                 break;
13205         }
13206 
13207     // 3rd, take care of any trailing sign or exponent ...
13208     switch(e->S2)
13209     {
13210         case CSTS:  // write trailing sign ....
13211             switch(dstTN)
13212             {
13213                 case CTN4:
13214                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13215                               //   then the 13(8) plus sign character is placed appropriately
13216                               //   if the result of the operation is positive.
13217                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13218                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13219                     else
13220                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13221                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13222                     break;
13223                 case CTN9:
13224                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13225                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13226                     break;
13227             }
13228             break;
13229 
13230         case CSFL:  // floating-point, leading sign.
13231             // write the exponent
13232             switch(dstTN)
13233             {
13234                 case CTN4:
13235                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13236                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13237                     break;
13238                 case CTN9:
13239                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13240                     break;
13241             }
13242             break;
13243 
13244         case CSLS:  // fixed point, leading sign - already done
13245         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13246             break;
13247     }
13248 
13249     // set flags, etc ...
13250     if (e->S2 == CSFL)
13251     {
13252         if (op3->exponent > 127)
13253         {
13254             SET_I_EOFL;
13255             EOvr = true;
13256         }
13257         if (op3->exponent < -128)
13258         {
13259             SET_I_EUFL;
13260             EOvr = true;
13261         }
13262     }
13263 
13264     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13265     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13266 
13267     //SC_I_TRUNC (!R && Trunc); // no truncation flag for divide
13268 
13269     cleanupOperandDescriptor (cpup, 1);
13270     cleanupOperandDescriptor (cpup, 2);
13271     cleanupOperandDescriptor (cpup, 3);
13272 
13273     //if (TST_I_TRUNC && T && tstOVFfault (cpup))
13274     //  doFault(FAULT_OFL, fst_zero, "dv2d truncation(overflow) fault");
13275     if (EOvr && tstOVFfault (cpup))
13276         doFault(FAULT_OFL, fst_zero, "dv2d over/underflow fault");
13277     if (Ovr)
13278     {
13279         SET_I_OFLOW;
13280         if (tstOVFfault (cpup))
13281           doFault(FAULT_OFL, fst_zero, "dv2d overflow fault");
13282     }
13283 }
13284 
13285 /*
13286  * dv3d - Divide Using Three Decimal Operands
13287  */
13288 
13289 void dv3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
13290 
13291 {
13292     EISstruct * e = & cpu.currentEISinstruction;
13293 
13294     fault_ipr_subtype_ mod_fault = 0;
13295 
13296 #if !defined(EIS_SETUP)
13297     setupOperandDescriptor(cpup, 1, &mod_fault);
13298     setupOperandDescriptor(cpup, 2, &mod_fault);
13299     setupOperandDescriptor(cpup, 3, &mod_fault);
13300 #endif
13301 
13302     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
13303     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
13304     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
13305 
13306     L68_ (
13307       // L68 raises it immediately
13308       if (mod_fault)
13309         {
13310           doFault (FAULT_IPR,
13311                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13312                    "Illegal modifier");
13313         }
13314     )
13315 
13316     // Bit 1 MBZ
13317     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ
13318     if (IWB_IRODD & 0200400000000)
13319       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv3d(): 1,9 MBZ");
13320 
13321     DPS8M_ (
13322       // DPS8M raises it delayed
13323       if (mod_fault)
13324         {
13325           doFault (FAULT_IPR,
13326                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13327                    "Illegal modifier");
13328         }
13329     )
13330 
13331     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
13332     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
13333     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
13334 
13335     PNL (L68_ (if (R)
13336       DU_CYCLE_FRND;))
13337 
13338     uint srcTN = e->TN1;    // type of chars in src
13339 
13340     uint dstTN = e->TN3;    // type of chars in dst
13341     uint dstCN = e->CN3;    // starting at char pos CN
13342 
13343     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
13344 
13345     /*
13346      * Here we need to distinguish between 4 type of numbers.
13347      *
13348      * CSFL - Floating-point, leading sign
13349      * CSLS - Scaled fixed-point, leading sign
13350      * CSTS - Scaled fixed-point, trailing sign
13351      * CSNS - Scaled fixed-point, unsigned
13352      */
13353 
13354     // determine precision
13355     switch(e->S1)
13356     {
13357         case CSFL:
13358             n1 = (int) e->N1 - 1; // need to account for the - sign
13359             if (srcTN == CTN4)
13360                 n1 -= 2;    // 2 4-bit digits exponent
13361             else
13362                 n1 -= 1;    // 1 9-bit digit exponent
13363             sc1 = 0;        // no scaling factor
13364             break;
13365 
13366         case CSLS:
13367         case CSTS:
13368             n1 = (int) e->N1 - 1; // only 1 sign
13369             sc1 = -e->SF1;
13370             break;
13371 
13372         case CSNS:
13373             n1 = (int) e->N1;     // no sign
13374             sc1 = -e->SF1;
13375             break;  // no sign wysiwyg
13376     }
13377 
13378     if (n1 < 1)
13379         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n1<1");
13380 
13381     switch(e->S2)
13382     {
13383         case CSFL:
13384             n2 = (int) e->N2 - 1; // need to account for the sign
13385             if (e->TN2 == CTN4)
13386                 n2 -= 2;    // 2 4-bit digit exponent
13387             else
13388                 n2 -= 1;    // 1 9-bit digit exponent
13389             sc2 = 0;        // no scaling factor
13390             break;
13391 
13392         case CSLS:
13393         case CSTS:
13394             n2 = (int) e->N2 - 1; // 1 sign
13395             sc2 = -e->SF2;
13396             break;
13397 
13398         case CSNS:
13399             n2 = (int) e->N2;     // no sign
13400             sc2 = -e->SF2;
13401             break;  // no sign wysiwyg
13402     }
13403 
13404     if (n2 < 1)
13405         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n2<1");
13406 
13407     switch(e->S3)
13408     {
13409         case CSFL:
13410             n3 = (int) e->N3 - 1; // need to account for the sign
13411             if (dstTN == CTN4)
13412                 n3 -= 2;    // 2 4-bit digit exponent
13413             else
13414                 n3 -= 1;    // 1 9-bit digit exponent
13415             break;
13416 
13417         case CSLS:
13418         case CSTS:
13419             n3 = (int) e->N3 - 1; // 1 sign
13420             break;
13421 
13422         case CSNS:
13423             n3 = (int) e->N3;     // no sign
13424             break;  // no sign wysiwyg
13425     }
13426     if (n3 < 1)
13427         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n3<1");
13428 
13429     decContext set;
13430     decContextDefaultDPS8(&set);
13431 
13432     set.traps=0;
13433 
13434     decNumber _1, _2, _3;
13435 
13436     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
13437 
13438     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
13439     //PRINTDEC("op1", op1);
13440     if (e->sign == -1)
13441         op1->bits |= DECNEG;
13442     if (e->S1 == CSFL)
13443         op1->exponent = e->exponent;
13444 
13445     // check for divide by 0!
13446     if (decNumberIsZero(op1))
13447     {
13448         doFault(FAULT_DIV, fst_zero, "dv3d division by 0");
13449     }
13450 
13451     word9   inBufferop1 [64];
13452     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13453 
13454     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
13455 
13456     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
13457     if (e->sign == -1)
13458         op2->bits |= DECNEG;
13459     if (e->S2 == CSFL)
13460         op2->exponent = e->exponent;
13461 
13462     // The number of required quotient digits, NQ, is determined before
13463     // division begins as follows:
13464     //  1) Floating-point quotient
13465     //      NQ = N3
13466     //  2) Fixed-point quotient
13467     //    NQ = (N2-LZ2+1) - (N1-LZ1) + (E2-E1-SF3)
13468     //    where: Nn = given operand field length
13469     //        LZn = leading zero count for operand n
13470     //        En = exponent of operand n
13471     //        SF3 = scaling factor of quotient
13472     // 3) Rounding
13473     //    If rounding is specified (R = 1), then one extra quotient digit is
13474     //    produced.
13475     // Note: rule 3 is already handled by formatDecimal rounding
13476     // Nn doesn't represent full field length, but length without sign and exponent (RJ78/DH03 seems like)
13477 
13478     int NQ;
13479     if (e->S3 == CSFL)
13480     {
13481         NQ = n3;
13482     }
13483     else
13484     {
13485         // count leading zeroes
13486         // TODO optimize - can these be somehow extracted from decNumbers?
13487         int clz1, clz2, i;
13488         for (i=0; i < op1->digits; i++)
13489             if (inBufferop1[i]!=0)
13490                 break;
13491         clz1 = i;
13492         for (i=0; i < op2->digits; i++)
13493             if (e->inBuffer[i]!=0) // this still holds op2 digits
13494                 break;
13495         clz2 = i;
13496         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: clz1 %d clz2 %d\n",clz1,clz2);
13497 
13498         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13499         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13500         NQ = (n2-clz2+1) - (n1-clz1) + \
13501                 ((e->S2==CSFL?op2->exponent:(int)e->SF2)-(e->S1==CSFL?op1->exponent:(int)e->SF1)-(int)e->SF3);
13502 
13503 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",
13504            e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF3,NQ);
13505     }
13506     if (NQ > 63)
13507         doFault(FAULT_DIV, fst_zero, "dv3d NQ>63");
13508     // Note: NQ is currently unused apart from this FAULT_DIV check.
13509     //   decNumber produces more digits than required, but they are then rounded/truncated
13510 
13511     // Yes, they're switched. op1=divisor
13512     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13513     // Note DPS88 and DPS9000 are different when NQ <= 0
13514     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13515     // ISOLTS-817 05b
13516 
13517     PRINTDEC("op2", op2);
13518     PRINTDEC("op1", op1);
13519     PRINTDEC("op3", op3);
13520 
13521     // let's check division results to see for anomalous conditions
13522     if (
13523         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13524         (set.status & DEC_Invalid_operation) ||
13525         (set.status & DEC_Division_by_zero)
13526         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv3d anomalous results"); } // divide by zero has already been checked before
13527 
13528     if (e->S3 == CSFL)
13529     {
13530         // justify CSFL left
13531         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13532         // Note DPS88 and DPS9000 are different
13533         // ISOLTS-817 06c,06e
13534 
13535         decNumber _sf;
13536 
13537         if (n3 - op3->digits > 0)
13538         {
13539             decNumberFromInt32(&_sf, op3->exponent - (n3 - op3->digits));
13540             PRINTDEC("Value 1", op3)
13541             PRINTDEC("Value sf", &_sf)
13542             op3 = decNumberRescale(op3, op3, &_sf, &set);
13543             PRINTDEC("Value 2", op3)
13544         }
13545     }
13546 
13547     bool Ovr = false, EOvr = false, Trunc = false;
13548     uint8_t out[256];
13549 
13550     // CSFL: If the divisor is greater than the dividend after operand
13551     // alignment, the leading zero digit produced is counted and the effective
13552     // precision of the result is reduced by one.
13553     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13554     // Note DPS88 and DPS9000 are different
13555     //
13556     // "greater after operand alignment" means scale until most-significant digits
13557     //   are nonzero, then compare magnitudes ignoring exponents
13558     // This passes ISOLTS-817 06e, ET 458,461,483,486
13559     char *res;
13560     if (e->S3 == CSFL) {
13561         decNumber _1a;
13562         decNumber _2a;
13563         decNumber _sf;
13564         if (op1->digits >= op2->digits) {
13565             // scale op2
13566             decNumberCopy(&_1a, op1);
13567             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13568             decNumberShift(&_2a, op2, &_sf, &set);
13569         } else if (op1->digits < op2->digits) {
13570             // scale op1
13571             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13572             decNumberShift(&_1a, op1, &_sf, &set);
13573             decNumberCopy(&_2a, op2);
13574         }
13575         _1a.exponent = 0;
13576         _2a.exponent = 0;
13577 
13578         PRINTDEC("dv3d: op1a", &_1a);
13579         PRINTDEC("dv3d: op2a", &_2a);
13580         sim_debug (DBG_TRACEEXT, & cpu_dev,
13581                    "dv3d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\n",
13582                    op1->exponent ,op2->exponent, op1->digits,
13583                    op2->digits, _1a.digits, _2a.digits);
13584 
13585         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13586             // shorten the result field to get proper rounding
13587             res = formatDecimal(out, &set, op3, n3 -1, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13588 
13589             // prepend zero digit
13590             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13591             for (int i = n3; i > 0; i--) // incl.zero terminator
13592                  res[i] = res[i-1];
13593             res[0] = '0';
13594             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: addzero n3 %d %s exp %d\n",n3,res,op3->exponent);
13595         } else {
13596             // full n3 digits are returned
13597             res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13598         }
13599     } else {
13600         // same as all other decimal instructions
13601         res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13602     }
13603 
13604     if (decNumberIsZero(op3))
13605         op3->exponent = 127;
13606 
13607     //(void)printf("%s\r\n", res);
13608 
13609     // now write to memory in proper format.....
13610 
13611     int pos = (int) dstCN;
13612 
13613     // 1st, take care of any leading sign .......
13614     switch(e->S3)
13615     {
13616         case CSFL:  // floating-point, leading sign.
13617         case CSLS:  // fixed-point, leading sign
13618             switch(dstTN)
13619             {
13620                 case CTN4:
13621                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13622                               //   then the 13(8) plus sign character is placed appropriately
13623                               //   if the result of the operation is positive.
13624                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13625                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13626                     else
13627                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13628                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13629                     break;
13630                 case CTN9:
13631                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13632                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13633                     break;
13634             }
13635             break;
13636 
13637         case CSTS:  // nuttin' to do here .....
13638         case CSNS:
13639             break;  // no sign wysiwyg
13640     }
13641 
13642     // 2nd, write the digits .....
13643     for(int i = 0 ; i < n3 ; i++)
13644         switch(dstTN)
13645         {
13646             case CTN4:
13647                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13648                 break;
13649             case CTN9:
13650                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13651                 break;
13652             }
13653 
13654     // 3rd, take care of any trailing sign or exponent ...
13655     switch(e->S3)
13656     {
13657         case CSTS:  // write trailing sign ....
13658             switch(dstTN)
13659             {
13660                 case CTN4:
13661                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13662                               //   then the 13(8) plus sign character is placed appropriately if
13663                               //   the result of the operation is positive.
13664                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13665                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13666                     else
13667                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13668                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13669                     break;
13670                 case CTN9:
13671                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13672                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13673                 break;
13674             }
13675             break;
13676 
13677         case CSFL:  // floating-point, leading sign.
13678             // write the exponent
13679             switch(dstTN)
13680             {
13681                 case CTN4:
13682                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13683                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13684                     break;
13685                 case CTN9:
13686                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13687                     break;
13688             }
13689             break;
13690 
13691         case CSLS:  // fixed point, leading sign - already done
13692         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13693             break;
13694     }
13695 
13696     // set flags, etc ...
13697     if (e->S3 == CSFL)
13698     {
13699         if (op3->exponent > 127)
13700         {
13701             SET_I_EOFL;
13702             EOvr = true;
13703         }
13704         if (op3->exponent < -128)
13705         {
13706             SET_I_EUFL;
13707             EOvr = true;
13708         }
13709     }
13710 
13711     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13712     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13713 
13714     // SC_I_TRUNC(!R && Trunc); // no truncation flag for divide
13715 
13716     cleanupOperandDescriptor (cpup, 1);
13717     cleanupOperandDescriptor (cpup, 2);
13718     cleanupOperandDescriptor (cpup, 3);
13719 
13720     //if (TST_I_TRUNC && T && tstOVFfault (cpup))
13721     //  doFault(FAULT_OFL, fst_zero, "dv3d truncation(overflow) fault");
13722     if (EOvr && tstOVFfault (cpup))
13723         doFault(FAULT_OFL, fst_zero, "dv3d over/underflow fault");
13724     if (Ovr)
13725     {
13726         SET_I_OFLOW;
13727         if (tstOVFfault (cpup))
13728           doFault(FAULT_OFL, fst_zero, "dv3d overflow fault");
13729     }
13730 }

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