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. tandd_eis_interruptible
  30. tandd_eis_sample
  31. a4bd
  32. s4bd
  33. axbd
  34. abd
  35. awd
  36. sbd
  37. swd
  38. s9bd
  39. asxbd
  40. cmpc
  41. scd
  42. scdr
  43. scm
  44. scmr
  45. xlate
  46. tct
  47. tctr
  48. isGBCDOvp
  49. mlr
  50. mrl
  51. EISloadInputBufferNumeric
  52. EISloadInputBufferAlphnumeric
  53. EISwriteOutputBufferToMemory
  54. writeToOutputBuffer
  55. mopCHT
  56. mopENF
  57. mopIGN
  58. mopINSA
  59. mopINSB
  60. mopINSM
  61. mopINSN
  62. mopINSP
  63. mopLTE
  64. mopMFLC
  65. mopMFLS
  66. mopMORS
  67. mopMVC
  68. mopMSES
  69. mopMVZA
  70. mopMVZB
  71. mopSES
  72. EISgetMop
  73. mopExecutor
  74. mve
  75. mvne
  76. mvt
  77. cmpn
  78. EISwrite4
  79. EISwrite9
  80. EISwrite49
  81. mvn
  82. csl
  83. getBitOffsets
  84. EISgetBitRWNR
  85. csr
  86. sztl
  87. sztr
  88. EISgetBit
  89. cmpb
  90. sign9n
  91. signExt9
  92. load9x
  93. btd
  94. dtb
  95. ad2d
  96. ad3d
  97. sb2d
  98. sb3d
  99. mp2d
  100. mp3d
  101. dv2d
  102. 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-2026 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?\r\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?\r\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?\r\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?\r\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?\r\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?\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\n", cpu.du.Dk_PTR_W[eisaddr_idx]);
 758 #else
 759     sim_debug (DBG_TRACEEXT, & cpu_dev, "EISRead addr %06o\r\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\r\n", __func__, addressN);
 793     if ((addressN & PGMK) != 0)
 794       {
 795         sim_warn ("EISReadPage not aligned %06o\r\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\r\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\r\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\r\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\r\n", __func__, addressN);
 855     if ((addressN & PGMK) != 0)
 856       {
 857         sim_warn ("EISWritePage not aligned %06o\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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             // Two 4-bit chars per 9-bit char; BITNO 5-15 is the second
1492             // (for BITNO 0-8 this is (9 * CHAR + BITNO) * 2 / 9; BITNO 9
1493             // from LAREG: PS905 01A)
1494             uint arn_char4 = ARn_CHAR * 2u + (ARn_BITNO >= 5u ? 1u : 0u);
1495             // 8 chars per word plus the number of chars in r, plus the
1496             // number of chars in ARn CHAR/BITNO plus the CN from the operand
1497 // XXX Handle 'r' too big intelligently...
1498             uint nchars = address * 8 + (uint) r + arn_char4 + CN;
1499 
1500             effWORDNO = nchars / 8; // 8 chars/word
1501             effCHAR = nchars % 8; // effCHAR is the 4 bit char number, not
1502                                   // the 9-bit char no
1503             effBITNO = (nchars & 1) ? 5 : 0;
1504 
1505             effWORDNO &= AMASK;
1506 
1507             e -> CN [k - 1] = effCHAR;
1508             e -> WN [k - 1] = effWORDNO;
1509 
1510             sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA4\r\n",
1511                        k, e -> CN [k - 1]);
1512           }
1513           break;
1514 
1515         case CTA6:
1516           if (CN >= 6) {
1517             L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TAn CTA6 CN >= 6");)
1518             // DPS8M
1519             *mod_fault |= FR_ILL_PROC;
1520           }
1521           {
1522           // MVNE's receiving string (operand 3): a 6-bit string's register
1523           // (REG) count is taken in 9-bit characters, not 6-bit ones.
1524           // With 6-bit units, a PS955 random case (MVNE, op3 6-bit with RL
1525           // and an X7 offset of 300465) wrapped to PS955's own code and
1526           // overwrote it; with 9-bit units the output lands in PS955's
1527           // operand buffer, as its other operands do, and PS955 runs
1528           // cleanly.
1529           uint rbits = (k == 3 &&
1530                         cpu.currentInstruction.opcode == 024 &&
1531                         cpu.currentInstruction.opcodeX == 1) ? 9u : 6u;
1532           effBITNO = (9u * ARn_CHAR + rbits * r + ARn_BITNO) % 9u;
1533           effCHAR = ((6u * CN +
1534                       9u * ARn_CHAR +
1535                       rbits * r + ARn_BITNO) % 36u) / 6u;//9;
1536           effWORDNO = (uint) (address +
1537                            (6u * CN +
1538                             9u * ARn_CHAR +
1539                             rbits * r +
1540                             ARn_BITNO) / 36u);
1541           }
1542           effWORDNO &= AMASK;
1543 
1544           e -> CN [k - 1] = effCHAR;   // ??????
1545           e -> WN [k - 1] = effWORDNO;
1546           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA6\r\n",
1547                      k, e -> CN [k - 1]);
1548           break;
1549 
1550         case CTA9:
1551           if (CN & 01) {
1552             L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor CTA9 & CN odd");)
1553             // DPS8M
1554             *mod_fault |= FR_ILL_PROC;
1555           }
1556           CN = (CN >> 1);
1557 
1558           effBITNO = 0;
1559           effCHAR = (CN + ARn_CHAR + r) % 4;
1560           sim_debug (DBG_TRACEEXT, & cpu_dev,
1561                      "effCHAR %d = (CN %d + ARn_CHAR %d + r %"PRId64") %% 4)\r\n",
1562                      effCHAR, CN, ARn_CHAR, r);
1563           // 9-bit data starts at a character: ARn.BITNO is not used (it
1564           // only mattered past 8; BITNO 9 from LAREG: PS905 01A)
1565           effWORDNO = (uint) (address +
1566                            ((9u * CN +
1567                              9u * ARn_CHAR +
1568                              9u * r) / 36u));
1569           effWORDNO &= AMASK;
1570 
1571           e -> CN [k - 1] = effCHAR;   // ??????
1572           e -> WN [k - 1] = effWORDNO;
1573           sim_debug (DBG_TRACEEXT, & cpu_dev, "CN%d set to %d by CTA9\r\n",
1574                      k, e -> CN [k - 1]);
1575           break;
1576 
1577         default:
1578           L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseAlphanumericOperandDescriptor TA1 3");)
1579           // DPS8M
1580           *mod_fault |= FR_ILL_PROC;
1581           break;
1582     }
1583 
1584     EISaddr * a = & e -> addr [k - 1];
1585     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1586 #if defined(EIS_PTR)
1587     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1588 #else
1589     a -> address = effWORDNO;
1590 #endif
1591     a -> cPos= (int) effCHAR;
1592     a -> bPos = (int) effBITNO;
1593 
1594 #if !defined(EIS_PTR3)
1595     // a->_type = eisTA;
1596     a -> TA = (int) e -> TA [k - 1];
1597 #endif
1598   }
1599 
1600 static void parseArgOperandDescriptor (cpu_state_t * cpup, uint k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1601   {
1602     PNL (L68_ (if (k == 1)
1603       DU_CYCLE_NLD1;
1604     else if (k == 2)
1605       DU_CYCLE_NLD2;
1606     else if (k == 3)
1607       DU_CYCLE_GSTR;))
1608 
1609     EISstruct * e = & cpu.currentEISinstruction;
1610     word36 opDesc = e -> op [k - 1];
1611     word18 y = GETHI (opDesc);
1612     word1 yA = GET_A (opDesc);
1613 
1614     uint yREG = opDesc & 0xf;
1615 
1616     word36 r = getMFReg36 (cpup, yREG, false, true, mod_fault); // disallow du, allow n,ic
1617 
1618     word8 ARn_CHAR = 0;
1619     word6 ARn_BITNO = 0;
1620 
1621     PNL (cpu.du.POP = 1);
1622 
1623     if (yA)
1624       {
1625         // if operand contains A (bit-29 set) then it Means Y-char9n is not
1626         // the memory address of the data but is a reference to a pointer
1627         // register pointing to the data.
1628         word3 n = GET_ARN (opDesc);
1629         CPTUR (cptUsePRn + n);
1630         word15 offset = y & MASK15;  // 15-bit signed number
1631         y = (cpu.AR [n].WORDNO + SIGNEXT15_18 (offset)) & AMASK;
1632 
1633         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1634         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1635 
1636         cpu.cu.TSN_PRNO[k-1] = n;
1637         cpu.cu.TSN_VALID[k-1] = 1;
1638         e -> addr [k - 1].SNR = cpu.PR[n].SNR;
1639         e -> addr [k - 1].RNR = max3 (cpu.PR [n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1640         e -> addr [k - 1].mat = viaPR;
1641       }
1642 
1643     y += ((9u * ARn_CHAR + 36u * r + ARn_BITNO) / 36u);
1644     y &= AMASK;
1645 
1646     PNL (cpu.du.Dk_PTR_W[k-1] = y);
1647 
1648 #if defined(EIS_PTR)
1649     cpu.du.Dk_PTR_W[k-1] = y;
1650 #else
1651     e -> addr [k - 1].address = y;
1652 #endif
1653   }
1654 
1655 static void parseNumericOperandDescriptor (cpu_state_t * cpup, int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1656 {
1657     PNL (L68_ (if (k == 1)
1658       DU_CYCLE_NLD1;
1659     else if (k == 2)
1660       DU_CYCLE_NLD2;
1661     else if (k == 3)
1662       DU_CYCLE_GSTR;))
1663 
1664     EISstruct * e = & cpu.currentEISinstruction;
1665     word18 MFk = e->MF[k-1];
1666 
1667     PNL (cpu.du.POP = 1);
1668 
1669     word36 opDesc = e->op[k-1];
1670 
1671     word8 ARn_CHAR = 0;
1672     word6 ARn_BITNO = 0;
1673 
1674     word18 address = GETHI(opDesc);
1675     if (MFk & MFkAR)
1676     {
1677         // if MKf contains ar then it Means Y-charn is not the memory address
1678         // of the data but is a reference to a pointer register pointing to the
1679         // data.
1680         word3 n = (word3) getbits18 (address, 0, 3);
1681         CPTUR (cptUsePRn + n);
1682         word15 offset = address & MASK15;  // 15-bit signed number
1683         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1684 
1685         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1686         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1687 
1688         cpu.cu.TSN_PRNO[k-1] = n;
1689         cpu.cu.TSN_VALID[k-1] = 1;
1690         e->addr[k-1].SNR = cpu.PR[n].SNR;
1691         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1692 
1693         e->addr[k-1].mat = viaPR;   // ARs involved
1694     }
1695 
1696     PNL (cpu.du.POL = 1);
1697 
1698     word3 CN = getbits36_3 (opDesc, 18);    // character number
1699     e->TN[k-1] = getbits36_1 (opDesc, 21); // type numeric
1700 
1701 #if defined(PANEL68)
1702     if (k == 1)
1703       {
1704         if (e->TN[0])
1705           cpu.dataMode = 0021; // 4 bit numeric
1706         else
1707           cpu.dataMode = 0101; // 9 bit numeric
1708       }
1709 #endif
1710 
1711     e->S[k-1]  = getbits36_2 (opDesc, 22);    // Sign and decimal type of data
1712     e->SF[k-1] = SIGNEXT6_int (getbits36_6 (opDesc, 24));    // Scaling factor.
1713 
1714     // Operand length. If MFk.RL = 0, this field contains the operand length in
1715     // digits. If MFk.RL = 1, it contains the REG code for the register holding
1716     // the operand length and C(REG) is treated as a 0 modulo 64 number. See
1717     // Table 4-1 and EIS modification fields (MF) above for a discussion of
1718     // register codes.
1719 
1720     if (MFk & MFkRL)
1721     {
1722         uint reg = opDesc & 017;
1723         e->N[k-1] = getMFReg18 (cpup,reg, false, false, mod_fault) & 077; // RL=1: disallow du,n,ic
1724     }
1725     else
1726         e->N[k-1] = opDesc & 077;
1727 
1728     sim_debug (DBG_TRACEEXT, & cpu_dev, "parseNumericOperandDescriptor(cpup, ): N%u %0o\r\n", k, e->N[k-1]);
1729 
1730     word36 r = getMFReg36(cpup, MFk & 017, false, true, mod_fault); // disallow du, allow n, ic
1731     if ((MFk & 017) == 4)   // reg == IC ?
1732     {
1733         address += r;
1734         address &= AMASK;
1735         r = 0;
1736     }
1737 
1738 // handled in numeric instructions
1739 
1740 
1741 
1742 
1743 
1744 
1745 
1746 
1747 
1748 
1749 // Causes:
1750 //DBG(662088814)> CPU0 FAULT: Fault 10(012), sub 4294967296(040000000000), dfc N, 'parseNumericOperandDescriptor N=1 S=0|1|2'
1751 //DBG(662088814)> CPU0 FAULT: 00257:004574 bound_process_env_:command_query_+04574
1752 //DBG(662088814)> CPU0 FAULT:       664 end print_question;
1753 //DBG(662088814)> CPU0 FAULT: 00257:004574 4 000100301500 (BTD PR0|100) 000100 301(1) 0 0 0 00
1754 
1755     uint effBITNO = 0;
1756     uint effCHAR = 0;
1757     uint effWORDNO = 0;
1758 
1759     // If seems that the effect address calcs given in AL39 p.6-27 are not
1760     // quite right.
1761     // E.g. For CTA4/CTN4 because of the 4 "slop" bits you need to do 32-bit
1762     // calcs not 36-bit!
1763 
1764     switch (e->TN[k-1])
1765     {
1766         case CTN4:
1767           {
1768             // Calculate character number of ARn CHAR and BITNO
1769             // Two 4-bit chars per 9-bit char; BITNO 5-15 is the second
1770             // (for BITNO 0-8 this is (9 * CHAR + BITNO) * 2 / 9; BITNO 9
1771             // from LAREG: PS905 01A)
1772             uint arn_char4 = ARn_CHAR * 2u + (ARn_BITNO >= 5u ? 1u : 0u);
1773             //// The odd chars start at the 6th bit, not the 5th
1774             //if (bitoffset & 1) // if odd
1775             //  arn_char4 ++;
1776             // 8 chars per word plus the number of chars in r, plus the number of chars in ARn CHAR/BITNO
1777 // XXX Handle 'r' too big intelligently...
1778             uint nchars = (uint) (address * 8u + r + arn_char4 + CN);
1779 
1780             effWORDNO = nchars / 8u; // 8 chars/word
1781             effCHAR = nchars % 8u; // effCHAR is the 4 bit char number, not the 9-bit char no
1782             effBITNO = (nchars & 1u) ? 5u : 0u;
1783             effWORDNO &= AMASK;
1784 
1785             e->CN[k-1] = effCHAR;        // ?????
1786           }
1787           break;
1788 
1789         case CTN9:
1790             if (CN & 1u) {
1791               L68_ (doFault(FAULT_IPR, fst_ill_proc, "parseNumericOperandDescriptor CTA9 & CN odd");)
1792               // DPS8M
1793               *mod_fault |= FR_ILL_PROC;
1794             }
1795             CN = (CN >> 1u) & 03u;
1796 
1797             effBITNO = 0;
1798             effCHAR = ((word36) CN + (word36) ARn_CHAR + r) % 4u;
1799             // ARn.BITNO is not used for 9-bit data (as for CTA9)
1800             effWORDNO = (uint) (address + (9u*CN + 9u*ARn_CHAR + 9u*r) / 36);
1801             effWORDNO &= AMASK;
1802 
1803             e->CN[k-1] = effCHAR;        // ?????
1804 
1805             break;
1806         default:
1807 #if defined(EIS_PTR3)
1808             sim_printf ("parseNumericOperandDescriptor(cpup, ta=%d) How'd we get here 2?\r\n",
1809                         cpu.du.TAk[k-1]);
1810 #else
1811             sim_printf ("parseNumericOperandDescriptor(cpup, ta=%d) How'd we get here 2?\r\n",
1812                         e->TA[k-1]);
1813 #endif
1814             break;
1815     }
1816 
1817     EISaddr *a = &e->addr[k-1];
1818     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1819 #if defined(EIS_PTR)
1820     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1821 #else
1822     a->address = effWORDNO;
1823 #endif
1824     a->cPos = (int) effCHAR;
1825     a->bPos = (int) effBITNO;
1826 
1827     // a->_type = eisTN;
1828     a->TN = (int) e->TN[k-1];
1829 
1830 #if defined(EIS_PTR)
1831     sim_debug (DBG_TRACEEXT, & cpu_dev,
1832                "parseNumericOperandDescriptor(cpup, ): address:%06o cPos:%d bPos:%d N%u %u\r\n",
1833                cpu.du.Dk_PTR_W[k-1], a->cPos, a->bPos, k, e->N[k-1]);
1834 #else
1835     sim_debug (DBG_TRACEEXT, & cpu_dev,
1836                "parseNumericOperandDescriptor(cpup, ): address:%06o cPos:%d bPos:%d N%u %u\r\n",
1837                a->address, a->cPos, a->bPos, k, e->N[k-1]);
1838 #endif
1839 }
1840 
1841 static void parseBitstringOperandDescriptor (cpu_state_t * cpup, int k, fault_ipr_subtype_ *mod_fault)
     /* [previous][next][first][last][top][bottom][index][help] */
1842 {
1843     PNL (L68_ (if (k == 1)
1844       DU_CYCLE_ANLD1;
1845     else if (k == 2)
1846       DU_CYCLE_ANLD2;
1847     else if (k == 3)
1848       DU_CYCLE_ANSTR;))
1849 
1850     EISstruct * e = & cpu.currentEISinstruction;
1851     word18 MFk = e->MF[k-1];
1852     word36 opDesc = e->op[k-1];
1853 
1854 #if defined(PANEL68)
1855     if (k == 1)
1856       cpu.dataMode = 0010; // 1 bit not alpha, not alpha numeric
1857 #endif
1858     word8 ARn_CHAR = 0;
1859     word6 ARn_BITNO = 0;
1860 
1861     PNL (cpu.du.POP = 1);
1862 
1863     word18 address = GETHI(opDesc);
1864     if (MFk & MFkAR)
1865     {
1866         // if MKf contains ar then it Means Y-charn is not the memory address
1867         // of the data but is a reference to a pointer register pointing to the
1868         // data.
1869         word3 n = (word3) getbits18 (address, 0, 3);
1870         CPTUR (cptUsePRn + n);
1871         word15 offset = address & MASK15;  // 15-bit signed number
1872         address = (cpu.AR[n].WORDNO + SIGNEXT15_18(offset)) & AMASK;
1873 
1874         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d AR%d\r\n", k, n);
1875 
1876         ARn_CHAR = GET_AR_CHAR (n); // AR[n].CHAR;
1877         ARn_BITNO = GET_AR_BITNO (n); // AR[n].BITNO;
1878         cpu.cu.TSN_PRNO[k-1] = n;
1879         cpu.cu.TSN_VALID[k-1] = 1;
1880         e->addr[k-1].SNR = cpu.PR[n].SNR;
1881         e->addr[k-1].RNR = max3(cpu.PR[n].RNR, cpu.TPR.TRR, cpu.PPR.PRR);
1882         e->addr[k-1].mat = viaPR;   // ARs involved
1883     }
1884     PNL (cpu.du.POL = 1);
1885 
1886     //Operand length. If MFk.RL = 0, this field contains the string length of
1887     //the operand. If MFk.RL = 1, this field contains the code for a register
1888     //holding the operand string length. See Table 4-1 and EIS modification
1889     //fields (MF) above for a discussion of register codes.
1890     if (MFk & MFkRL)
1891     {
1892         uint reg = opDesc & 017;
1893         e->N[k-1] = getMFReg36(cpup, reg, false, false, mod_fault) & 077777777;  // RL=1: disallow du,n,ic
1894         sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d RL reg %u val %"PRIo64"\r\n", k, reg, (word36)e->N[k-1]);
1895     }
1896     else
1897     {
1898         e ->N[k-1] = opDesc & 07777;
1899     }
1900 
1901     sim_debug (DBG_TRACEEXT, & cpu_dev, "bitstring k %d opdesc %012"PRIo64"\r\n", k, opDesc);
1902     sim_debug (DBG_TRACEEXT, & cpu_dev, "N%u %u\r\n", k, e->N[k-1]);
1903 
1904     word4 B = getbits36_4(opDesc, 20);    // bit# from descriptor
1905     word2 C = getbits36_2 (opDesc, 18);     // char# from descriptor
1906 
1907     if (B >= 9) {
1908       L68_ (doFault (FAULT_IPR, fst_ill_proc, "parseBitstringOperandDescriptor B >= 9");)
1909       // DPS8M
1910       *mod_fault |= FR_ILL_PROC;
1911     }
1912 
1913     word36 r = getMFReg36(cpup, MFk & 017, false, true, mod_fault);  // disallow du, allow n,ic
1914     if ((MFk & 017) == 4)   // reg == IC ?
1915     {
1916         // If reg == IC, then R is in words, not bits.
1917         //r *= 36;
1918         address += r;
1919         address &= AMASK;
1920         r = 0;
1921     }
1922 
1923     uint effBITNO = (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 9u;
1924     uint effCHAR = ((9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) % 36u) / 9u;
1925     uint effWORDNO = (uint) (address + (9u*ARn_CHAR + r + ARn_BITNO + B + 9u*C) / 36u);
1926     effWORDNO &= AMASK;
1927 
1928     e->B[k-1] = effBITNO;
1929     e->C[k-1] = effCHAR;
1930 
1931     EISaddr *a = &e->addr[k-1];
1932     PNL (cpu.du.Dk_PTR_W[k-1] = effWORDNO);
1933 #if defined(EIS_PTR)
1934     cpu.du.Dk_PTR_W[k-1] = effWORDNO;
1935 #else
1936     a->address = effWORDNO;
1937 #endif
1938     a->cPos = (int) effCHAR;
1939     a->bPos = (int) effBITNO;
1940 }
1941 
1942 static void cleanupOperandDescriptor (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
1943   {
1944     EISstruct * e = & cpu.currentEISinstruction;
1945     if (e -> addr [k - 1].cacheValid && e -> addr [k - 1].cacheDirty)
1946       {
1947         EISWriteCache(cpup, & e -> addr [k - 1]);
1948       }
1949     e -> addr [k - 1].cacheDirty = false;
1950   }
1951 
1952 // T&D: the EIS instructions that can be interrupted part way (PM842
1953 // tests each with an interrupt and with timer runouts).
1954 bool tandd_eis_interruptible (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1955   {
1956     DCDstruct * i = & cpu.currentInstruction;
1957     if (! i -> opcodeX)
1958       return false;
1959     switch (i -> opcode)
1960       {
1961         case 0100: // mlr
1962         case 0101: // mrl
1963         case 0160: // mvt
1964         case 0106: // cmpc
1965         case 0120: // scd
1966         case 0121: // scdr
1967         case 0124: // scm
1968         case 0125: // scmr
1969         case 0164: // tct
1970         case 0165: // tctr
1971         case 0060: // csl
1972         case 0061: // csr
1973         case 0064: // sztl
1974         case 0065: // sztr
1975         case 0066: // cmpb
1976           return true;
1977       }
1978     return false;
1979   }
1980 
1981 // characters per word for operand type ta
1982 #define TDPER(ta) ((ta) == CTA6 ? 6u : (ta) == CTA4 ? 8u : 4u)
1983 
1984 // T&D: called before an interruptible EIS instruction processes unit
1985 // (character or bit) 'unit'. Every two words' worth of units (perWord
1986 // units per word) costs one cycle of TR time (PM842 allows 1 to 9 timer
1987 // runouts in a 96 character mrl with TR = 1); at those points, after
1988 // the first unit of this execution, the instruction samples group 7
1989 // faults and interrupts unless it has the inhibit bit. One that is present stops it with MIF
1990 // on, the IC at the instruction and CHTALLY at 'unit'; executed again
1991 // with MIF on it carries on from there (PM842).
1992 void tandd_eis_sample (cpu_state_t * cpup, uint unit, uint perWord)
     /* [previous][next][first][last][top][bottom][index][help] */
1993   {
1994     if (! cpu.tweaks.tandd_mode || cpu.currentInstruction.i ||
1995         unit <= cpu.tanddEISstart || unit % (2 * perWord))
1996       return;
1997     if (++ cpu.rTRlsb >= 4)
1998       {
1999         cpu.rTRlsb = 0;
2000         cpu.rTR --;
2001         cpu.lufTicks ++;
2002         cpu.tanddTRTicks ++;
2003       }
2004     if (cpu.rTR & ~MASK27)
2005       {
2006         cpu.rTR &= MASK27;
2007         if (cpu.tweaks.tro_enable)
2008           setG7fault (current_running_cpu_idx, FAULT_TRO);
2009       }
2010     advanceG7Faults (cpup);
2011     bool noCheckTR = is_priv_mode (cpup);
2012     // Not the L68 floating faults (OC, CU-HR overflow, address traps):
2013     // they occur only between instructions, "after completion of the next
2014     // odd instruction" (PM842 01C: a CU-HR trap pair inside an MLR)
2015     bool g7 = noCheckTR ? (cpu.g7Faults & ~(1u << FAULT_TRO)) != 0
2016                         : cpu.g7Faults != 0;
2017     if (! g7 && ! sample_interrupts (cpup))
2018       return;
2019     for (int k = 1; k <= 3; k ++)
2020       cleanupOperandDescriptor (cpup, k);
2021     cpu.du.CHTALLY = unit;
2022     SC_I_MIF (1);
2023     if (g7)
2024       doG7Fault (cpup, ! noCheckTR);
2025     cpu.interrupt_flag = true;
2026     cpu.cycle = INTERRUPT_cycle;
2027     longjmp (cpu.jmpMain, JMP_REENTRY);
2028   }
2029 
2030 // For a4bd/s4bd, the world is made of 32 bit words, so the address space
2031 // is 2^18 * 32 bits
2032 #define n4bits (1 << 23)
2033 // For a4bd/s4bd, the world is made of 8 4-bitcharacter words, so the address space
2034 // is 2^18 * 8 characters
2035 #define n4chars (1 << 21)
2036 // For axbd/sxbd, the world is made of 36 bits words, so the address space
2037 // is 2^18 * 36 bits
2038 #define nxbits ((1 << 18) * 36)
2039 
2040 // 2 * (s->BITNO / 9) + (s->BITNO % 9) / 4;
2041 static unsigned int cntFromBit[36] = {
2042     0, 0, 0, 0, 0, 1, 1, 1, 1,
2043     2, 2, 2, 2, 2, 3, 3, 3, 3,
2044     4, 4, 4, 4, 4, 5, 5, 5, 5,
2045     6, 6, 6, 6, 6, 7, 7, 7, 7
2046 };
2047 
2048 static word6 bitFromCnt[8] = {1, 5, 10, 14, 19, 23, 28, 32};
2049 
2050 void a4bd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2051   {
2052     // 8 4-bit characters/word
2053 
2054     uint ARn = GET_ARN (cpu.cu.IWB);
2055     CPTUR (cptUsePRn + ARn);
2056     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2057 //if (current_running_cpu_idx)
2058 //sim_printf ("a4bd address %o %d.\r\n", address, address);
2059 
2060     word4 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2061                                      // au, qu, al, ql, xn)
2062     // r is the count of 4bit characters
2063     word36 ur = getCrAR (cpup, reg);
2064     int32 r = SIGNEXT22_32 ((word22) ur);
2065 //if (current_running_cpu_idx)
2066 //sim_printf ("a4bd r %o %d.\r\n", r, r);
2067 
2068     uint augend = 0; // in 4bit characters
2069     if (GET_A (cpu.cu.IWB))
2070        {
2071 //if (current_running_cpu_idx)
2072 //sim_printf ("a4bd AR%d WORDNO %o %d. CHAR %o BITNO %o\r\n",
2073 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO,
2074 //            cpu.AR[ARn].CHAR, cpu.AR[ARn].BITNO);
2075 
2076          //augend = cpu.AR[ARn].WORDNO * 32u + cntFromBit [GET_AR_BITNO (ARn)];
2077          // force to 4 bit character boundary
2078          //augend = augend & ~3;
2079          //augend = cpu.AR[ARn].WORDNO * 8 + cpu.AR[ARn].CHAR * 2;
2080          augend = cpu.AR[ARn].WORDNO * 8u + GET_AR_CHAR (ARn) * 2u;
2081 
2082          //if (cpu.AR[ARn].BITNO >= 5)
2083          if (GET_AR_BITNO (ARn) >= 5u)
2084            augend ++;
2085        }
2086 
2087 //if (current_running_cpu_idx)
2088 //sim_printf ("a4bd augend %o %d.\r\n", augend, augend);
2089 
2090     int32_t addend = address * 8 + r;  // in characters
2091 
2092 //if (current_running_cpu_idx)
2093 //sim_printf ("a4bd addend %o %d.\r\n", addend, addend);
2094 
2095     int32_t sum = (int32_t) augend + addend;
2096 //if (current_running_cpu_idx)
2097 //sim_printf ("a4bd sum %o %d.\r\n", sum, sum);
2098 
2099     // Handle over/under flow
2100     while (sum < 0)
2101       sum += n4chars;
2102     sum = sum % n4chars;
2103 //if (current_running_cpu_idx)
2104 //sim_printf ("a4bd sum %o %d.\r\n", sum, sum);
2105 
2106     cpu.AR[ARn].WORDNO = (word18) (sum / 8) & AMASK;
2107 //if (current_running_cpu_idx)
2108 //sim_printf ("a4bd WORDNO %o %d.\r\n", cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO);
2109 
2110 //    // 0aaaabbbb0ccccdddd0eeeeffff0gggghhhh
2111 //    //             111111 11112222 22222233
2112 //    //  01234567 89012345 67890123 45678901   // 4 bit notation offset
2113 //    static int tab [32] = { 1,  2,  3,  4,  5,  6,  7,  8,
2114 //                           10, 11, 12, 13, 14, 15, 16, 17,
2115 //                           19, 20, 21, 22, 23, 24, 25, 26,
2116 //                           28, 29, 30, 31, 32, 33, 34, 35};
2117 //
2118     //uint bitno = sum % 32;
2119 //    AR [ARn].BITNO = tab [bitno];
2120     //cpu.AR [ARn].BITNO = bitFromCnt[bitno % 8];
2121     //SET_PR_BITNO (ARn, bitFromCnt[bitno % 8]);
2122     uint char4no = (uint) (sum % 8);
2123 //if (current_running_cpu_idx)
2124 //sim_printf ("a4bd char4no %d.\r\n", char4no);
2125 
2126     SET_AR_CHAR_BITNO (ARn, (word2) (char4no / 2), (char4no % 2) ? 5 : 0);
2127 #if defined(TESTING)
2128     HDBGRegARW (ARn, "a4bd");
2129 #endif
2130 //if (current_running_cpu_idx)
2131 //sim_printf ("a4bd CHAR %o %d.\r\n", cpu.AR[ARn].CHAR, cpu.AR[ARn].CHAR);
2132 //if (current_running_cpu_idx)
2133 //sim_printf ("a4bd BITNO %o %d.\r\n", cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2134   }
2135 
2136 void s4bd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2137   {
2138     uint ARn = GET_ARN (cpu.cu.IWB);
2139     CPTUR (cptUsePRn + ARn);
2140     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2141     word4 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2142                                   // au, qu, al, ql, xn)
2143     // r is the count of characters
2144     word36 ur = getCrAR (cpup, reg);
2145     int32 r = SIGNEXT22_32 ((word22) ur);
2146 
2147     uint minuend = 0;
2148     if (GET_A (cpu.cu.IWB))
2149        {
2150          //minuend = cpu.AR [ARn].WORDNO * 32 + cntFromBit [GET_PR_BITNO (ARn)];
2151          minuend = cpu.AR [ARn].WORDNO * 32 + cntFromBit [GET_AR_CHAR (ARn) * 9 + GET_AR_BITNO (ARn)];
2152          // force to 4 bit character boundary
2153          minuend = minuend & (unsigned int) ~3;
2154        }
2155     int32_t subtractend = address * 32 + r * 4;
2156     int32_t difference = (int32_t) minuend - subtractend;
2157 
2158     // Handle over/under flow
2159     while (difference < 0)
2160       difference += n4bits;
2161     difference = difference % n4bits;
2162 
2163     cpu.AR [ARn].WORDNO = (word18) (difference / 32) & AMASK;
2164 
2165 //    // 0aaaabbbb0ccccdddd0eeeeffff0gggghhhh
2166 //    //             111111 11112222 22222233
2167 //    //  01234567 89012345 67890123 45678901   // 4 bit notation offset
2168 //    static int tab [32] = { 1,  2,  3,  4,  5,  6,  7,  8,
2169 //                       10, 11, 12, 13, 14, 15, 16, 17,
2170 //                       19, 20, 21, 22, 23, 24, 25, 26,
2171 //                       28, 29, 30, 31, 32, 33, 34, 35};
2172 //
2173 
2174     uint bitno = (uint) (difference % 32);
2175 //    cpu.AR [ARn].BITNO = tab [bitno];
2176     // SET_PR_BITNO (ARn, bitFromCnt[bitno % 8]);
2177     SET_AR_CHAR_BITNO (ARn, bitFromCnt[bitno % 8] / 9, bitFromCnt[bitno % 8] % 9);
2178 #if defined(TESTING)
2179     HDBGRegARW (ARn, "s4bd");
2180 #endif
2181   }
2182 
2183 void axbd (cpu_state_t * cpup, uint sz)
     /* [previous][next][first][last][top][bottom][index][help] */
2184   {
2185     uint ARn = GET_ARN (cpu.cu.IWB);
2186     CPTUR (cptUsePRn + ARn);
2187     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2188     word6 reg = GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2189                                      // au, qu, al, ql, xn)
2190     // r is the count of characters
2191     word36 rcnt = getCrAR (cpup, reg);
2192     int32_t r;
2193 
2194     if (sz == 1)
2195       r = SIGNEXT24_32 ((word24) rcnt);
2196     else if (sz == 4)
2197       r = SIGNEXT22_32 ((word22) rcnt);
2198     else if (sz == 6)
2199       r = SIGNEXT21_32 ((word21) rcnt);
2200     else if (sz == 9)
2201       r = SIGNEXT21_32 ((word21) rcnt);
2202     else // if (sz == 36)
2203       r = SIGNEXT18_32 ((word18) rcnt);
2204 
2205     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2206                "axbd sz %d ARn 0%o address 0%o reg 0%o r 0%o\r\n",
2207                sz, ARn, address, reg, r);
2208 
2209     uint augend = 0;
2210     if (GET_A (cpu.cu.IWB))
2211       {
2212        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2213                   "axbd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\r\n",
2214                   ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn),
2215                   GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2216        augend = cpu.AR[ARn].WORDNO * 36u + GET_AR_CHAR (ARn) * 9u + GET_AR_BITNO (ARn);
2217       }
2218     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2219                "axbd augend 0%o\r\n",
2220                augend);
2221     // force to character boundary
2222     //if (sz == 9 || sz == 36 || GET_A (cpu.cu.IWB))
2223     if (sz == 9 || GET_A (cpu.cu.IWB))
2224       {
2225         augend = (augend / sz) * sz;
2226         sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2227                    "axbd force augend 0%o\r\n",
2228                    augend);
2229       }
2230 // If sz == 9, this is an a9bd instruction; ISOLTS says that r is in characters, not bits.
2231 // wow. That breaks the boot bad.
2232 //    if (sz == 9)
2233 //      {
2234 //        r *= 9;
2235 //if (current_running_cpu_idx)
2236 //sim_printf ("axbd force chars 0%o %d. bits\r\n", r, r);
2237 //      }
2238 
2239     int32_t addend = address * 36 + r * (int32_t) sz;
2240     int32_t sum = (int32_t) augend + addend;
2241 
2242     // Handle over/under flow
2243     while (sum < 0)
2244       sum += nxbits;
2245     sum = sum % nxbits;
2246 
2247     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "axbd augend 0%o addend 0%o sum 0%o\r\n", augend, addend, sum);
2248 
2249     cpu.AR [ARn].WORDNO = (word18) (sum / 36) & AMASK;
2250     //SET_PR_BITNO (ARn, sum % 36);
2251 #if defined(TESTING)
2252     HDBGRegARR (ARn, "axbd");
2253 #endif
2254     SET_AR_CHAR_BITNO (ARn, (word2)((sum % 36) / 9), (word2)(sum % 9));
2255 #if defined(TESTING)
2256     HDBGRegARW (ARn, "axbd");
2257 #endif
2258   }
2259 
2260 
2261 void abd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2262   {
2263     uint ARn = GET_ARN (cpu.cu.IWB);
2264     CPTUR (cptUsePRn + ARn);
2265 
2266     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2267 //if (current_running_cpu_idx)
2268 //sim_printf ("address %o\r\n", address);
2269     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2270     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2271     word24 r = getCrAR (cpup, (word4) reg) & MASK24;
2272 //if (current_running_cpu_idx)
2273 //sim_printf ("r 0%o %d.\r\n", r, r);
2274 //if (current_running_cpu_idx)
2275 //sim_printf ("abd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\r\n",
2276 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR,
2277 //            cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2278 
2279     //if (cpu.AR[ARn].BITNO > 8)
2280       //cpu.AR[ARn].BITNO = 8;
2281     if (GET_AR_BITNO (ARn) > 8)
2282       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2283 
2284     if (GET_A (cpu.cu.IWB))
2285       {
2286 //if (current_running_cpu_idx)
2287 //sim_printf ("A 1\r\n");
2288         //word24 bits = 9 * cpu.AR[ARn].CHAR + cpu.AR[ARn].BITNO + r;
2289         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) + r;
2290 //if (current_running_cpu_idx)
2291 //sim_printf ("bits 0%o %d.\r\n", bits, bits);
2292         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO + address +
2293                               bits / 36) & MASK18;
2294         if (r % 36)
2295           {
2296             //cpu.AR[ARn].CHAR = (bits % 36) / 9;
2297             //cpu.AR[ARn].BITNO = bits % 9;
2298             SET_AR_CHAR_BITNO (ARn, (bits % 36) / 9,
2299                                     bits % 9);
2300           }
2301       }
2302     else
2303       {
2304 //if (current_running_cpu_idx)
2305 //sim_printf ("A 0\r\n");
2306         cpu.AR[ARn].WORDNO = (address + r / 36) & MASK18;
2307         if (r % 36)
2308           {
2309             //cpu.AR[ARn].CHAR = (r % 36) / 9;
2310             //cpu.AR[ARn].BITNO = r % 9;
2311             SET_AR_CHAR_BITNO (ARn, (r % 36) / 9,
2312                                     r % 9);
2313           }
2314       }
2315 # if defined(TESTING)
2316     HDBGRegARW (ARn, "abd");
2317 # endif
2318 //if (current_running_cpu_idx)
2319 //sim_printf ("abd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\r\n",
2320 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR,
2321 //            cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
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 
2376 
2377 
2378 
2379 
2380 
2381 
2382 
2383 
2384 
2385 
2386 
2387 
2388 
2389 
2390 
2391 
2392 
2393 
2394 
2395 
2396 
2397 
2398 
2399 
2400 
2401 
2402 
2403 
2404 
2405 
2406 
2407 
2408 
2409 
2410 
2411 
2412 
2413 
2414 
2415 
2416 
2417 
2418 
2419 
2420 
2421 
2422 
2423 
2424 
2425 
2426 
2427 
2428 
2429 
2430 
2431 
2432 
2433 
2434 
2435 
2436 
2437 
2438 
2439 
2440 
2441 
2442 
2443 
2444 
2445 
2446 
2447 
2448 
2449 
2450 
2451 
2452 
2453 
2454 
2455 
2456 
2457 
2458 
2459 
2460 
2461 
2462 
2463 
2464 
2465 
2466 
2467 
2468 
2469 
2470 
2471 void awd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2472   {
2473     uint ARn = GET_ARN (cpu.cu.IWB);
2474     CPTUR (cptUsePRn + ARn);
2475     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2476     // 4-bit register modification (None except
2477     // au, qu, al, ql, xn)
2478     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2479     // r is the count of characters
2480 // XXX This code is assuming that 'r' has 18 bits of data....
2481     int32_t r = (int32_t) (getCrAR (cpup, reg) & MASK18);
2482     r = SIGNEXT18_32 ((word18) r);
2483 
2484     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2485                "awd ARn 0%o address 0%o reg 0%o r 0%o\r\n",
2486                ARn, address, reg, r);
2487 
2488     uint augend = 0;
2489     if (GET_A (cpu.cu.IWB))
2490       {
2491        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2492                   "awd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\r\n",
2493                   ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn),
2494                   GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2495 
2496        //augend = cpu.AR [ARn].WORDNO * 36 + GET_AR_CHAR (ARn) * 9 + GET_AR_BITNO (ARn);
2497        augend = cpu.AR [ARn].WORDNO;
2498       }
2499 
2500     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2501                "awd augend 0%o\r\n",
2502                augend);
2503 
2504     int32_t addend = address + r;
2505     int32_t sum = (int32_t) augend + addend;
2506 
2507     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2508                "awd augend 0%o addend 0%o sum 0%o\r\n",
2509                augend, addend, sum);
2510 
2511     cpu.AR[ARn].WORDNO = (word18) sum & AMASK;
2512     SET_AR_CHAR_BITNO (ARn, 0, 0);
2513 #if defined(TESTING)
2514     HDBGRegARW (ARn, "awd");
2515 #endif
2516   }
2517 
2518 void sbd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2519   {
2520     uint ARn = GET_ARN (cpu.cu.IWB);
2521 
2522     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2523     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2524     // r is the count of bits (0 - 2^18 * 36 -1); 24 bits
2525     word24 r = getCrAR (cpup, (word4) reg) & MASK24;
2526     if (GET_AR_BITNO (ARn) > 8)
2527       SET_AR_CHAR_BITNO (ARn, GET_AR_CHAR (ARn), 8);
2528 
2529     if (GET_A (cpu.cu.IWB))
2530       {
2531         word24 bits = 9u * GET_AR_CHAR (ARn) + GET_AR_BITNO (ARn) - r;
2532         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2533                              address + bits / 36) & MASK18;
2534         if (r % 36)
2535           {
2536             SET_AR_CHAR_BITNO (ARn, (- ((bits % 36) / 9)) & MASK2,
2537                                     (- (bits % 9)) & MASK4);
2538           }
2539       }
2540     else
2541       {
2542         cpu.AR[ARn].WORDNO = (- (address + r / 36)) & MASK18;
2543         if (r % 36)
2544           {
2545             SET_AR_CHAR_BITNO (ARn, (- ((r % 36) / 9)) & MASK2,
2546                                     (- (r % 9)) & MASK4);
2547           }
2548       }
2549 #if defined(TESTING)
2550     HDBGRegARW (ARn, "sbd");
2551 #endif
2552   }
2553 
2554 void swd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2555   {
2556     uint ARn = GET_ARN (cpu.cu.IWB);
2557     CPTUR (cptUsePRn + ARn);
2558     int32_t address = SIGNEXT15_32 (GET_OFFSET (cpu.cu.IWB));
2559     // 4-bit register modification (None except
2560     // au, qu, al, ql, xn)
2561     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2562     // r is the count of characters
2563 // XXX This code is assuming that 'r' has 18 bits of data....
2564     int32_t r = (int32_t) (getCrAR (cpup, reg) & MASK18);
2565     r = SIGNEXT18_32 ((word18) r);
2566 
2567     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2568                "swd ARn 0%o address 0%o reg 0%o r 0%o\r\n",
2569                ARn, address, reg, r);
2570 
2571     uint minued = 0;
2572     if (GET_A (cpu.cu.IWB))
2573       {
2574        sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2575                   "swd ARn %d WORDNO %o CHAR %o BITNO %0o %d.\r\n",
2576                   ARn, cpu.PAR[ARn].WORDNO, GET_AR_CHAR (ARn),
2577                   GET_AR_BITNO (ARn), GET_AR_BITNO (ARn));
2578 
2579        //minued = cpu.AR [ARn].WORDNO * 36 + GET_AR_BITNO (ARn);
2580        minued = cpu.AR [ARn].WORDNO;
2581       }
2582 
2583     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2584                "swd minued 0%o\r\n", minued);
2585 
2586     int32_t subtractend = address + r;
2587     int32_t difference = (int32_t) minued - subtractend;
2588 
2589     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev,
2590                "swd minued 0%o subtractend 0%o difference 0%o\r\n",
2591                minued, subtractend, difference);
2592 
2593     cpu.AR [ARn].WORDNO = (word18) difference & AMASK;
2594     SET_AR_CHAR_BITNO (ARn, 0, 0);
2595 #if defined(TESTING)
2596     HDBGRegARW (ARn, "swd");
2597 #endif
2598   }
2599 
2600 void s9bd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2601   {
2602     uint ARn = GET_ARN (cpu.cu.IWB);
2603     CPTUR (cptUsePRn + ARn);
2604     word18 address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2605     // 4-bit register modification (None except
2606     // au, qu, al, ql, xn)
2607     word4 reg = (word4) GET_TD (cpu.cu.IWB);
2608 
2609     // r is the count of 9-bit characters
2610     word21 r = getCrAR (cpup, reg) & MASK21;;
2611 
2612     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "s9bd r 0%o\r\n", r);
2613 
2614     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "s9bd ARn 0%o address 0%o reg 0%o r 0%o\r\n", ARn, address, reg, r);
2615 
2616     if (GET_A (cpu.cu.IWB))
2617       {
2618         //cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2619         //                      address +
2620         //                      (cpu.AR[ARn].CHAR - r) / 4) & MASK18;
2621         cpu.AR[ARn].WORDNO = (cpu.AR[ARn].WORDNO -
2622                               address +
2623                               (GET_AR_CHAR (ARn) - r) / 4) & MASK18;
2624         //if (r % 36)
2625           //{
2626             //cpu.AR[ARn].CHAR = ((cpu.AR[ARn].CHAR - r) % 4) & MASK2;
2627             //cpu.AR[ARn].CHAR = (cpu.AR[ARn].CHAR - r)  & MASK2;
2628             SET_AR_CHAR_BITNO (ARn, (GET_AR_CHAR (ARn) - r)  & MASK2, 0);
2629           //}
2630       }
2631     else
2632       {
2633         cpu.AR[ARn].WORDNO = (- (address + (r + 3) / 4)) & MASK18;
2634         //if (r % 36)
2635           //{
2636             //cpu.AR[ARn].CHAR = (-r) & MASK2;
2637             SET_AR_CHAR_BITNO (ARn, (-r) & MASK2, 0);
2638           //}
2639       }
2640     //cpu.AR[ARn].BITNO = 0;
2641 #if defined(TESTING)
2642     HDBGRegARW (ARn, "s9bd");
2643 #endif
2644 //if (current_running_cpu_idx)
2645 //sim_printf ("s9bd WORDNO 0%o %d. CHAR %o BITNO 0%o %d.\r\n",
2646 //            cpu.AR[ARn].WORDNO, cpu.AR[ARn].WORDNO, cpu.AR[ARn].CHAR,
2647 //            cpu.AR[ARn].BITNO, cpu.AR[ARn].BITNO);
2648   }
2649 
2650 //
2651 // Address Register arithmetic
2652 //
2653 // This code handles Address Register arithmetic
2654 //
2655 // asxbd (  ,       )
2656 // ABD     1   false
2657 // A4BD    4   false
2658 // A6BD    6   false
2659 // A9BD    9   false
2660 // AWD    36   false
2661 // SBD     1   true
2662 // S4BD    4   true
2663 // S6BD    6   true
2664 // S9BD    9   true
2665 // SWD    36   true
2666 //
2667 
2668 // The general approach is do all of the math as unsigned number of bits,
2669 // modulo 2^18 * 36 (the number of bits in a segment).
2670 //
2671 // To handle subtraction underflow, a preemptive borrow is done if the
2672 // the operation will underflow.
2673 //
2674 // Notes:
2675 //   According to ISOLTS 805, WORDNO is unsigned; this disagrees with AL-39
2676 
2677 void asxbd (cpu_state_t * cpup, uint sz, bool sub)
     /* [previous][next][first][last][top][bottom][index][help] */
2678   {
2679     // Map charno:bitno to bit offset for 4 bit char set
2680     uint map4 [64] =
2681       {      // 9-bit    4-bit
2682           0, // 0  0      0
2683           0, // 0  1      0
2684           0, // 0  2      0
2685           0, // 0  3      0
2686           0, // 0  4      0
2687           5, // 0  5      1
2688           5, // 0  6      1
2689           5, // 0  7      1
2690           5, // 0  8      1
2691           5, // 0  9  ill     guess
2692           5, // 0 10  ill     guess
2693           5, // 0 11  ill     guess
2694           5, // 0 12  ill     guess
2695           5, // 0 13  ill     guess
2696           5, // 0 14  ill     guess
2697           5, // 0 15  ill     guess
2698           9, // 1  0      2
2699           9, // 1  1      2
2700           9, // 1  2      2
2701           9, // 1  3      2
2702           9, // 1  4      2
2703          14, // 1  5      3
2704          14, // 1  6      3
2705          14, // 1  7      3
2706          14, // 1  8      3
2707          14, // 1  9  ill     guess
2708          14, // 1 10  ill ISOLTS 805 loop point 010226 sxbd test no 28 (4bit)
2709          14, // 1 11  ill     guess
2710          14, // 1 12  ill     guess
2711          14, // 1 13  ill     guess
2712          14, // 1 14  ill     guess
2713          14, // 1 15  ill     guess
2714          18, // 2  0      4
2715          18, // 2  1      4
2716          18, // 2  2      4
2717          18, // 2  3      4
2718          18, // 2  4      4
2719          23, // 2  5      5
2720          23, // 2  6      5
2721          23, // 2  7      5
2722          23, // 2  8      5
2723          23, // 2  9  ill     guess
2724          23, // 2 10  ill     guess
2725          23, // 2 11  ill     guess
2726          23, // 2 12  ill   ISOLTS 805 loop point 010226 sxbd test no 26 (4bit)
2727          23, // 2 13  ill     guess
2728          23, // 2 14  ill     guess
2729          23, // 2 15  ill     guess
2730          27, // 3  0      6
2731          27, // 3  1      6
2732          27, // 3  2      6
2733          27, // 3  3      6
2734          27, // 3  4      6
2735          32, // 3  5      7
2736          32, // 3  6      7
2737          32, // 3  7      7
2738          32, // 3  8      7
2739          32, // 3  9  ill     guess
2740          32, // 3 10  ill     guess
2741          32, // 3 11  ill     guess
2742          32, // 3 12  ill     guess
2743          32, // 3 13  ill     guess
2744          32, // 3 14  ill   ISOLTS 805 loop point 010226 sxbd test no 24 (4bit)
2745          32  // 3 15  ill     guess
2746       };
2747     // Map charno:bitno to bit offset for 6 bit char set
2748     uint map6 [64] =
2749       {      // 9-bit    6-bit
2750           0, // 0  0      0
2751           1, // 0  1      0
2752           2, // 0  2      0
2753           3, // 0  3      0
2754           4, // 0  4      0
2755           5, // 0  5      0
2756           6, // 0  6      1
2757           7, // 0  7      1
2758           8, // 0  8      1
2759           6, // 0  9  ill  ISOLTS 805 loop point 010100 sxbd test no 12
2760           6, // 0 10  ill     guess
2761           6, // 0 11  ill     guess
2762           6, // 0 12  ill     guess
2763           6, // 0 13  ill     guess
2764           6, // 0 14  ill     guess
2765           6, // 0 15  ill     guess
2766           9, // 1  0      1
2767          10, // 1  1      1
2768          11, // 1  2      1
2769          12, // 1  3      2
2770          13, // 1  4      2
2771          14, // 1  5      2
2772          15, // 1  6      2
2773          16, // 1  7      2
2774          17, // 1  8      2
2775          12, // 1  9  ill     guess
2776          12, // 1 10  ill     guess
2777          12, // 1 11  ill ISOLTS 805 loop point 010100 sxbd test no 12
2778          12, // 1 12  ill     guess
2779          12, // 1 13  ill     guess
2780          12, // 1 14  ill     guess
2781          12, // 1 15  ill     guess
2782          18, // 2  0      3
2783          19, // 2  1      3
2784          20, // 2  2      3
2785          21, // 2  3      3
2786          22, // 2  4      3
2787          23, // 2  5      3
2788          24, // 2  6      4
2789          25, // 2  7      4
2790          26, // 2  8      4
2791          24, // 2  9  ill     guess
2792          24, // 2 10  ill     guess
2793          24, // 2 11  ill     guess
2794          24, // 2 12  ill     guess
2795          24, // 2 13  ill   ISOLTS 805 loop point 010100 sxbd test no 10
2796          24, // 2 14  ill     guess
2797          24, // 2 15  ill     guess
2798          27, // 3  0      4
2799          28, // 3  1      4
2800          29, // 3  2      4
2801          30, // 3  3      5
2802          31, // 3  4      5
2803          32, // 3  5      5
2804          33, // 3  6      5
2805          34, // 3  7      5
2806          35, // 3  8      5
2807          30, // 3  9  ill     guess
2808          30, // 3 10  ill     guess
2809          30, // 3 11  ill     guess
2810          30, // 3 12  ill     guess
2811          30, // 3 13  ill     guess
2812          30, // 3 14  ill     guess
2813          30  // 3 15  ill   ISOLTS 805 loop point 010100 sxbd test no 8 (6bit)
2814       };
2815     // Map charno:bitno to 1 and 9 bit offset
2816     uint map9 [64] =
2817       {      // 9-bit
2818           0, // 0  0
2819           1, // 0  1
2820           2, // 0  2
2821           3, // 0  3
2822           4, // 0  4
2823           5, // 0  5
2824           6, // 0  6
2825           7, // 0  7
2826           8, // 0  8
2827           8, // 0  9  ill     guess
2828           8, // 0 10  ill     guess
2829           8, // 0 11  ill     guess
2830           8, // 0 12  ill     guess
2831           8, // 0 13  ill     guess
2832           8, // 0 14  ill     guess
2833           8, // 0 15  ill     guess
2834           9, // 1  0
2835          10, // 1  1
2836          11, // 1  2
2837          12, // 1  3
2838          13, // 1  4
2839          14, // 1  5
2840          15, // 1  6
2841          16, // 1  7
2842          17, // 1  8
2843          17, // 1  9  ill     guess
2844          17, // 1 10  ill     guess
2845          17, // 1 11  ill     guess
2846          17, // 1 12  ill     guess
2847          17, // 1 13  ill     guess
2848          17, // 1 14  ill     guess
2849          17, // 1 15  ill     guess
2850          18, // 2  0
2851          19, // 2  1
2852          20, // 2  2
2853          21, // 2  3
2854          22, // 2  4
2855          23, // 2  5
2856          24, // 2  6
2857          25, // 2  7
2858          26, // 2  8
2859          26, // 2  9  ill     guess
2860          26, // 2 10  ill     guess
2861          26, // 2 11  ill     guess
2862          26, // 2 12  ill     guess
2863          26, // 2 13  ill     guess
2864          26, // 2 14  ill     guess
2865          26, // 2 15  ill     guess
2866          27, // 3  0
2867          28, // 3  1
2868          29, // 3  2
2869          30, // 3  3
2870          31, // 3  4
2871          32, // 3  5
2872          33, // 3  6
2873          34, // 3  7
2874          35, // 3  8
2875          35, // 3  9  ill     guess
2876          35, // 3 10  ill     guess
2877          35, // 3 11  ill     guess
2878          35, // 3 12  ill     guess
2879          35, // 3 13  ill     guess
2880          35, // 3 14  ill     guess
2881          35  // 3 15  ill     guess
2882       };
2883 
2884 //
2885 // Extract the operand data from the instruction
2886 //
2887 
2888     uint ARn = GET_ARN (cpu.cu.IWB);
2889     uint address = SIGNEXT15_18 (GET_OFFSET (cpu.cu.IWB));
2890     word4 reg = (word4) GET_TD (cpu.cu.IWB); // 4-bit register modification (None except
2891                                   // au, qu, al, ql, xn)
2892 
2893 //
2894 // Calculate r
2895 //
2896 
2897     // r is the count of characters (or bits if sz is 1; words if sz == 36)
2898     word36 rcnt = getCrAR (cpup, reg);
2899 
2900     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd sz %d r 0%"PRIo64"\r\n", sz, rcnt);
2901 
2902     // Crop rcnt into r based on the operand size.
2903     uint r = 0;
2904 
2905     if (sz == 1)
2906       r = (uint) (rcnt & MASK24);
2907     else if (sz == 4)
2908       r = (uint) (rcnt & MASK22);
2909     else if (sz == 6)
2910       r = (uint) (rcnt & MASK21);
2911     else if (sz == 9)
2912       r = (uint) (rcnt & MASK21);
2913     else // if (sz == 36)
2914       r = (uint) (rcnt & MASK18);
2915 
2916     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd sz %d ARn 0%o address 0%o reg 0%o r 0%o\r\n", sz, ARn, address, reg, r);
2917 
2918 //
2919 // Calculate augend
2920 //
2921 
2922     // If A is set, the instruction is AR = AR op operand; if not, AR = 0 op operand.
2923     uint augend = 0;
2924     if (GET_A (cpu.cu.IWB))
2925       {
2926         // For AWD/SWD, leave CHAR/BITNO alone
2927         if (sz == 36)
2928           {
2929             augend = cpu.AR[ARn].WORDNO * 36u;
2930           }
2931         else
2932           {
2933             uint bitno = GET_AR_BITNO (ARn);
2934             uint charno = GET_AR_CHAR (ARn);
2935 
2936             // The behavior of the DU for cases of CHAR > 9 is not defined; some values
2937             // are tested by ISOLTS, and have been recorded in the mapx tables; the
2938             // missing values are guessed at.
2939 
2940             uint * map;
2941             if (sz == 4)
2942               map = map4;
2943             else if (sz == 6)
2944               map = map6;
2945             else
2946               map = map9;
2947 
2948             augend = cpu.AR[ARn].WORDNO * 36u + map [charno * 16 + bitno];
2949             augend = augend % nxbits;
2950           }
2951       }
2952 
2953 //
2954 // Calculate addend
2955 //
2956 
2957     uint addend = 0;
2958     if (sz == 4)
2959       {
2960         // r is the number of 4 bit characters; each character is actually
2961         // 4.5 bits long
2962         addend = address * 36u + (r * 9) / 2;
2963 
2964         // round the odd character up one bit
2965         // (the odd character starts at bit n/2 + 1, not n/2.)
2966         if ((! sub) && r % 2) // r is odd
2967           addend ++;
2968       }
2969     else
2970       addend = address * 36u + r * sz;
2971 
2972     // Handle overflow
2973     addend = addend % nxbits;
2974 
2975 //
2976 // Calculate sum or difference
2977 //
2978 
2979     uint sum = 0;
2980     if (sub)
2981       {
2982         // Prevent underflow
2983         if (addend > augend)
2984           augend += nxbits;
2985         sum = augend - addend;
2986       }
2987     else
2988       {
2989         sum = augend + addend;
2990         sum %= nxbits;
2991       }
2992 
2993     sim_debug (DBG_TRACEEXT|DBG_CAC, & cpu_dev, "asxbd augend 0%o addend 0%o sum 0%o\r\n", augend, addend, sum);
2994 
2995 //
2996 // Adjust to character boundary
2997 //
2998 
2999     if (sz == 6 || sz == 9)
3000       {
3001         sum = (sum / sz) * sz;
3002       }
3003 
3004 //
3005 // Convert sum to WORDNO/CHAR/BITNO
3006 //
3007 
3008     cpu.AR [ARn].WORDNO = (word18) (sum / 36u) & AMASK;
3009 
3010     // If AWD/SWD clear CHAR/BITNO
3011 
3012     if (sz == 36)
3013       {
3014         SET_AR_CHAR_BITNO (ARn, 0, 0);
3015       }
3016     else
3017       {
3018         if (sz == 4)
3019           {
3020             static uint tab [36] [2] =
3021               {
3022                 // char bitno  offset  4-bit charno
3023                 { 0, 0 }, // 0   0
3024                 { 0, 0 }, // 1
3025                 { 0, 0 }, // 2
3026                 { 0, 0 }, // 3
3027                 { 0, 0 }, // 4
3028 
3029                 { 0, 5 }, // 5   1
3030                 { 0, 5 }, // 6
3031                 { 0, 5 }, // 7
3032                 { 0, 5 }, // 8
3033 
3034                 { 1, 0 }, // 9   2
3035                 { 1, 0 }, // 10
3036                 { 1, 0 }, // 11
3037                 { 1, 0 }, // 12
3038                 { 1, 0 }, // 13
3039 
3040                 { 1, 5 }, // 15  3
3041                 { 1, 5 }, // 15
3042                 { 1, 5 }, // 16
3043                 { 1, 5 }, // 17
3044 
3045                 { 2, 0 }, // 18  4
3046                 { 2, 0 }, // 19
3047                 { 2, 0 }, // 20
3048                 { 2, 0 }, // 21
3049                 { 2, 0 }, // 22
3050 
3051                 { 2, 5 }, // 23  5
3052                 { 2, 5 }, // 24
3053                 { 2, 5 }, // 25
3054                 { 2, 5 }, // 26
3055 
3056                 { 3, 0 }, // 27  6
3057                 { 3, 0 }, // 28
3058                 { 3, 0 }, // 29
3059                 { 3, 0 }, // 30
3060                 { 3, 0 }, // 31
3061 
3062                 { 3, 5 }, // 32  7
3063                 { 3, 5 }, // 33
3064                 { 3, 5 }, // 34
3065                 { 3, 5 }  // 35
3066               };
3067             uint charno = tab [sum % 36u] [0];
3068             uint bitno = tab [sum % 36u] [1];
3069             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
3070           }
3071         else
3072           {
3073             uint charno = (sum % 36u) / 9;
3074             uint bitno = sum % 9;
3075             SET_AR_CHAR_BITNO (ARn, (word2) charno, (word4) bitno);
3076           }
3077       }
3078 #if defined(TESTING)
3079     HDBGRegARW (ARn, "asxbd");
3080 #endif
3081   }
3082 
3083 void cmpc (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3084   {
3085     EISstruct * e = & cpu.currentEISinstruction;
3086 
3087     // For i = 1, 2, ..., minimum (N1,N2)
3088     //    C(Y-charn1)i-1 :: C(Y-charn2)i-1
3089     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
3090     //    C(FILL) :: C(Y-charn2)i-1
3091     // If N1 > N2, then for i = N2+1, N2+2, ..., N1
3092     //    C(Y-charn1)i-1 :: C(FILL)
3093     //
3094     // Indicators:
3095     //     Zero: If C(Y-charn1)i-1 = C(Y-charn2)i-1 for all i, then ON;
3096     //       otherwise, OFF
3097     //     Carry: If C(Y-charn1)i-1 < C(Y-charn2)i-1 for any i, then OFF;
3098     //       otherwise ON
3099 
3100     // Both strings are treated as the data type given for the left-hand
3101     // string, TA1. A data type given for the right-hand string, TA2, is
3102     // ignored.
3103     //
3104     // Comparison is made on full 9-bit fields. If the given data type is not
3105     // 9-bit (TA1 ≠ 0), then characters from C(Y-charn1) and C(Y-charn2) are
3106     // high- order zero filled. All 9 bits of C(FILL) are used.
3107     //
3108     // Instruction execution proceeds until an inequality is found or the
3109     // larger string length count is exhausted.
3110 
3111     fault_ipr_subtype_ mod_fault = 0;
3112 
3113 #if !defined(EIS_SETUP)
3114     setupOperandDescriptor (cpup, 1, &mod_fault);
3115     setupOperandDescriptor (cpup, 2, &mod_fault);
3116 #endif
3117     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3118     parseAlphanumericOperandDescriptor (cpup, 2, 1, false, &mod_fault);
3119 
3120     L68_ (
3121       // L68 raises it immediately
3122       if (mod_fault)
3123         {
3124           doFault (FAULT_IPR,
3125                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3126                    "Illegal modifier");
3127         }
3128     )
3129 
3130     // Bits 9-10 MBZ
3131     if (IWB_IRODD & 0000600000000)
3132       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpc 9-10 MBZ");
3133 
3134     // Bit 23 of OP1 MBZ
3135     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3136       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "cmpc op1 23 MBZ");
3137 
3138 // ISOLTS ps846    test-07a    dec add test
3139 // Sets TA2 to the same as TA1. AL39 says TA2 ignored.
3140 // Try only check bit 23.
3141 // ISOLTS 880 test-04c sets bit 23.
3142 
3143 
3144 
3145 
3146 
3147 
3148 
3149 
3150     DPS8M_ (
3151       // DPS8M raises it delayed
3152       if (mod_fault)
3153         {
3154           doFault (FAULT_IPR,
3155                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3156                    "Illegal modifier");
3157         }
3158     )
3159 
3160     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
3161 
3162     SET_I_ZERO;  // set ZERO flag assuming strings are equal ...
3163     SET_I_CARRY; // set CARRY flag assuming strings are equal ...
3164 
3165     PNL (L68_ (if (max (e->N1, e->N2) < 128)
3166       DU_CYCLE_FLEN_128;))
3167 
3168     for (; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
3169       {
3170         tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA1));
3171         word9 c1 = EISget469 (cpup, 1, cpu.du.CHTALLY); // get Y-char1n
3172         word9 c2 = EISget469 (cpup, 2, cpu.du.CHTALLY); // get Y-char2n
3173 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpc tally %d c1 %03o c2 %03o\r\n", cpu.du.CHTALLY, c1, c2);
3174         if (c1 != c2)
3175           {
3176             CLR_I_ZERO;  // an inequality found
3177             SC_I_CARRY (c1 > c2);
3178             cleanupOperandDescriptor (cpup, 1);
3179             cleanupOperandDescriptor (cpup, 2);
3180             return;
3181           }
3182       }
3183 
3184     if (e -> N1 < e -> N2)
3185       {
3186         for( ; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY ++)
3187           {
3188             tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA1));
3189             word9 c1 = fill;     // use fill for Y-char1n
3190             word9 c2 = EISget469 (cpup, 2, cpu.du.CHTALLY); // get Y-char2n
3191 
3192             if (c1 != c2)
3193               {
3194                 CLR_I_ZERO;  // an inequality found
3195                 SC_I_CARRY (c1 > c2);
3196                 cleanupOperandDescriptor (cpup, 1);
3197                 cleanupOperandDescriptor (cpup, 2);
3198                 return;
3199               }
3200           }
3201       }
3202     else if (e->N1 > e->N2)
3203       {
3204         for ( ; cpu.du.CHTALLY < e->N1; cpu.du.CHTALLY ++)
3205           {
3206             tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA1));
3207             word9 c1 = EISget469 (cpup, 1, cpu.du.CHTALLY); // get Y-char1n
3208             word9 c2 = fill;   // use fill for Y-char2n
3209 
3210             if (c1 != c2)
3211               {
3212                 CLR_I_ZERO;  // an inequality found
3213                 SC_I_CARRY (c1 > c2);
3214                 cleanupOperandDescriptor (cpup, 1);
3215                 cleanupOperandDescriptor (cpup, 2);
3216                 return;
3217               }
3218           }
3219       }
3220     // else ==
3221     cleanupOperandDescriptor (cpup, 1);
3222     cleanupOperandDescriptor (cpup, 2);
3223   }
3224 
3225 /*
3226  * SCD - Scan Characters Double
3227  */
3228 
3229 void scd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3230   {
3231     EISstruct * e = & cpu.currentEISinstruction;
3232 
3233     // For i = 1, 2, ..., N1-1
3234     //   C(Y-charn1)i-1,i :: C(Y-charn2)0,1
3235     // On instruction completion, if a match was found:
3236     //   00...0 -> C(Y3)0,11
3237     //   i-1 -> C(Y3)12,35
3238     // If no match was found:
3239     //   00...0 -> C(Y3)0,11
3240     //      N1-1 -> C(Y3)12,35
3241     //
3242 
3243     // The REG field of MF1 is checked for a legal code. If DU is specified in
3244     // the REG field of MF2 in one of the four multiword instructions (SCD,
3245     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3246     // the character or characters are arranged within the 18 bits of the word
3247     // address portion of the operand descriptor.
3248 
3249     fault_ipr_subtype_ mod_fault = 0;
3250 
3251 #if !defined(EIS_SETUP)
3252     setupOperandDescriptor (cpup, 1, &mod_fault);
3253     setupOperandDescriptor (cpup, 2, &mod_fault);
3254     setupOperandDescriptorCache (cpup,3);
3255 #endif
3256 
3257     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3258     parseAlphanumericOperandDescriptor (cpup, 2, 1, true, &mod_fault); // use TA1
3259     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3260 
3261     L68_ (
3262       // L68 raises it immediately
3263       if (mod_fault)
3264         {
3265           doFault (FAULT_IPR,
3266                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3267                    "Illegal modifier");
3268         }
3269     )
3270 
3271     // Bits 0-10 MBZ
3272     if (IWB_IRODD & 0777600000000)
3273       {
3274         //sim_printf ("scd %12"PRIo64"\r\n", IWB_IRODD);
3275         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scd 0-10 MBZ");
3276       }
3277 
3278     // Bit 23 of OP1 MBZ
3279     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3280       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op1 23 MBZ");
3281 
3282     // Bits 18-28. 30-31 of OP3 MBZ
3283     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3284       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scd op3 18-28. 30-31 MBZ");
3285 
3286     DPS8M_ (
3287       // DPS8M raises it delayed
3288       if (mod_fault)
3289         {
3290           doFault (FAULT_IPR,
3291                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3292                    "Illegal modifier");
3293         }
3294     )
3295 
3296     // Both the string and the test character pair are treated as the data type
3297     // given for the string, TA1. A data type given for the test character
3298     // pair, TA2, is ignored.
3299 
3300     // fetch 'test' char - double
3301     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3302     // instruction word does not contain an operand descriptor for the test
3303     // character; instead, it contains the test character as a direct upper
3304     // operand in bits 0,8.
3305 
3306     word9 c1 = 0;
3307     word9 c2 = 0;
3308 
3309     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3310       {
3311         // per Bull RJ78, p. 5-45
3312 #if defined(EIS_PTR3)
3313         switch (TA1) // Use TA1, not TA2
3314 #else
3315         switch (e -> TA1) // Use TA1, not TA2
3316 #endif
3317         {
3318             case CTA4:
3319 #if defined(EIS_PTR)
3320               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3321               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3322 #else
3323               c1 = (e -> ADDR2.address >> 13) & 017;
3324               c2 = (e -> ADDR2.address >>  9) & 017;
3325 #endif
3326               break;
3327 
3328             case CTA6:
3329 #if defined(EIS_PTR)
3330               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3331               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3332 #else
3333               c1 = (e -> ADDR2.address >> 12) & 077;
3334               c2 = (e -> ADDR2.address >>  6) & 077;
3335 #endif
3336               break;
3337 
3338             case CTA9:
3339 #if defined(EIS_PTR)
3340               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3341               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3342 #else
3343               c1 = (e -> ADDR2.address >> 9) & 0777;
3344               c2 = (e -> ADDR2.address     ) & 0777;
3345 #endif
3346               break;
3347           }
3348       }
3349     else
3350       {
3351         c1 = EISget469 (cpup, 2, 0);
3352         c2 = EISget469 (cpup, 2, 1);
3353       }
3354 
3355 #if defined(EIS_PTR3)
3356     switch (TA1) // Use TA1, not TA2
3357 #else
3358     switch (e -> TA1) // Use TA1, not TA2
3359 #endif
3360       {
3361         case CTA4:
3362           c1 &= 017;    // keep 4-bits
3363           c2 &= 017;    // keep 4-bits
3364           break;
3365 
3366         case CTA6:
3367           c1 &= 077;    // keep 6-bits
3368           c2 &= 077;    // keep 6-bits
3369           break;
3370 
3371         case CTA9:
3372           c1 &= 0777;   // keep 9-bits
3373           c2 &= 0777;   // keep 9-bits
3374           break;
3375       }
3376 
3377     PNL (L68_ (if (e->N1 < 128)
3378       DU_CYCLE_FLEN_128;))
3379 
3380     word9 yCharn11;
3381     word9 yCharn12;
3382     if (e -> N1)
3383       {
3384         uint limit = e -> N1 - 1;
3385         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3386           {
3387             tandd_eis_sample (cpup, cpu.du.CHTALLY, 3); // 6 chars/cycle: PM842 05B-07B <= 9 TROs, PA887 12A TRO inside
3388             yCharn11 = EISget469 (cpup, 1, cpu.du.CHTALLY);
3389             yCharn12 = EISget469 (cpup, 1, cpu.du.CHTALLY + 1);
3390             if (yCharn11 == c1 && yCharn12 == c2)
3391               break;
3392           }
3393         SC_I_TALLY (cpu.du.CHTALLY == limit);
3394       }
3395     else
3396       {
3397         SET_I_TALLY;
3398       }
3399 
3400     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3401     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3402     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3403 
3404     cleanupOperandDescriptor (cpup, 1);
3405     cleanupOperandDescriptor (cpup, 2);
3406     cleanupOperandDescriptor (cpup, 3);
3407  }
3408 
3409 /*
3410  * SCDR - Scan Characters Double Reverse
3411  */
3412 
3413 void scdr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3414   {
3415     EISstruct * e = & cpu.currentEISinstruction;
3416 
3417     // For i = 1, 2, ..., N1-1
3418     //   C(Y-charn1)N1-i-1,N1-i :: C(Y-charn2)0,1
3419     // On instruction completion, if a match was found:
3420     //   00...0 -> C(Y3)0,11
3421     //   i-1 -> C(Y3)12,35
3422     // If no match was found:
3423     //   00...0 -> C(Y3)0,11
3424     //      N1-1 -> C(Y3)12,35
3425     //
3426 
3427     // The REG field of MF1 is checked for a legal code. If DU is specified in
3428     // the REG field of MF2 in one of the four multiword instructions (SCD,
3429     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3430     // the character or characters are arranged within the 18 bits of the word
3431     // address portion of the operand descriptor.
3432 
3433     fault_ipr_subtype_ mod_fault = 0;
3434 
3435 #if !defined(EIS_SETUP)
3436     setupOperandDescriptor(cpup, 1, &mod_fault);
3437     setupOperandDescriptor(cpup, 2, &mod_fault);
3438     setupOperandDescriptorCache(cpup,3);
3439 #endif
3440 
3441     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
3442     parseAlphanumericOperandDescriptor(cpup, 2, 1, true, &mod_fault); // Use TA1
3443     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3444 
3445     L68_ (
3446       // L68 raises it immediately
3447       if (mod_fault)
3448         {
3449           doFault (FAULT_IPR,
3450                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3451                    "Illegal modifier");
3452         }
3453     )
3454 
3455     // Bits 0-10 MBZ
3456     if (IWB_IRODD & 0777600000000)
3457       {
3458         //sim_printf ("scdr %12"PRIo64"\r\n", IWB_IRODD);
3459         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scdr 0-10 MBZ");
3460       }
3461 
3462     // Bit 23 of OP1 MBZ
3463     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3464       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op1 23 MBZ");
3465 
3466     // Bits 18-28. 30-31 of OP3 MBZ
3467     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3468       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scdr op3 18-28. 30-31 MBZ");
3469 
3470     DPS8M_ (
3471       // DPS8M raises it delayed
3472       if (mod_fault)
3473         {
3474           doFault (FAULT_IPR,
3475                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3476                    "Illegal modifier");
3477         }
3478     )
3479 
3480     // Both the string and the test character pair are treated as the data type
3481     // given for the string, TA1. A data type given for the test character
3482     // pair, TA2, is ignored.
3483 
3484     // fetch 'test' char - double
3485     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3486     // instruction word does not contain an operand descriptor for the test
3487     // character; instead, it contains the test character as a direct upper
3488     // operand in bits 0,8.
3489 
3490     word9 c1 = 0;
3491     word9 c2 = 0;
3492 
3493     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3494       {
3495         // per Bull RJ78, p. 5-45
3496 #if defined(EIS_PTR3)
3497         switch (TA1) // Use TA1, not TA2
3498 #else
3499         switch (e -> TA1)
3500 #endif
3501           {
3502             case CTA4:
3503 #if defined(EIS_PTR)
3504               c1 = (cpu.du.D2_PTR_W >> 13) & 017;
3505               c2 = (cpu.du.D2_PTR_W >>  9) & 017;
3506 #else
3507               c1 = (e -> ADDR2.address >> 13) & 017;
3508               c2 = (e -> ADDR2.address >>  9) & 017;
3509 #endif
3510               break;
3511 
3512             case CTA6:
3513 #if defined(EIS_PTR)
3514               c1 = (cpu.du.D2_PTR_W >> 12) & 077;
3515               c2 = (cpu.du.D2_PTR_W >>  6) & 077;
3516 #else
3517               c1 = (e -> ADDR2.address >> 12) & 077;
3518               c2 = (e -> ADDR2.address >>  6) & 077;
3519 #endif
3520               break;
3521 
3522             case CTA9:
3523 #if defined(EIS_PTR)
3524               c1 = (cpu.du.D2_PTR_W >> 9) & 0777;
3525               c2 = (cpu.du.D2_PTR_W     ) & 0777;
3526 #else
3527               c1 = (e -> ADDR2.address >> 9) & 0777;
3528               c2 = (e -> ADDR2.address     ) & 0777;
3529 #endif
3530               break;
3531           }
3532       }
3533     else
3534       {
3535         c1 = EISget469 (cpup, 2, 0);
3536         c2 = EISget469 (cpup, 2, 1);
3537       }
3538 
3539 #if defined(EIS_PTR3)
3540     switch (TA1) // Use TA1, not TA2
3541 #else
3542     switch (e -> TA1) // Use TA1, not TA2
3543 #endif
3544       {
3545         case CTA4:
3546           c1 &= 017;    // keep 4-bits
3547           c2 &= 017;    // keep 4-bits
3548           break;
3549 
3550         case CTA6:
3551           c1 &= 077;    // keep 6-bits
3552           c2 &= 077;    // keep 6-bits
3553           break;
3554 
3555         case CTA9:
3556           c1 &= 0777;   // keep 9-bits
3557           c2 &= 0777;   // keep 9-bits
3558           break;
3559       }
3560 
3561     word9 yCharn11;
3562     word9 yCharn12;
3563 
3564     PNL (L68_ (if (e->N1 < 128)
3565       DU_CYCLE_FLEN_128;))
3566 
3567     if (e -> N1)
3568       {
3569         uint limit = e -> N1 - 1;
3570 
3571         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3572           {
3573             tandd_eis_sample (cpup, cpu.du.CHTALLY, 3); // 6 chars/cycle: PM842 05B-07B <= 9 TROs, PA887 12A TRO inside
3574             yCharn11 = EISget469 (cpup, 1, limit - cpu.du.CHTALLY - 1);
3575             yCharn12 = EISget469 (cpup, 1, limit - cpu.du.CHTALLY);
3576 
3577             if (yCharn11 == c1 && yCharn12 == c2)
3578                 break;
3579           }
3580         SC_I_TALLY (cpu.du.CHTALLY == limit);
3581       }
3582     else
3583       {
3584         SET_I_TALLY;
3585       }
3586 
3587     //word36 CY3 = bitfieldInsert36(0, cpu.du.CHTALLY, 0, 24);
3588     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3589     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3590 
3591     cleanupOperandDescriptor (cpup, 1);
3592     cleanupOperandDescriptor (cpup, 2);
3593     cleanupOperandDescriptor (cpup, 3);
3594   }
3595 
3596 /*
3597  * SCM - Scan with Mask
3598  */
3599 
3600 void scm (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3601   {
3602     EISstruct * e = & cpu.currentEISinstruction;
3603 
3604     // For characters i = 1, 2, ..., N1
3605     //   For bits j = 0, 1, ..., 8
3606     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j (+) (C(Y-charn2)0)j)
3607     //      If C(Z)0,8 = 00...0, then
3608     //           00...0 -> C(Y3)0,11
3609     //           i-1 -> C(Y3)12,35
3610     //      otherwise, continue scan of C(Y-charn1)
3611     // If a masked character match was not found, then
3612     //   00...0 -> C(Y3)0,11
3613     //   N1 -> C(Y3)12,35
3614 
3615     // Starting at location YC1, the L1 type TA1 characters are masked and
3616     // compared with the assumed type TA1 character contained either in
3617     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3618     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3619     // mask is right-justified in bit positions 0-8 of the instruction word.
3620     // Each bit position of the mask that is a 1 prevents that bit position in
3621     // the two characters from entering into the compare.
3622 
3623     // The masked compare operation continues until either a match is found or
3624     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3625     // incremented by 1. When a match is found or when the L1 tally runs out,
3626     // this count is stored right-justified in bits 12-35 of location Y3 and
3627     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3628     // string remain unchanged. The RL bit of the MF2 field is not used.
3629 
3630     // The REG field of MF1 is checked for a legal code. If DU is specified in
3631     // the REG field of MF2 in one of the four multiword instructions (SCD,
3632     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3633     // the character or characters are arranged within the 18 bits of the word
3634     // address portion of the operand descriptor.
3635 
3636     fault_ipr_subtype_ mod_fault = 0;
3637 
3638 #if !defined(EIS_SETUP)
3639     setupOperandDescriptor (cpup, 1, &mod_fault);
3640     setupOperandDescriptor (cpup, 2, &mod_fault);
3641     setupOperandDescriptorCache (cpup,3);
3642 #endif
3643 
3644     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3645     parseAlphanumericOperandDescriptor (cpup, 2, 1, true, &mod_fault);
3646     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3647 
3648     L68_ (
3649       // L68 raises it immediately
3650       if (mod_fault)
3651         {
3652           doFault (FAULT_IPR,
3653                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3654                    "Illegal modifier");
3655         }
3656     )
3657 
3658     // Bits 9-10 MBZ
3659     if (IWB_IRODD & 0000600000000)
3660       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scm 9-10 MBZ");
3661 
3662     // Bit 23 of OP1 MBZ
3663     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3664       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op1 23 MBZ");
3665 
3666     // Bits 18-28, 39-31 of OP3 MBZ
3667     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3668       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scm op3 18-28, 39-31 MBZ");
3669 
3670     DPS8M_ (
3671       // DPS8M raises it delayed
3672       if (mod_fault)
3673         {
3674           doFault (FAULT_IPR,
3675                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3676                    "Illegal modifier");
3677         }
3678     )
3679 
3680     // Both the string and the test character pair are treated as the data type
3681     // given for the string, TA1. A data type given for the test character
3682     // pair, TA2, is ignored.
3683 
3684     // get 'mask'
3685     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3686 
3687     // fetch 'test' char
3688     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3689     // instruction word does not contain an operand descriptor for the test
3690     // character; instead, it contains the test character as a direct upper
3691     // operand in bits 0,8.
3692 
3693     word9 ctest = 0;
3694     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3695       {
3696         word18 duo = GETHI (e -> OP2);
3697         // per Bull RJ78, p. 5-45
3698 #if defined(EIS_PTR3)
3699         switch (TA1) // Use TA1, not TA2
3700 #else
3701         switch (e -> TA1)
3702 #endif
3703           {
3704             case CTA4:
3705               ctest = (duo >> 13) & 017;
3706               break;
3707             case CTA6:
3708               ctest = (duo >> 12) & 077;
3709               break;
3710             case CTA9:
3711               ctest = (duo >> 9) & 0777;
3712               break;
3713           }
3714       }
3715     else
3716       {
3717         ctest = EISget469 (cpup, 2, 0);
3718       }
3719 
3720 #if defined(EIS_PTR3)
3721     switch (TA1) // Use TA1, not TA2
3722 #else
3723     switch (e -> TA1) // use TA1, not TA2
3724 #endif
3725       {
3726         case CTA4:
3727             ctest &= 017;    // keep 4-bits
3728             break;
3729         case CTA6:
3730             ctest &= 077;    // keep 6-bits
3731             break;
3732         case CTA9:
3733             ctest &= 0777;   // keep 9-bits
3734       }
3735 
3736     PNL (L68_ (if (e->N1 < 128)
3737       DU_CYCLE_FLEN_128;))
3738 
3739     uint limit = e -> N1;
3740 
3741     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3742       {
3743         tandd_eis_sample (cpup, cpu.du.CHTALLY, 3); // 6 chars/cycle: PM842 05B-07B <= 9 TROs, PA887 12A TRO inside
3744         word9 yCharn1 = EISget469 (cpup, 1, cpu.du.CHTALLY);
3745         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3746         if (c == 0)
3747           {
3748             //00...0 -> C(Y3)0,11
3749             //i-1 -> C(Y3)12,35
3750             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3751             break;
3752           }
3753       }
3754     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3755     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3756 
3757     SC_I_TALLY (cpu.du.CHTALLY == limit);
3758 
3759     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3760 
3761     cleanupOperandDescriptor (cpup, 1);
3762     cleanupOperandDescriptor (cpup, 2);
3763     cleanupOperandDescriptor (cpup, 3);
3764   }
3765 /*
3766  * SCMR - Scan with Mask in Reverse
3767  */
3768 
3769 void scmr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3770   {
3771     EISstruct * e = & cpu.currentEISinstruction;
3772 
3773     // For characters i = 1, 2, ..., N1
3774     //   For bits j = 0, 1, ..., 8
3775     //      C(Z)j = ~C(MASK)j & ((C(Y-charn1)i-1 )j (+) (C(Y-charn2)0)j)
3776     //      If C(Z)0,8 = 00...0, then
3777     //           00...0 -> C(Y3)0,11
3778     //           i-1 -> C(Y3)12,35
3779     //      otherwise, continue scan of C(Y-charn1)
3780     // If a masked character match was not found, then
3781     //   00...0 -> C(Y3)0,11
3782     //   N1 -> C(Y3)12,35
3783 
3784     // Starting at location YC1, the L1 type TA1 characters are masked and
3785     // compared with the assumed type TA1 character contained either in
3786     // location YC2 or in bits 0-8 or 0-5 of the address field of operand
3787     // descriptor 2 (when the REG field of MF2 specifies DU modification). The
3788     // mask is right-justified in bit positions 0-8 of the instruction word.
3789     // Each bit position of the mask that is a 1 prevents that bit position in
3790     // the two characters from entering into the compare.
3791 
3792     // The masked compare operation continues until either a match is found or
3793     // the tally (L1) is exhausted. For each unsuccessful match, a count is
3794     // incremented by 1. When a match is found or when the L1 tally runs out,
3795     // this count is stored right-justified in bits 12-35 of location Y3 and
3796     // bits 0-11 of Y3 are zeroed. The contents of location YC2 and the source
3797     // string remain unchanged. The RL bit of the MF2 field is not used.
3798 
3799     // The REG field of MF1 is checked for a legal code. If DU is specified in
3800     // the REG field of MF2 in one of the four multiword instructions (SCD,
3801     // SCDR, SCM, or SCMR) for which DU is legal, the CN field is ignored and
3802     // the character or characters are arranged within the 18 bits of the word
3803     // address portion of the operand descriptor.
3804 
3805     fault_ipr_subtype_ mod_fault = 0;
3806 
3807 #if !defined(EIS_SETUP)
3808     setupOperandDescriptor (cpup, 1, &mod_fault);
3809     setupOperandDescriptor (cpup, 2, &mod_fault);
3810     setupOperandDescriptorCache (cpup,3);
3811 #endif
3812 
3813     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
3814     parseAlphanumericOperandDescriptor (cpup, 2, 1, true, &mod_fault);
3815     parseArgOperandDescriptor (cpup, 3, &mod_fault);
3816 
3817     L68_ (
3818       // L68 raises it immediately
3819       if (mod_fault)
3820         {
3821           doFault (FAULT_IPR,
3822                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3823                    "Illegal modifier");
3824         }
3825     )
3826 
3827     // Bits 9-10 MBZ
3828     if (IWB_IRODD & 0000600000000)
3829       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "scmr 9-10 MBZ");
3830 
3831     // Bit 23 of OP1 MBZ
3832     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
3833       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op1 23 MBZ");
3834 
3835     // Bits 18 of OP3 MBZ
3836     //if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000400000)
3837     //  doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18 MBZ");
3838 
3839     // Bits 18-28, 39-31 of OP3 MBZ
3840     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
3841       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "scmr op3 18-28, 39-31 MBZ");
3842 
3843     DPS8M_ (
3844       // DPS8M raises it delayed
3845       if (mod_fault)
3846         {
3847           doFault (FAULT_IPR,
3848                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
3849                    "Illegal modifier");
3850         }
3851     )
3852 
3853     // Both the string and the test character pair are treated as the data type
3854     // given for the string, TA1. A data type given for the test character
3855     // pair, TA2, is ignored.
3856 
3857     // get 'mask'
3858     uint mask = (uint) getbits36_9 (cpu.cu.IWB, 0);
3859 
3860     // fetch 'test' char
3861     // If MF2.ID = 0 and MF2.REG = du, then the second word following the
3862     // instruction word does not contain an operand descriptor for the test
3863     // character; instead, it contains the test character as a direct upper
3864     // operand in bits 0,8.
3865 
3866     word9 ctest = 0;
3867     if (! (e -> MF2 & MFkID) && ((e -> MF2 & MFkREGMASK) == 3))  // MF2.du
3868       {
3869         word18 duo = GETHI (e -> OP2);
3870         // per Bull RJ78, p. 5-45
3871 #if defined(EIS_PTR3)
3872         switch (TA1) // Use TA1, not TA2
3873 #else
3874         switch (e -> TA1)
3875 #endif
3876           {
3877             case CTA4:
3878               ctest = (duo >> 13) & 017;
3879               break;
3880             case CTA6:
3881               ctest = (duo >> 12) & 077;
3882               break;
3883             case CTA9:
3884               ctest = (duo >> 9) & 0777;
3885               break;
3886           }
3887       }
3888     else
3889       {
3890         ctest = EISget469 (cpup, 2, 0);
3891       }
3892 
3893 #if defined(EIS_PTR3)
3894     switch (TA1) // Use TA1, not TA2
3895 #else
3896     switch (e -> TA1) // use TA1, not TA2
3897 #endif
3898       {
3899         case CTA4:
3900             ctest &= 017;    // keep 4-bits
3901             break;
3902         case CTA6:
3903             ctest &= 077;    // keep 6-bits
3904             break;
3905         case CTA9:
3906             ctest &= 0777;   // keep 9-bits
3907       }
3908 
3909     PNL (L68_ (if (e->N1 < 128)
3910       DU_CYCLE_FLEN_128;))
3911 
3912     uint limit = e -> N1;
3913     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
3914       {
3915         tandd_eis_sample (cpup, cpu.du.CHTALLY, 3); // 6 chars/cycle: PM842 05B-07B <= 9 TROs, PA887 12A TRO inside
3916         word9 yCharn1 = EISget469 (cpup, 1, limit - cpu.du.CHTALLY - 1);
3917         word9 c = ((~mask) & (yCharn1 ^ ctest)) & 0777;
3918         if (c == 0)
3919           {
3920             //00...0 -> C(Y3)0,11
3921             //i-1 -> C(Y3)12,35
3922             //Y3 = bitfieldInsert36(Y3, cpu.du.CHTALLY, 0, 24);
3923             break;
3924           }
3925       }
3926     //word36 CY3 = bitfieldInsert36 (0, cpu.du.CHTALLY, 0, 24);
3927     word36 CY3 = setbits36_24 (0, 12, cpu.du.CHTALLY);
3928 
3929     SC_I_TALLY (cpu.du.CHTALLY == limit);
3930 
3931     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
3932 
3933     cleanupOperandDescriptor (cpup, 1);
3934     cleanupOperandDescriptor (cpup, 2);
3935     cleanupOperandDescriptor (cpup, 3);
3936   }
3937 
3938 /*
3939  * TCT - Test Character and Translate
3940  */
3941 
3942 
3943 
3944 
3945 
3946 
3947 
3948 
3949 
3950 
3951 
3952 
3953 
3954 
3955 
3956 
3957 
3958 
3959 
3960 
3961 
3962 
3963 static word9 xlate (cpu_state_t * cpup, EISaddr * xlatTbl, uint dstTA, uint c)
     /* [previous][next][first][last][top][bottom][index][help] */
3964   {
3965     uint idx = (c / 4) & 0177;      // max 128-words (7-bit index)
3966     word36 entry = EISReadIdx(cpup, xlatTbl, idx);
3967 
3968     uint pos9 = c % 4;      // lower 2-bits
3969     word9 cout = GETBYTE (entry, pos9);
3970     switch (dstTA)
3971       {
3972         case CTA4:
3973           return cout & 017;
3974         case CTA6:
3975           return cout & 077;
3976         case CTA9:
3977           return cout;
3978       }
3979     return 0;
3980   }
3981 
3982 void tct (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3983   {
3984     EISstruct * e = & cpu.currentEISinstruction;
3985 
3986     // For i = 1, 2, ..., N1
3987     //   m = C(Y-charn1)i-1
3988     //   If C(Y-char92)m ≠ 00...0, then
3989     //     C(Y-char92)m -> C(Y3)0,8
3990     //     000 -> C(Y3)9,11
3991     //     i-1 -> C(Y3)12,35
3992     //   otherwise, continue scan of C(Y-charn1)
3993     // If a non-zero table entry was not found, then 00...0 -> C(Y3)0,11
3994     // N1 -> C(Y3)12,35
3995     //
3996     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
3997     // otherwise, OFF
3998     //
3999     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
4000     // then characters from C(Y-charn1) are high-order zero filled in forming
4001     // the table index, m.
4002     // Instruction execution proceeds until a non-zero table entry is found or
4003     // the string length count is exhausted.
4004     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
4005     // on a word boundary.
4006 
4007     fault_ipr_subtype_ mod_fault = 0;
4008 
4009 #if !defined(EIS_SETUP)
4010     setupOperandDescriptor (cpup, 1, &mod_fault);
4011     setupOperandDescriptorCache (cpup,2);
4012     setupOperandDescriptorCache (cpup,3);
4013 #endif
4014 
4015     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
4016     parseArgOperandDescriptor (cpup, 2, &mod_fault);
4017     parseArgOperandDescriptor (cpup, 3, &mod_fault);
4018 
4019     L68_ (
4020       // L68 raises it immediately
4021       if (mod_fault)
4022         {
4023           doFault (FAULT_IPR,
4024                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4025                    "Illegal modifier");
4026         }
4027     )
4028 
4029     // Bits 0-17 MBZ
4030     if (IWB_IRODD & 0777777000000)
4031       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tct 0-17 MBZ");
4032 
4033     // Bit 23 of OP1 MBZ
4034     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4035       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op1 23 MBZ");
4036 
4037     // Bits 18-28, 39-31 of OP2 MBZ
4038     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
4039       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op2 18-28, 39-31 MBZ");
4040 
4041     // Bits 18-28, 39-31 of OP3 MBZ
4042     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
4043       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tct op3 18-28, 39-31 MBZ");
4044 
4045     DPS8M_ (
4046       // DPS8M raises it delayed
4047       if (mod_fault)
4048         {
4049           doFault (FAULT_IPR,
4050                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4051                    "Illegal modifier");
4052         }
4053     )
4054 
4055 #if defined(EIS_PTR3)
4056     sim_debug (DBG_TRACEEXT, & cpu_dev,
4057                "TCT CN1: %d TA1: %d\r\n", e -> CN1, TA1);
4058 #else
4059     sim_debug (DBG_TRACEEXT, & cpu_dev,
4060                "TCT CN1: %d TA1: %d\r\n", e -> CN1, e -> TA1);
4061 #endif
4062 
4063     uint srcSZ = 0;
4064 
4065 #if defined(EIS_PTR3)
4066     switch (TA1)
4067 #else
4068     switch (e -> TA1)
4069 #endif
4070       {
4071         case CTA4:
4072             srcSZ = 4;
4073             break;
4074         case CTA6:
4075             srcSZ = 6;
4076             break;
4077         case CTA9:
4078             srcSZ = 9;
4079             break;
4080       }
4081 
4082     // ISOLTS-878 01h asserts no prepaging
4083 
4084 
4085 
4086 
4087 
4088 
4089 
4090 
4091 
4092 
4093 
4094 
4095 
4096 
4097 
4098 
4099 
4100 
4101 
4102 
4103 
4104 
4105 
4106 
4107 
4108 
4109 
4110 
4111 
4112 
4113 
4114 
4115 
4116 
4117 
4118 
4119 
4120 
4121     word36 CY3 = 0;
4122 
4123     sim_debug (DBG_TRACEEXT, & cpu_dev,
4124                "TCT N1 %d\r\n", e -> N1);
4125 
4126     PNL (L68_ (if (e->N1 < 128)
4127       DU_CYCLE_FLEN_128;))
4128 
4129     for ( ; cpu.du.CHTALLY < e -> N1; cpu.du.CHTALLY ++)
4130       {
4131         tandd_eis_sample (cpup, cpu.du.CHTALLY, 2); // a table read per char
4132         word9 c = EISget469 (cpup, 1, cpu.du.CHTALLY); // get src char
4133 
4134         uint m = 0;
4135 
4136         switch (srcSZ)
4137           {
4138             case 4:
4139               m = c & 017;    // truncate upper 2-bits
4140               break;
4141             case 6:
4142               m = c & 077;    // truncate upper 3-bits
4143               break;
4144             case 9:
4145               m = c;          // keep all 9-bits
4146               break;              // should already be 0-filled
4147           }
4148 
4149         word9 cout = xlate (cpup, &e->ADDR2, CTA9, m);
4150 
4151         sim_debug (DBG_TRACEEXT, & cpu_dev,
4152                    "TCT c %03o %c cout %03o %c\r\n",
4153                    m, isprint ((int) m) ? '?' : (char) m,
4154                    cout, isprint ((int) cout) ? '?' : (char) cout);
4155 
4156         if (cout)
4157           {
4158             // CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4159             CY3 = setbits36_9 (0, 0, cout);
4160             break;
4161           }
4162       }
4163 
4164     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4165 
4166     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4167     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4168     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
4169 
4170     cleanupOperandDescriptor (cpup, 1);
4171     cleanupOperandDescriptor (cpup, 2);
4172     cleanupOperandDescriptor (cpup, 3);
4173   }
4174 
4175 void tctr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4176   {
4177     EISstruct * e = & cpu.currentEISinstruction;
4178 
4179     // For i = 1, 2, ..., N1
4180     //   m = C(Y-charn1)N1-i
4181     //   If C(Y-char92)m ≠ 00...0, then
4182     //     C(Y-char92)m -> C(Y3)0,8
4183     //     000 -> C(Y3)9,11
4184     //     i-1 -> C(Y3)12,35
4185     //   otherwise, continue scan of C(Y-charn1) If a non-zero table entry was
4186     //   not found, then
4187     // 00...0 -> C(Y3)0,11
4188     // N1 -> C(Y3)12,35
4189     //
4190     // Indicators: Tally Run Out. If the string length count exhausts, then ON;
4191     // otherwise, OFF
4192     //
4193     // If the data type of the string to be scanned is not 9-bit (TA1 ≠ 0),
4194     // then characters from C(Y-charn1) are high-order zero filled in forming
4195     // the table index, m.
4196 
4197     // Instruction execution proceeds until a non-zero table entry is found or
4198     // the string length count is exhausted.
4199 
4200     // The character number of Y-char92 must be zero, i.e., Y-char92 must start
4201     // on a word boundary.
4202 
4203     fault_ipr_subtype_ mod_fault = 0;
4204 
4205 #if !defined(EIS_SETUP)
4206     setupOperandDescriptor (cpup, 1, &mod_fault);
4207     setupOperandDescriptorCache (cpup,2);
4208     setupOperandDescriptorCache (cpup,3);
4209 #endif
4210 
4211     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
4212     parseArgOperandDescriptor (cpup, 2, &mod_fault);
4213     parseArgOperandDescriptor (cpup, 3, &mod_fault);
4214 
4215     L68_ (
4216       // L68 raises it immediately
4217       if (mod_fault)
4218         {
4219           doFault (FAULT_IPR,
4220                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4221                    "Illegal modifier");
4222         }
4223     )
4224 
4225     // Bits 0-17 MBZ
4226     if (IWB_IRODD & 0777777000000)
4227       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "tctr 0-17 MBZ");
4228 
4229     // Bit 23 of OP1 MBZ
4230     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4231       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op1 23 MBZ");
4232 
4233     // Bits 18-28, 39-31 of OP2 MBZ
4234     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000777660)
4235       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op2 18-28, 39-31 MBZ");
4236 
4237     // Bits 18-28, 39-31 of OP3 MBZ
4238     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777660)
4239       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "tctr op3 18-28, 39-31 MBZ");
4240 
4241     DPS8M_ (
4242       // DPS8M raises it delayed
4243       if (mod_fault)
4244         {
4245           doFault (FAULT_IPR,
4246                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4247                    "Illegal modifier");
4248         }
4249     )
4250 
4251 #if defined(EIS_PTR3)
4252     sim_debug (DBG_TRACEEXT, & cpu_dev,
4253                "TCTR CN1: %d TA1: %d\r\n", e -> CN1, TA1);
4254 #else
4255     sim_debug (DBG_TRACEEXT, & cpu_dev,
4256                "TCTR CN1: %d TA1: %d\r\n", e -> CN1, e -> TA1);
4257 #endif
4258 
4259     uint srcSZ = 0;
4260 
4261 #if defined(EIS_PTR3)
4262     switch (TA1)
4263 #else
4264     switch (e -> TA1)
4265 #endif
4266       {
4267         case CTA4:
4268             srcSZ = 4;
4269             break;
4270         case CTA6:
4271             srcSZ = 6;
4272             break;
4273         case CTA9:
4274             srcSZ = 9;
4275             break;
4276       }
4277 
4278     // ISOLTS-878 01i asserts no prepaging
4279 
4280 
4281 
4282 
4283 
4284 
4285 
4286 
4287 
4288 
4289 
4290 
4291 
4292 
4293 
4294 
4295 
4296 
4297 
4298 
4299 
4300 
4301 
4302 
4303 
4304 
4305 
4306 
4307 
4308 
4309 
4310 
4311 
4312 
4313 
4314 
4315 
4316 
4317     word36 CY3 = 0;
4318 
4319     sim_debug (DBG_TRACEEXT, & cpu_dev,
4320                "TCT N1 %d\r\n", e -> N1);
4321 
4322     PNL (L68_ (if (e->N1 < 128)
4323       DU_CYCLE_FLEN_128;))
4324 
4325     uint limit = e -> N1;
4326     for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY ++)
4327       {
4328         tandd_eis_sample (cpup, cpu.du.CHTALLY, 2); // a table read per char
4329         word9 c = EISget469 (cpup, 1, limit - cpu.du.CHTALLY - 1); // get src char
4330 
4331         uint m = 0;
4332 
4333         switch (srcSZ)
4334           {
4335             case 4:
4336               m = c & 017;    // truncate upper 2-bits
4337               break;
4338             case 6:
4339               m = c & 077;    // truncate upper 3-bits
4340               break;
4341             case 9:
4342               m = c;          // keep all 9-bits
4343               break;              // should already be 0-filled
4344           }
4345 
4346         word9 cout = xlate (cpup, &e->ADDR2, CTA9, m);
4347 
4348         sim_debug (DBG_TRACEEXT, & cpu_dev,
4349                    "TCT c %03o %c cout %03o %c\r\n",
4350                    m, isprint ((int) m) ? '?' : (char) m,
4351                    cout, isprint ((int) cout) ? '?' : (char) cout);
4352 
4353         if (cout)
4354           {
4355             //CY3 = bitfieldInsert36 (0, cout, 27, 9); // C(Y-char92)m -> C(Y3)0,8
4356             CY3 = setbits36_9 (0, 0, cout);
4357             break;
4358           }
4359       }
4360 
4361     SC_I_TALLY (cpu.du.CHTALLY == e -> N1);
4362 
4363     //CY3 = bitfieldInsert36 (CY3, cpu.du.CHTALLY, 0, 24);
4364     putbits36_24 (& CY3, 12, cpu.du.CHTALLY);
4365     EISWriteIdx (cpup, & e -> ADDR3, 0, CY3, true);
4366 
4367     cleanupOperandDescriptor (cpup, 1);
4368     cleanupOperandDescriptor (cpup, 2);
4369     cleanupOperandDescriptor (cpup, 3);
4370   }
4371 
4372 /*
4373  * MLR - Move Alphanumeric Left to Right
4374  *
4375  * (Nice, simple instruction if it weren't for the stupid overpunch stuff that ruined it!!!!)
4376  */
4377 
4378 /*
4379  * does 6-bit char represent a GEBCD negative overpunch? if so, which numeral?
4380  * Refer to Bull NovaScale 9000 RJ78 Rev2 p11-178
4381  */
4382 
4383 
4384 
4385 
4386 
4387 
4388 
4389 
4390 
4391 
4392 
4393 
4394 
4395 
4396 
4397 
4398 
4399 
4400 
4401 
4402 
4403 
4404 
4405 
4406 
4407 // RJ78 p.11-178,D-6
4408 static bool isGBCDOvp (uint c, bool * isNeg)
     /* [previous][next][first][last][top][bottom][index][help] */
4409   {
4410     if (c & 020)
4411       {
4412         * isNeg = false;
4413         return true;
4414       }
4415     if (c & 040)
4416       {
4417         * isNeg = true;
4418         return true;
4419       }
4420     return false;
4421   }
4422 
4423 // Applies to both MLR and MRL
4424 //
4425 // If L1 is greater than L2, the least significant (L1-L2) characters are not moved and
4426 // the Truncation indicator is set. If L1 is less than L2, bits 0-8, 3-8, or 5-8 of the FILL
4427 // character (depending on TA2) are inserted as the least significant (L2-L1)
4428 // characters. If L1 is less than L2, bit 0 of C(FILL) = 1, TA1 = 01, and TA2 = 10
4429 // (6-4 move); the hardware looks for a 6-bit overpunched sign. If a negative
4430 // overpunch sign is found, a negative sign (octal 15) is inserted as the last FILL
4431 // character. If a negative overpunch sign is not found, a positive sign (octal 14) is
4432 // inserted as the last FILL character
4433 
4434 void mlr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4435   {
4436     EISstruct * e = & cpu.currentEISinstruction;
4437 
4438     // For i = 1, 2, ..., minimum (N1,N2)
4439     //     C(Y-charn1)N1-i -> C(Y-charn2)N2-i
4440     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4441     //    C(FILL) -> C(Y-charn2)N2-i
4442     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4443 
4444     fault_ipr_subtype_ mod_fault = 0;
4445 
4446 #if !defined(EIS_SETUP)
4447     setupOperandDescriptor (cpup, 1, &mod_fault);
4448     setupOperandDescriptor (cpup, 2, &mod_fault);
4449     //setupOperandDescriptorCache (cpup,3);
4450 #endif
4451 
4452     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
4453     parseAlphanumericOperandDescriptor(cpup, 2, 2, false, &mod_fault);
4454 
4455     L68_ (
4456       // L68 raises it immediately
4457       if (mod_fault)
4458         {
4459           doFault (FAULT_IPR,
4460                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4461                    "Illegal modifier");
4462         }
4463     )
4464 
4465     // Bit 10 MBZ
4466     if (IWB_IRODD & 0000200000000)
4467       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mlr 10 MBZ");
4468 
4469     // Bit 23 of OP1 MBZ
4470     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4471       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op1 23 MBZ");
4472 
4473     // Bit 23 of OP2 MBZ
4474     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4475       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mlr op2 23 MBZ");
4476 
4477     DPS8M_ (
4478       // DPS8M raises it delayed
4479       if (mod_fault)
4480         {
4481           doFault (FAULT_IPR,
4482                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4483                    "Illegal modifier");
4484         }
4485     )
4486 
4487     int srcSZ = 0, dstSZ = 0;
4488 
4489 #if defined(EIS_PTR3)
4490     switch (TA1)
4491 #else
4492     switch (e -> TA1)
4493 #endif
4494       {
4495         case CTA4:
4496           srcSZ = 4;
4497           break;
4498         case CTA6:
4499           srcSZ = 6;
4500           break;
4501         case CTA9:
4502           srcSZ = 9;
4503           break;
4504       }
4505 
4506 #if defined(EIS_PTR3)
4507     switch (TA2)
4508 #else
4509     switch (e -> TA2)
4510 #endif
4511       {
4512         case CTA4:
4513           dstSZ = 4;
4514           break;
4515         case CTA6:
4516           dstSZ = 6;
4517           break;
4518         case CTA9:
4519           dstSZ = 9;
4520           break;
4521       }
4522 
4523     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4524 
4525     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4526     word9 fillT = fill;  // possibly truncated fill pattern
4527 
4528     // play with fill if we need to use it
4529     switch (dstSZ)
4530       {
4531         case 4:
4532           fillT = fill & 017;    // truncate upper 5-bits
4533           break;
4534         case 6:
4535           fillT = fill & 077;    // truncate upper 3-bits
4536           break;
4537       }
4538 
4539     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4540     // and the truncation indicator is set ON.
4541 
4542     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4543     // characters are high-order truncated as they are moved to C(Y-charn2). No
4544     // character conversion takes place.
4545 
4546     // The user of string replication or overlaying is warned that the decimal
4547     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4548     // units of Y-block8 words and that the overlaid string, C(Y-charn2), is
4549     // not returned to main memory until the unit of Y-block8 words is filled or
4550     // the instruction completes.
4551 
4552     // If T = 1 and the truncation indicator is set ON by execution of the
4553     // instruction, then a truncation (overflow) fault occurs.
4554 
4555     // Attempted execution with the xed instruction causes an illegal procedure
4556     // fault.
4557 
4558     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4559     // illegal procedure fault.
4560 
4561     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4562       DU_CYCLE_FLEN_128;))
4563 
4564 #if defined(EIS_PTR3)
4565     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4566                (TA2 == 2); // (6-4 move)
4567 #else
4568     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4569                (e -> TA2 == 2); // (6-4 move)
4570 #endif
4571     //word9 on;     // number overpunch represents (if any)
4572     bool isNeg = false;
4573     //bool bOvp = false;  // true when a negative overpunch character has been
4574                         // found @ N1-1
4575 
4576 #if defined(EIS_PTR3)
4577     sim_debug (DBG_TRACEEXT, & cpu_dev,
4578                "MLR TALLY %u TA1 %u TA2 %u N1 %u N2 %u CN1 %u CN2 %u\r\n",
4579                cpu.du.CHTALLY, TA1, TA2, e -> N1, e -> N2, e -> CN1, e -> CN2);
4580 #else
4581     sim_debug (DBG_TRACEEXT, & cpu_dev,
4582                "MLR TALLY %u TA1 %u TA2 %u N1 %u N2 %u CN1 %u CN2 %u\r\n",
4583                cpu.du.CHTALLY, e -> TA1, e -> TA2, e -> N1, e -> N2, e -> CN1, e -> CN2);
4584 #endif
4585 
4586 //
4587 // Multics frequently uses certain code sequences which are easily detected
4588 // and optimized; eg. it uses the MLR instruction to copy or zero segments.
4589 //
4590 // The MLR implementation is correct, not efficient. Copy invokes 12 append
4591 // cycles per word, and fill 8.
4592 //
4593 
4594 //
4595 // Page copy
4596 //
4597 
4598     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4599 #if defined(EIS_PTR3)
4600         TA1 == CTA9 &&  // src and dst are both char 9
4601         TA2 == CTA9 &&
4602 #else
4603         e -> TA1 == CTA9 &&  // src and dst are both char 9
4604         e -> TA2 == CTA9 &&
4605 #endif
4606         (e -> N1 % (PGSZ * 4)) == 0 &&  // a page
4607         e -> N2 == e -> N1 && // the src is the same size as the dest.
4608         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4609         e -> CN2 == 0 &&
4610 #if defined(EIS_PTR)
4611         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4612         (cpu.du.D2_PTR_W & PGMK) == 0)
4613 #else
4614         (e -> ADDR1.address & PGMK) == 0 &&
4615         (e -> ADDR2.address & PGMK) == 0)
4616 #endif
4617       {
4618         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #3\r\n");
4619         while (cpu.du.CHTALLY < e -> N1)
4620           {
4621             word36 pg [PGSZ];
4622             EISReadPage (cpup, & e -> ADDR1, cpu.du.CHTALLY / 4, pg);
4623             EISWritePage (cpup, & e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4624             cpu.du.CHTALLY += PGSZ * 4;
4625           }
4626         cleanupOperandDescriptor (cpup, 1);
4627         cleanupOperandDescriptor (cpup, 2);
4628         // truncation fault check does need to be checked for here since
4629         // it is known that N1 == N2
4630         CLR_I_TRUNC;
4631         return;
4632       }
4633 
4634 //
4635 // Page zero
4636 //
4637 
4638     if ((cpu.du.CHTALLY % PGSZ) == 0 &&
4639 #if defined(EIS_PTR3)
4640         TA1 == CTA9 &&  // src and dst are both char 9
4641         TA2 == CTA9 &&
4642 #else
4643         e -> TA1 == CTA9 &&  // src and dst are both char 9
4644         e -> TA2 == CTA9 &&
4645 #endif
4646         e -> N1 == 0 && // the source is entirely fill
4647         (e -> N2 % (PGSZ * 4)) == 0 &&  // a page
4648         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4649         e -> CN2 == 0 &&
4650 #if defined(EIS_PTR)
4651         (cpu.du.D1_PTR_W & PGMK) == 0 &&
4652         (cpu.du.D2_PTR_W& PGMK) == 0)
4653 #else
4654         (e -> ADDR1.address & PGMK) == 0 &&
4655         (e -> ADDR2.address & PGMK) == 0)
4656 #endif
4657       {
4658         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #4\r\n");
4659         word36 pg [PGSZ];
4660         if (fill)
4661           {
4662             word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4663             for (uint i = 0; i < PGSZ; i ++)
4664               pg [i] = w;
4665           }
4666         else
4667           {
4668            (void)memset (pg, 0, sizeof (pg));
4669           }
4670         while (cpu.du.CHTALLY < e -> N2)
4671           {
4672             EISWritePage (cpup, & e -> ADDR2, cpu.du.CHTALLY / 4, pg);
4673             cpu.du.CHTALLY += PGSZ * 4;
4674           }
4675         cleanupOperandDescriptor (cpup, 1);
4676         cleanupOperandDescriptor (cpup, 2);
4677         // truncation fault check does need to be checked for here since
4678         // it is known that N1 == N2
4679         CLR_I_TRUNC;
4680         return;
4681       }
4682 
4683 // Test for the case of aligned word move; and do things a word at a time,
4684 // instead of a byte at a time...
4685 
4686 #if defined(EIS_PTR3)
4687     if (TA1 == CTA9 &&  // src and dst are both char 9
4688         TA2 == CTA9 &&
4689 #else
4690     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4691         e -> TA2 == CTA9 &&
4692 #endif
4693         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4694         e -> N2 == e -> N1 && // the src is the same size as the dest.
4695         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4696         e -> CN2 == 0)
4697       {
4698         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #1\r\n");
4699         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4700           {
4701             tandd_eis_sample (cpup, cpu.du.CHTALLY, 4);
4702             uint n = cpu.du.CHTALLY / 4;
4703             word36 w = EISReadIdx (cpup, & e -> ADDR1, n);
4704             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
4705           }
4706         cleanupOperandDescriptor (cpup, 1);
4707         cleanupOperandDescriptor (cpup, 2);
4708         // truncation fault check does need to be checked for here since
4709         // it is known that N1 == N2
4710         CLR_I_TRUNC;
4711         return;
4712       }
4713 
4714 // Test for the case of aligned word fill; and do things a word at a time,
4715 // instead of a byte at a time...
4716 
4717 #if defined(EIS_PTR3)
4718     if (TA1 == CTA9 && // src and dst are both char 9
4719         TA2 == CTA9 &&
4720 #else
4721     if (e -> TA1 == CTA9 && // src and dst are both char 9
4722         e -> TA2 == CTA9 &&
4723 #endif
4724         e -> N1 == 0 && // the source is entirely fill
4725         e -> N2 % 4 == 0 && // a whole number of words in the dest
4726         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4727         e -> CN2 == 0)
4728       {
4729         sim_debug (DBG_TRACEEXT, & cpu_dev, "MLR special case #2\r\n");
4730         word36 w = (word36) fill | ((word36) fill << 9) | ((word36) fill << 18) | ((word36) fill << 27);
4731         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
4732           {
4733             tandd_eis_sample (cpup, cpu.du.CHTALLY, 4);
4734             uint n = cpu.du.CHTALLY / 4;
4735             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
4736           }
4737         cleanupOperandDescriptor (cpup, 1);
4738         cleanupOperandDescriptor (cpup, 2);
4739         // truncation fault check does need to be checked for here since
4740         // it is known that N1 <= N2
4741         CLR_I_TRUNC;
4742         return;
4743       }
4744 
4745     uint tdPer = TDPER (e -> TA2);
4746     for ( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY ++)
4747       {
4748         tandd_eis_sample (cpup, cpu.du.CHTALLY, tdPer);
4749         word9 c = EISget469 (cpup, 1, cpu.du.CHTALLY); // get src char
4750         word9 cout = 0;
4751 
4752 #if defined(EIS_PTR3)
4753         if (TA1 == TA2)
4754 #else
4755         if (e -> TA1 == e -> TA2)
4756 #endif
4757           EISput469 (cpup, 2, cpu.du.CHTALLY, c);
4758         else
4759           {
4760             // If data types are dissimilar (TA1 ≠ TA2), each character is
4761             // high-order truncated or zero filled, as appropriate, as it is
4762             // moved. No character conversion takes place.
4763             cout = c;
4764             switch (srcSZ)
4765               {
4766                 case 6:
4767                   switch(dstSZ)
4768                     {
4769                       case 4:
4770                         cout = c & 017;    // truncate upper 2-bits
4771                         break;
4772                       case 9:
4773                         break;              // should already be 0-filled
4774                     }
4775                   break;
4776                 case 9:
4777                   switch(dstSZ)
4778                     {
4779                       case 4:
4780                         cout = c & 017;    // truncate upper 5-bits
4781                         break;
4782                       case 6:
4783                         cout = c & 077;    // truncate upper 3-bits
4784                         break;
4785                     }
4786                   break;
4787               }
4788 
4789             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
4790             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
4791             // negative overpunch sign is found, then the minus sign character
4792             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
4793             // is placed in C(Y-charn2)N2-1.
4794 
4795             if (ovp && (cpu.du.CHTALLY == e -> N1 - 1))
4796               {
4797                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
4798                 // ISOLTS-838 01e, RJ78 p. 11-126
4799                 isGBCDOvp (c, & isNeg);
4800               }
4801             EISput469 (cpup, 2, cpu.du.CHTALLY, cout);
4802           }
4803       }
4804 
4805     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4806     //    C(FILL) -> C(Y-charn2)N2-i
4807     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4808     // characters are high-order truncated as they are moved to C(Y-charn2). No
4809     // character conversion takes place.
4810 
4811     if (e -> N1 < e -> N2)
4812       {
4813         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
4814           {
4815             tandd_eis_sample (cpup, cpu.du.CHTALLY, tdPer);
4816             // if there's an overpunch then the sign will be the last of the fill
4817             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
4818               {
4819                 if (isNeg)
4820                   EISput469 (cpup, 2, cpu.du.CHTALLY, 015); // 015 is decimal -
4821                 else
4822                   EISput469 (cpup, 2, cpu.du.CHTALLY, 014); // 014 is decimal +
4823               }
4824             else
4825               EISput469 (cpup, 2, cpu.du.CHTALLY, fillT);
4826           }
4827     }
4828     cleanupOperandDescriptor (cpup, 1);
4829     cleanupOperandDescriptor (cpup, 2);
4830 
4831     if (e -> N1 > e -> N2)
4832       {
4833         SET_I_TRUNC;
4834         if (T && ! TST_I_OMASK)
4835           doFault (FAULT_OFL, fst_zero, "mlr truncation fault");
4836       }
4837     else
4838       CLR_I_TRUNC;
4839   }
4840 
4841 void mrl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4842   {
4843     EISstruct * e = & cpu.currentEISinstruction;
4844 
4845     // For i = 1, 2, ..., minimum (N1,N2)
4846     //     C(Y-charn1)N1-i -> C(Y-charn2)N2-i
4847     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
4848     //    C(FILL) -> C(Y-charn2)N2-i
4849     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
4850 
4851     fault_ipr_subtype_ mod_fault = 0;
4852 
4853 #if !defined(EIS_SETUP)
4854     setupOperandDescriptor (cpup, 1, &mod_fault);
4855     setupOperandDescriptor (cpup, 2, &mod_fault);
4856     //setupOperandDescriptorCache (cpup,3);
4857 #endif
4858 
4859     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
4860     parseAlphanumericOperandDescriptor(cpup, 2, 2, false, &mod_fault);
4861 
4862     L68_ (
4863       // L68 raises it immediately
4864       if (mod_fault)
4865         {
4866           doFault (FAULT_IPR,
4867                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4868                    "Illegal modifier");
4869         }
4870     )
4871 
4872     // Bit 10 MBZ
4873     if (IWB_IRODD & 0000200000000)
4874       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mrl 10 MBZ");
4875 
4876     // Bit 23 of OP1 MBZ
4877     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
4878       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op1 23 MBZ");
4879 
4880     // Bit 23 of OP2 MBZ
4881     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
4882       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mrl op2 23 MBZ");
4883 
4884     DPS8M_ (
4885       // DPS8M raises it delayed
4886       if (mod_fault)
4887         {
4888           doFault (FAULT_IPR,
4889                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
4890                    "Illegal modifier");
4891         }
4892     )
4893 
4894     int srcSZ = 0, dstSZ = 0;
4895 
4896 #if defined(EIS_PTR3)
4897     switch (TA1)
4898 #else
4899     switch (e -> TA1)
4900 #endif
4901       {
4902         case CTA4:
4903           srcSZ = 4;
4904           break;
4905         case CTA6:
4906           srcSZ = 6;
4907           break;
4908         case CTA9:
4909           srcSZ = 9;
4910           break;
4911       }
4912 
4913 #if defined(EIS_PTR3)
4914     switch (TA2)
4915 #else
4916     switch (e -> TA2)
4917 #endif
4918       {
4919         case CTA4:
4920           dstSZ = 4;
4921           break;
4922         case CTA6:
4923           dstSZ = 6;
4924           break;
4925         case CTA9:
4926           dstSZ = 9;
4927           break;
4928       }
4929 
4930     word1 T = getbits36_1 (cpu.cu.IWB, 9);
4931 
4932     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
4933     word9 fillT = fill;  // possibly truncated fill pattern
4934 
4935     // play with fill if we need to use it
4936     switch (dstSZ)
4937       {
4938         case 4:
4939           fillT = fill & 017;    // truncate upper 5-bits
4940           break;
4941         case 6:
4942           fillT = fill & 077;    // truncate upper 3-bits
4943           break;
4944       }
4945 
4946     // If N1 > N2, then (N1-N2) leading characters of C(Y-charn1) are not moved
4947     // and the truncation indicator is set ON.
4948 
4949     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
4950     // characters are high-order truncated as they are moved to C(Y-charn2). No
4951     // character conversion takes place.
4952 
4953     // The user of string replication or overlaying is warned that the decimal
4954     // unit addresses the main memory in unaligned (not on modulo 8 boundary)
4955     // units of Y-block8 words and that the overlaid string, C(Y-charn2), is
4956     // not returned to main memory until the unit of Y-block8 words is filled or
4957     // the instruction completes.
4958 
4959     // If T = 1 and the truncation indicator is set ON by execution of the
4960     // instruction, then a truncation (overflow) fault occurs.
4961 
4962     // Attempted execution with the xed instruction causes an illegal procedure
4963     // fault.
4964 
4965     // Attempted repetition with the rpt, rpd, or rpl instructions causes an
4966     // illegal procedure fault.
4967 
4968 #if defined(EIS_PTR3)
4969     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (TA1 == 1) &&
4970                (TA2 == 2); // (6-4 move)
4971 #else
4972     bool ovp = (e -> N1 < e -> N2) && (fill & 0400) && (e -> TA1 == 1) &&
4973                (e -> TA2 == 2); // (6-4 move)
4974 #endif
4975     bool isNeg = false;
4976     //bool bOvp = false;  // true when a negative overpunch character has been
4977                         // found @ N1-1
4978 
4979     PNL (L68_ (if (max (e->N1, e->N2) < 128)
4980       DU_CYCLE_FLEN_128;))
4981 
4982 //
4983 // Test for the case of aligned word move; and do things a word at a time,
4984 // instead of a byte at a time...
4985 
4986 #if defined(EIS_PTR3)
4987     if (TA1 == CTA9 &&  // src and dst are both char 9
4988         TA2 == CTA9 &&
4989 #else
4990     if (e -> TA1 == CTA9 &&  // src and dst are both char 9
4991         e -> TA2 == CTA9 &&
4992 #endif
4993         e -> N1 % 4 == 0 &&  // a whole number of words in the src
4994         e -> N2 == e -> N1 && // the src is the same size as the dest.
4995         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
4996         e -> CN2 == 0)
4997       {
4998         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #1\r\n");
4999         uint limit = e -> N2;
5000         for ( ; cpu.du.CHTALLY < limit; cpu.du.CHTALLY += 4)
5001           {
5002             tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA2));
5003             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
5004             word36 w = EISReadIdx (cpup, & e -> ADDR1, n);
5005             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
5006           }
5007         cleanupOperandDescriptor (cpup, 1);
5008         cleanupOperandDescriptor (cpup, 2);
5009         // truncation fault check does need to be checked for here since
5010         // it is known that N1 == N2
5011         CLR_I_TRUNC;
5012         return;
5013       }
5014 
5015 // Test for the case of aligned word fill; and do things a word at a time,
5016 // instead of a byte at a time...
5017 
5018 #if defined(EIS_PTR3)
5019     if (TA1 == CTA9 && // src and dst are both char 9
5020         TA2 == CTA9 &&
5021 #else
5022     if (e -> TA1 == CTA9 && // src and dst are both char 9
5023         e -> TA2 == CTA9 &&
5024 #endif
5025         e -> N1 == 0 && // the source is entirely fill
5026         e -> N2 % 4 == 0 && // a whole number of words in the dest
5027         e -> CN1 == 0 &&  // and it starts at a word boundary // BITNO?
5028         e -> CN2 == 0)
5029       {
5030         sim_debug (DBG_TRACEEXT, & cpu_dev, "MRL special case #2\r\n");
5031         word36 w = (word36) fill |
5032                   ((word36) fill << 9) |
5033                   ((word36) fill << 18) |
5034                   ((word36) fill << 27);
5035         uint limit = e -> N2;
5036         for ( ; cpu.du.CHTALLY < e -> N2; cpu.du.CHTALLY += 4)
5037           {
5038             tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA2));
5039             uint n = (limit - cpu.du.CHTALLY - 1) / 4;
5040             EISWriteIdx (cpup, & e -> ADDR2, n, w, true);
5041           }
5042         cleanupOperandDescriptor (cpup, 1);
5043         cleanupOperandDescriptor (cpup, 2);
5044         // truncation fault check does need to be checked for here since
5045         // it is known that N1 <= N2
5046         CLR_I_TRUNC;
5047         return;
5048       }
5049 
5050     for ( ; cpu.du.CHTALLY < min (e -> N1, e -> N2); cpu.du.CHTALLY ++)
5051       {
5052         tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA2));
5053         word9 c = EISget469 (cpup, 1, e -> N1 - cpu.du.CHTALLY - 1); // get src char
5054         word9 cout = 0;
5055 
5056 #if defined(EIS_PTR3)
5057         if (TA1 == TA2)
5058 #else
5059         if (e -> TA1 == e -> TA2)
5060 #endif
5061           EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, c);
5062         else
5063           {
5064             // If data types are dissimilar (TA1 ≠ TA2), each character is
5065             // high-order truncated or zero filled, as appropriate, as it is
5066             // moved. No character conversion takes place.
5067             cout = c;
5068             switch (srcSZ)
5069               {
5070                 case 6:
5071                   switch(dstSZ)
5072                     {
5073                       case 4:
5074                         cout = c & 017;    // truncate upper 2-bits
5075                         break;
5076                       case 9:
5077                         break;              // should already be 0-filled
5078                     }
5079                   break;
5080                 case 9:
5081                   switch(dstSZ)
5082                     {
5083                       case 4:
5084                         cout = c & 017;    // truncate upper 5-bits
5085                         break;
5086                       case 6:
5087                         cout = c & 077;    // truncate upper 3-bits
5088                         break;
5089                     }
5090                   break;
5091               }
5092 
5093             // If N1 < N2, C(FILL)0 = 1, TA1 = 1, and TA2 = 2 (6-4 move), then
5094             // C(Y-charn1)N1-1 is examined for a GBCD overpunch sign. If a
5095             // negative overpunch sign is found, then the minus sign character
5096             // is placed in C(Y-charn2)N2-1; otherwise, a plus sign character
5097             // is placed in C(Y-charn2)N2-1.
5098 
5099 // ISOLTS 838 01f, RJ78 p.11-154 - the rightmost digit is examined for overpunch.
5100             if (ovp && (cpu.du.CHTALLY == 0))
5101               {
5102                 // C(FILL)0 = 1 means that there *is* an overpunch char here.
5103                 isGBCDOvp (c, & isNeg);
5104               }
5105             EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, cout);
5106           }
5107       }
5108 
5109     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
5110     //    C(FILL) -> C(Y-charn2)N2-i
5111     // If N1 < N2 and TA2 = 2 (4-bit data) or 1 (6-bit data), then FILL
5112     // characters are high-order truncated as they are moved to C(Y-charn2). No
5113     // character conversion takes place.
5114 
5115     if (e -> N1 < e -> N2)
5116       {
5117         for ( ; cpu.du.CHTALLY < e -> N2 ; cpu.du.CHTALLY ++)
5118           {
5119             tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA2));
5120             // if there's an overpunch then the sign will be the last of the fill
5121             if (ovp && (cpu.du.CHTALLY == e -> N2 - 1))
5122               {
5123                 if (isNeg)
5124                   EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, 015); // 015 is decimal -
5125                 else
5126                   EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, 014); // 014 is decimal +
5127               }
5128             else
5129               {
5130                  EISput469 (cpup, 2, e -> N2 - cpu.du.CHTALLY - 1, fillT);
5131               }
5132           }
5133     }
5134     cleanupOperandDescriptor (cpup, 1);
5135     cleanupOperandDescriptor (cpup, 2);
5136 
5137     if (e -> N1 > e -> N2)
5138       {
5139         SET_I_TRUNC;
5140         if (T && ! TST_I_OMASK)
5141           doFault (FAULT_OFL, fst_zero, "mrl truncation fault");
5142       }
5143     else
5144       CLR_I_TRUNC;
5145   }
5146 
5147 // decimalZero
5148 //
5149 //  Try 1:
5150 //
5151 // This makes MVE 1-28 and all of MVNE work
5152 // Fails MVE 29-37 (6->6)
5153 //    #define decimalZero (e->srcTA != CTA4 ? '0' : 0)
5154 //
5155 // Try 2
5156 // This makes MVE 1-10 and 20-37 and all of MVNE work
5157 // Fails MVE 11-19 (6->9)
5158 //    #define decimalZero (e->srcTA == CTA9 ? '0' : 0)
5159 //
5160 // Try 4
5161 //
5162 #define isDecimalZero(c) ((e->srcTA == CTA9) ? \
5163                           ((c) == '0') : \
5164                           (((c) & 017) == 0))
5165 
5166 /*
5167  * Load the entire sending string number (maximum length 63 characters) into
5168  * the decimal unit input buffer as 4-bit digits (high-order truncating 9-bit
5169  * data). Strip the sign and exponent characters (if any), put them aside into
5170  * special holding registers and decrease the input buffer count accordingly.
5171  */
5172 
5173 static void EISloadInputBufferNumeric (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5174 {
5175     EISstruct * e = & cpu.currentEISinstruction;
5176 
5177     word9 *p = e->inBuffer; // p points to position in inBuffer where 4-bit chars are stored
5178     (void)memset(e->inBuffer, 0, sizeof(e->inBuffer));   // initialize to all 0's
5179 
5180     int pos = (int) e->CN[k-1];
5181 
5182     int TN = (int) e->TN[k-1];
5183     int S = (int) e->S[k-1];  // This is where MVNE gets really nasty.
5184     // I spit on the designers of this instruction set (and of COBOL.) >Ptui!<
5185 
5186     int N = (int) e->N[k-1];  // number of chars in src string
5187 
5188     EISaddr *a = &e->addr[k-1];
5189 
5190     e->sign = 1;
5191     e->exponent = 0;
5192 
5193     for(int n = 0 ; n < N ; n += 1)
5194     {
5195         word9 c = EISget49(cpup, a, &pos, TN);
5196         sim_debug (DBG_TRACEEXT, & cpu_dev, "src: %d: %o\r\n", n, c);
5197 
5198         /*
5199          * Here we need to distinguish between 4 type of numbers.
5200          *
5201          * CSFL - Floating-point, leading sign
5202          * CSLS - Scaled fixed-point, leading sign
5203          * CSTS - Scaled fixed-point, trailing sign
5204          * CSNS - Scaled fixed-point, unsigned
5205          */
5206         switch(S)
5207         {
5208             case CSFL:  // this is the real evil one ....
5209                 // Floating-point:
5210                 // [sign=c0] c1x10(n-3) + c2x10(n-4) + ... + c(n-3) [exponent=8
5211                 // bits]
5212                 //
5213                 // where:
5214                 //
5215                 //  ci is the decimal value of the byte in the ith byte
5216                 //  position.
5217                 //
5218                 //  [sign=ci] indicates that ci is interpreted as a sign byte.
5219                 //
5220                 //  [exponent=8 bits] indicates that the exponent value is
5221                 //  taken from the last 8 bits of the string. If the data is in
5222                 //  9-bit bytes, the exponent is bits 1-8 of c(n-1). If the
5223                 //  data is in 4- bit bytes, the exponent is the binary value
5224                 //  of the concatenation of c(n-2) and c(n-1).
5225 
5226                 if (n == 0) // first had better be a sign ....
5227                 {
5228                     c &= 0xf;   // hack off all but lower 4 bits
5229 
5230                     if (c < 012 || c > 017) //-V560
5231                       doFault (FAULT_IPR,
5232                                fst_ill_dig,
5233                                "loadInputBufferNumeric(1): illegal char in "
5234                                "input");
5235 
5236                     if (c == 015)   // '-'
5237                         e->sign = -1;
5238 
5239                     e->srcTally -= 1;   // 1 less source char
5240                 }
5241                 else if (TN == CTN9 && n == N-1)    // the 9-bit exponent (of which only 8-bits are used)
5242                 {
5243                     e->exponent = (signed char)(c & 0377); // want to do a sign extend
5244                     e->srcTally -= 1;   // 1 less source char
5245                 }
5246                 else if (TN == CTN4 && n == N-2)    // the 1st 4-chars of the 8-bit exponent
5247                 {
5248                     e->exponent = (c & 0xf);// << 4;
5249                     e->exponent <<= 4;
5250                     e->srcTally -= 1;   // 1 less source char
5251                 }
5252                 else if (TN == CTN4 && n == N-1)    // the 2nd 4-chars of the 8-bit exponent
5253                 {
5254                     e->exponent |= (c & 0xf);
5255 
5256                     signed char ce = (signed char) (e->exponent & 0xff);
5257                     e->exponent = ce;
5258 
5259                     e->srcTally -= 1;   // 1 less source char
5260                 }
5261                 else
5262                 {
5263                     c &= 0xf;   // hack off all but lower 4 bits
5264                     if (c > 011)                        // TODO: generate ill proc fault
5265                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(2): illegal char in input");
5266 
5267                     *p++ = c; // store 4-bit char in buffer
5268                 }
5269                 break;
5270 
5271             case CSLS:
5272                 // Only the byte values [0,11]8 are legal in digit positions
5273                 //    and only the byte values [12,17]8 are legal in sign positions.
5274                 //    Detection of an illegal byte value causes an illegal procedure fault
5275                 c &= 0xf;   // hack off all but lower 4 bits
5276 
5277                 if (n == 0) // first had better be a sign ....
5278                 {
5279                     if (c < 012 || c > 017) //-V560     // TODO: generate ill proc fault
5280                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(3): illegal char in input");
5281 
5282                     if (c == 015)  // '-'
5283                         e->sign = -1;
5284                     e->srcTally -= 1;   // 1 less source char
5285                 }
5286                 else
5287                 {
5288                     if (c > 011) //-V560
5289                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(4): illegal char in input");
5290                     *p++ = c; // store 4-bit char in buffer
5291                 }
5292                 break;
5293 
5294             case CSTS:
5295                 c &= 0xf;   // hack off all but lower 4 bits
5296 
5297                 if (n == N-1) // last had better be a sign ....
5298                 {
5299                     if (c < 012 || c > 017) //-V560
5300                          doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(5): illegal char in input");
5301                     if (c == 015)   // '-'
5302                         e->sign = -1;
5303                     e->srcTally -= 1;   // 1 less source char
5304                 }
5305                 else
5306                 {
5307                     if (c > 011)
5308                         doFault(FAULT_IPR, fst_ill_dig, "loadInputBufferNumeric(6): illegal char in input");
5309                     *p++ = c; // store 4-bit char in buffer
5310                 }
5311                 break;
5312 
5313             case CSNS:
5314                 c &= 0xf; // hack off all but lower 4 bits
5315 
5316                 *p++ = c; // the "easy" one
5317                 break;
5318         }
5319     }
5320     if_sim_debug (DBG_TRACEEXT, & cpu_dev)
5321       {
5322         sim_debug (DBG_TRACEEXT, & cpu_dev, "inBuffer:");
5323         for (word9 *q = e->inBuffer; q < p; q ++)
5324           sim_debug (DBG_TRACEEXT, & cpu_dev, " %02o", * q);
5325         sim_debug (DBG_TRACEEXT, & cpu_dev, "\r\n");
5326       }
5327 }
5328 
5329 /*
5330  * Load decimal unit input buffer with sending string characters. Data is read
5331  * from main memory in unaligned units (not modulo 8 boundary) of Y-block8
5332  * words. The number of characters loaded is the minimum of the remaining
5333  * sending string count, the remaining receiving string count, and 64.
5334  */
5335 
5336 static void EISloadInputBufferAlphnumeric (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5337   {
5338     EISstruct * e = & cpu.currentEISinstruction;
5339     // p points to position in inBuffer where 4-bit chars are stored
5340     word9 * p = e -> inBuffer;
5341     (void)memset (e -> inBuffer, 0, sizeof (e -> inBuffer)); // initialize to all 0's
5342 
5343     // minimum of the remaining sending string count, the remaining receiving
5344     // string count, and 64.
5345     // uint N = min3 (e -> N1, e -> N3, 64);
5346     // The above AL39 rule doesn't work with IGN and possibly other MOPs as
5347     // well. Workaround: Load all source, but max 63 characters (as RJ78
5348     // suggests).
5349     uint N = min (e-> N1, 63);
5350 
5351     for (uint n = 0 ; n < N ; n ++)
5352       {
5353         word9 c = EISget469 (cpup, k, n);
5354         * p ++ = c;
5355       }
5356 }
5357 
5358 static void EISwriteOutputBufferToMemory (cpu_state_t * cpup, int k)
     /* [previous][next][first][last][top][bottom][index][help] */
5359   {
5360     EISstruct * e = & cpu.currentEISinstruction;
5361 
5362     for (uint n = 0 ; n < (uint) e -> dstTally; n ++)
5363       {
5364         word9 c49 = e -> outBuffer [n];
5365         EISput469 (cpup, k, n, c49);
5366       }
5367   }
5368 
5369 static void writeToOutputBuffer (cpu_state_t *cpup, word9 **dstAddr, int szSrc, int szDst, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
5370 {
5371     EISstruct * e = & cpu.currentEISinstruction;
5372     // 4. If an edit insertion table entry or MOP insertion character is to be
5373     // stored, ANDed, or ORed into a receiving string of 4- or 6-bit
5374     // characters, high-order truncate the character accordingly.
5375     // 5. (MVNE) If the receiving string is 9-bit characters, high-order fill
5376     // the (4-bit) digits from the input buffer with bits 0-4 of character 8 of
5377     // the edit insertion table. If the receiving string is 6-bit characters,
5378     // high-order fill the digits with "00"b.
5379 
5380     if (e -> mvne)
5381       {
5382         switch (szSrc)   // XXX according to rule 1 of Numeric Edit,
5383                          // input should be 4bits. this needs cleaning
5384           {
5385             case 4:
5386               switch (szDst)
5387                 {
5388                   case 4:
5389                     ** dstAddr = c49 & 0xf;
5390                     break;
5391                   case 6:
5392                     ** dstAddr = c49 & 077;   // high-order fill the digits with "00"b.
5393                     break;
5394                   case 9:
5395                     ** dstAddr = c49 | (e -> editInsertionTable [7] & 0760);
5396                     break;
5397                 }
5398               break;
5399             case 6:
5400               switch (szDst)
5401                 {
5402                   case 4:
5403                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5404                     break;
5405                   case 6:
5406                     ** dstAddr = c49; //-V1037 // XXX is this safe? shouldn't it be & 077 ???
5407                     break;
5408                   case 9:
5409                     ** dstAddr = c49; //-V1037
5410                     break;
5411                 }
5412               break;
5413             // Note: case szSrc == 9 is also used for writing edit table
5414             // entries and MOP insertion characters which shall NOT be
5415             // transformed by rule 5
5416             case 9:
5417               switch(szDst)
5418                 {
5419                   case 4:
5420                     ** dstAddr = c49 & 0xf;    // write only-4-bits
5421                     break;
5422                   case 6:
5423                     ** dstAddr = c49 & 077;   // write only 6-bits
5424                     break;
5425                   case 9:
5426                     ** dstAddr = c49;
5427                     break;
5428                 }
5429               break;
5430           }
5431       }
5432     else // mve
5433       {
5434         switch(szDst)
5435           {
5436             case 4:
5437               ** dstAddr = c49 & 0xf;    // write only-4-bits
5438               break;
5439             case 6:
5440               ** dstAddr = c49 & 077;   // write only 6-bits
5441               break;
5442             case 9:
5443               ** dstAddr = c49;
5444               break;
5445           }
5446       }
5447     e->dstTally -= 1;
5448     *dstAddr += 1;
5449 }
5450 
5451 /*!
5452  * This is the Micro Operation Executor/Interpreter
5453  */
5454 
5455 static char* defaultEditInsertionTable = " *+-$,.0";
5456 
5457 // Edit Flags
5458 //
5459 // The processor provides the following four edit flags for use by the micro
5460 // operations.
5461 //
5462 // bool mopES = false; // End Suppression flag; initially OFF, set ON by a
5463 // micro operation when zero-suppression ends.
5464 //
5465 // bool mopSN = false;
5466 // Sign flag; initially set OFF if the sending string has an alphanumeric
5467 // descriptor or an unsigned numeric descriptor. If the sending string has a
5468 // signed numeric descriptor, the sign is initially read from the sending
5469 // string from the digit position defined by the sign and the decimal type
5470 // field (S); SN is set OFF if positive, ON if negative. If all digits are
5471 // zero, the data is assumed positive and the SN flag is set OFF, even when the
5472 // sign is negative.
5473 //
5474 //bool mopBZ = false; i
5475 // Blank-when-zero flag; initially set OFF and set ON by either the ENF or SES
5476 // micro operation. If, at the completion of a move (L1 exhausted), both the Z
5477 // and BZ flags are ON, the receiving string is filled with character 1 of the
5478 // edit insertion table.
5479 
5480 /*!
5481  * CHT Micro Operation - Change Table
5482  * EXPLANATION: The edit insertion table is replaced by the string of eight
5483  * 9-bit characters immediately following the CHT micro operation.
5484  * FLAGS: None affected
5485  * NOTE: C(IF) is not interpreted for this operation.
5486  */
5487 
5488 static int mopCHT (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5489 {
5490     EISstruct * e = & cpu.currentEISinstruction;
5491     (void)memset(&e->editInsertionTable, 0, sizeof(e->editInsertionTable)); // XXX do we really need this?
5492     for(int i = 0 ; i < 8 ; i += 1)
5493     {
5494         if (e->mopTally == 0)
5495         {
5496             e->_faults |= FAULT_IPR;
5497             break;
5498         }
5499 #if defined(EIS_PTR2)
5500         word9 entry = EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);  // get mop table entries
5501 #else
5502         word9 entry = EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);  // get mop table entries
5503 #endif
5504         e->editInsertionTable[i] = entry & 0777;            // keep to 9-bits
5505         e->mopTally -= 1;
5506     }
5507     return 0;
5508 }
5509 
5510 /*!
5511  * ENF Micro Operation - End Floating Suppression
5512  * EXPLANATION:
5513  *  Bit 0 of IF, IF(0), specifies the nature of the floating suppression. Bit 1
5514  *  of IF, IF(1), specifies if blank when zero option is used.
5515  * For IF(0) = 0 (end floating-sign operation),
5516  * - If ES is OFF and SN is OFF, then edit insertion table entry 3 is moved to
5517  * the receiving field and ES is set ON.
5518  * - If ES is OFF and SN is ON, then edit insertion table entry 4 is moved to
5519  * the receiving field and ES is set ON.
5520  * - If ES is ON, no action is taken.
5521  * For IF(0) = 1 (end floating currency symbol operation),
5522  * - If ES is OFF, then edit insertion table entry 5 is moved to the receiving
5523  * field and ES is set ON.
5524  * - If ES is ON, no action is taken.
5525  * For IF(1) = 1 (blank when zero): the BZ flag is set ON. For IF(1) = 0 (no
5526  * blank when zero): no action is taken.
5527  * FLAGS: (Flags not listed are not affected)
5528  *      ES - If OFF, then set ON
5529  *      BZ - If bit 1 of C(IF) = 1, then set ON; otherwise, unchanged
5530  */
5531 
5532 static int mopENF (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5533 {
5534     EISstruct * e = & cpu.currentEISinstruction;
5535     // For IF(0) = 0 (end floating-sign operation),
5536     if (!(e->mopIF & 010))
5537     {
5538         // 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.
5539         if (!e->mopES && !e->mopSN)
5540         {
5541             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[2]);
5542             e->mopES = true;
5543         }
5544         // 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.
5545         if (!e->mopES && e->mopSN)
5546         {
5547             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[3]);
5548             e->mopES = true;
5549         }
5550         // If ES is ON, no action is taken.
5551     } else { // IF(0) = 1 (end floating currency symbol operation),
5552         if (!e->mopES)
5553         {
5554             // If ES is OFF, then edit insertion table entry 5 is moved to the receiving field and ES is set ON.
5555             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[4]);
5556             e->mopES = true;
5557         }
5558         // If ES is ON, no action is taken.
5559     }
5560 
5561     // 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.
5562     if (e->mopIF & 04)
5563         e->mopBZ = true;
5564 
5565     return 0;
5566 }
5567 
5568 /*!
5569  * IGN Micro Operation - Ignore Source Characters
5570  * EXPLANATION:
5571  * IF specifies the number of characters to be ignored, where IF = 0 specifies
5572  * 16 characters.
5573  * The next IF characters in the source data field are ignored and the sending
5574  * tally is reduced accordingly.
5575  * FLAGS: None affected
5576  */
5577 
5578 static int mopIGN (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5579 {
5580     EISstruct * e = & cpu.currentEISinstruction;
5581 // AL-39 doesn't specify the == 0 test, but NovaScale does;
5582 // also ISOLTS ps830 test-04a seems to rely on it.
5583     if (e->mopIF == 0)
5584         e->mopIF = 16;
5585 
5586     for(int n = 0 ; n < e->mopIF ; n += 1)
5587     {
5588         if (e->dstTally == 0)
5589             break;
5590         if (e->srcTally == 0)
5591         {
5592             // IGN doesn't allow BZ, raise IPR straight away
5593             e->_faults |= FAULT_IPR;
5594             break;
5595         }
5596 
5597         e->srcTally -= 1;
5598         e->in += 1;
5599     }
5600     return 0;
5601 }
5602 
5603 /*!
5604  * INSA Micro Operation - Insert Asterisk on Suppression
5605  * EXPLANATION:
5606  * This MOP is the same as INSB except that if ES is OFF, then edit insertion
5607  * table entry 2 is moved to the receiving field.
5608  * FLAGS: None affected
5609  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5610  */
5611 
5612 static int mopINSA (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5613 {
5614     EISstruct * e = & cpu.currentEISinstruction;
5615     // If C(IF) = 9-15, an IPR fault occurs.
5616     if (e->mopIF >= 9 /* && e->mopIF <= 15 */)
5617     {
5618         e->_faults |= FAULT_IPR;
5619         return 0;
5620     }
5621 
5622 
5623     // If ES is OFF, then edit insertion table entry 1 is moved to the
5624     // receiving field. If IF = 0, then the next 9 bits are also skipped. If IF
5625     // is not 0, the next 9 bits are treated as a MOP.
5626 
5627     if (!e->mopES)
5628       {
5629         writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[1]);
5630 
5631         if (e->mopIF == 0)
5632           {
5633             if (e->mopTally == 0)
5634               {
5635                 e->_faults |= FAULT_IPR;
5636                 return 0;
5637               }
5638 # if defined(EIS_PTR2)
5639             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5640 # else
5641             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5642 # endif
5643             e->mopTally -= 1;
5644           }
5645       }
5646 
5647     // If ES is ON and IF = 0, then the 9-bit character immediately following
5648     // the INSB micro-instruction is moved to the receiving field
5649     else
5650       {
5651         if (e->mopIF == 0)
5652           {
5653             if (e->mopTally == 0)
5654               {
5655                 e->_faults |= FAULT_IPR;
5656                 return 0;
5657               }
5658 # if defined(EIS_PTR2)
5659             word9 c = EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5660 # else
5661             word9 c = EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5662 # endif
5663             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, c);
5664             e->mopTally -= 1;
5665           }
5666     // If ES is ON and IF<>0, then IF specifies which edit insertion table
5667     // entry (1-8) is to be moved to the receiving field.
5668         else
5669           {
5670             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF-1]);
5671           }
5672       }
5673 
5674 
5675 
5676 
5677 
5678 
5679 
5680 
5681 
5682 
5683 
5684 
5685 
5686 
5687 
5688 
5689 
5690 
5691 
5692 
5693 
5694 
5695 
5696 
5697 
5698 
5699 
5700 
5701 
5702 
5703 
5704 
5705 
5706 
5707 
5708 
5709 
5710 
5711 
5712 
5713 
5714 
5715 
5716 
5717 
5718 
5719 
5720 
5721 
5722     return 0;
5723 }
5724 
5725 /*!
5726  * INSB Micro Operation - Insert Blank on Suppression
5727  * EXPLANATION:
5728  * IF specifies which edit insertion table entry is inserted.
5729  * If IF = 0, the 9 bits immediately following the INSB micro operation are
5730  * treated as a 9-bit character (not a MOP) and are moved or skipped according
5731  * to ES.
5732  * - If ES is OFF, then edit insertion table entry 1 is moved to the receiving
5733  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5734  * next 9 bits are treated as a MOP.
5735  * - If ES is ON and IF = 0, then the 9-bit character immediately following the
5736  * INSB micro-instruction is moved to the receiving field.
5737  * - If ES is ON and IF<>0, then IF specifies which edit insertion table entry
5738  * (1-8) is to be moved to the receiving field.
5739  * FLAGS: None affected
5740  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5741  */
5742 
5743 static int mopINSB (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5744 {
5745     EISstruct * e = & cpu.currentEISinstruction;
5746     // If C(IF) = 9-15, an IPR fault occurs.
5747     if (e->mopIF >= 9 /* && e->mopIF <= 15 */)
5748     {
5749         e->_faults |= FAULT_IPR;
5750         return 0;
5751     }
5752 
5753     if (!e->mopES)
5754     {
5755         // If ES is OFF, then edit insertion table entry 1 is moved to the
5756         // receiving field. If IF = 0, then the next 9 bits are also skipped.
5757         // If IF is not 0, the next 9 bits are treated as a MOP.
5758         writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5759 
5760         if (e->mopIF == 0)
5761         {
5762             if (e->mopTally == 0)
5763             {
5764                 e->_faults |= FAULT_IPR;
5765                 return 0;
5766             }
5767 #if defined(EIS_PTR2)
5768             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5769 #else
5770             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5771 #endif
5772             e->mopTally -= 1;
5773         }
5774 
5775     } else {
5776         // ES is ON
5777 
5778         // If C(IF) != 0
5779         if (e->mopIF)
5780         {
5781             // If ES is ON and IF<>0, then IF specifies which edit
5782             // insertion table entry (1-8) is to be moved to the receiving
5783             // field.
5784             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5785         } else {
5786             // If ES is ON and IF = 0, then the 9-bit character immediately
5787             // following the INSB micro-instruction is moved to the
5788             // receiving field.
5789             if (e->mopTally == 0)
5790             {
5791                 e->_faults |= FAULT_IPR;
5792                 return 0;
5793             }
5794 #if defined(EIS_PTR2)
5795             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9));
5796             //EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5797 #else
5798             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, e->mopAddress, &e->mopPos, CTN9));
5799             //EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5800 #endif
5801             e->mopTally -= 1;
5802 
5803         }
5804     }
5805     return 0;
5806 }
5807 
5808 /*!
5809  * INSM Micro Operation - Insert Table Entry One Multiple
5810  * EXPLANATION:
5811  * IF specifies the number of receiving characters affected, where IF = 0
5812  * specifies 16 characters.
5813  * Edit insertion table entry 1 is moved to the next IF (1-16) receiving field
5814  * characters.
5815  * FLAGS: None affected
5816  */
5817 
5818 static int mopINSM (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5819 {
5820     EISstruct * e = & cpu.currentEISinstruction;
5821     if (e->mopIF == 0)
5822         e->mopIF = 16;
5823     for(int n = 0 ; n < e->mopIF ; n += 1)
5824     {
5825         if (e->dstTally == 0)
5826           break;
5827         writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5828     }
5829     return 0;
5830 }
5831 
5832 /*!
5833  * INSN Micro Operation - Insert on Negative
5834  * EXPLANATION:
5835  * IF specifies which edit insertion table entry is inserted. If IF = 0, the 9
5836  * bits immediately following the INSN micro operation are treated as a 9-bit
5837  * character (not a MOP) and are moved or skipped according to SN.
5838  * - If SN is OFF, then edit insertion table entry 1 is moved to the receiving
5839  * field. If IF = 0, then the next 9 bits are also skipped. If IF is not 0, the
5840  * next 9 bits are treated as a MOP.
5841  * - If SN is ON and IF = 0, then the 9-bit character immediately following the
5842  * INSN micro-instruction is moved to the receiving field.
5843  * - If SN is ON and IF <> 0, then IF specifies which edit insertion table
5844  * entry (1-8) is to be moved to the receiving field.
5845  * FLAGS: None affected
5846  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5847  */
5848 
5849 static int mopINSN (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5850 {
5851     EISstruct * e = & cpu.currentEISinstruction;
5852     // If C(IF) = 9-15, an IPR fault occurs.
5853     if (e->mopIF >= 9 /* && e->mopIF <= 15 */)
5854     {
5855         e->_faults |= FAULT_IPR;
5856         return 0;
5857     }
5858 
5859     // If IF = 0, the 9 bits immediately following the INSN micro operation are
5860     // treated as a 9-bit character (not a MOP) and are moved or skipped
5861     // according to SN.
5862 
5863     if (e->mopIF == 0)
5864     {
5865         if (e->mopTally == 0)
5866         {
5867             e->_faults |= FAULT_IPR;
5868             return 0;
5869         }
5870       if (!e->mopSN)
5871         {
5872             //If SN is OFF, then edit insertion table entry 1 is moved to the
5873             //receiving field. If IF = 0, then the next 9 bits are also
5874             //skipped. If IF is not 0, the next 9 bits are treated as a MOP.
5875 #if defined(EIS_PTR2)
5876             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5877 #else
5878             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5879 #endif
5880             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5881             e->mopTally -= 1;
5882         } else {
5883             // If SN is ON and IF = 0, then the 9-bit character immediately
5884             // following the INSN micro-instruction is moved to the receiving
5885             // field.
5886 #if defined(EIS_PTR2)
5887             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9));
5888 #else
5889             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, e->mopAddress, &e->mopPos, CTN9));
5890 #endif
5891 
5892             e->mopTally -= 1;
5893         }
5894     }
5895     else
5896     {
5897         if (e->mopSN)
5898         {
5899             //If SN is ON and IF <> 0, then IF specifies which edit insertion
5900             //table entry (1-8) is to be moved to the receiving field.
5901             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5902         } else {
5903             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5904         }
5905     }
5906     return 0;
5907 }
5908 
5909 /*!
5910  * INSP Micro Operation - Insert on Positive
5911  * EXPLANATION:
5912  * INSP is the same as INSN except that the responses for the SN values are
5913  * reversed.
5914  * FLAGS: None affected
5915  * NOTE: If C(IF) = 9-15, an IPR fault occurs.
5916  */
5917 
5918 static int mopINSP (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5919 {
5920     EISstruct * e = & cpu.currentEISinstruction;
5921     // If C(IF) = 9-15, an IPR fault occurs.
5922     if (e->mopIF >= 9 /* && e->mopIF <= 15 */)
5923     {
5924         e->_faults |= FAULT_IPR;
5925         return 0;
5926     }
5927 
5928     if (e->mopIF == 0)
5929     {
5930         if (e->mopTally == 0)
5931         {
5932             e->_faults |= FAULT_IPR;
5933             return 0;
5934         }
5935         if (e->mopSN)
5936         {
5937 #if defined(EIS_PTR2)
5938             EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5939 #else
5940             EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5941 #endif
5942             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5943             e->mopTally -= 1;
5944         } else {
5945 #if defined(EIS_PTR2)
5946             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9));
5947 #else
5948             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, EISget49(cpup, e->mopAddress, &e->mopPos, CTN9));
5949 #endif
5950             e->mopTally -= 1;
5951         }
5952     }
5953     else
5954     {
5955         if (!e->mopSN)
5956         {
5957             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[e->mopIF - 1]);
5958         } else {
5959             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
5960         }
5961     }
5962 
5963     return 0;
5964 }
5965 
5966 /*!
5967  * LTE Micro Operation - Load Table Entry
5968  * EXPLANATION:
5969  * IF specifies the edit insertion table entry to be replaced.
5970  * The edit insertion table entry specified by IF is replaced by the 9-bit
5971  * character immediately following the LTE microinstruction.
5972  * FLAGS: None affected
5973  * NOTE: If C(IF) = 0 or C(IF) = 9-15, an Illegal Procedure fault occurs.
5974  */
5975 
5976 static int mopLTE (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5977 {
5978     EISstruct * e = & cpu.currentEISinstruction;
5979     if (e->mopIF == 0 || (e->mopIF >= 9 && e->mopIF <= 15))
5980     {
5981         e->_faults |= FAULT_IPR;
5982         return 0;
5983     }
5984     if (e->mopTally == 0)
5985     {
5986         e->_faults |= FAULT_IPR;
5987         return 0;
5988     }
5989 #if defined(EIS_PTR2)
5990     word9 next = EISget49(cpup, &e->ADDR2, &e->mopPos, CTN9);
5991 #else
5992     word9 next = EISget49(cpup, e->mopAddress, &e->mopPos, CTN9);
5993 #endif
5994     e->mopTally -= 1;
5995 
5996     //e->editInsertionTable[e->mopIF - 1] = next;
5997     if (e->mopIF - 1 >= 0 &&
5998         e->mopIF - 1 < sizeof(e->editInsertionTable) / sizeof(e->editInsertionTable[0])) {
5999           e->editInsertionTable[e->mopIF - 1] = next;
6000     } else {
6001         e->_faults |= FAULT_IPR;
6002         sim_warn("mopIF %d OOB in %s!\r\n", e->mopIF, __func__);
6003         return 0;
6004     }
6005     sim_debug (DBG_TRACEEXT, & cpu_dev, "LTE IT[%d]<=%d\r\n", e -> mopIF - 1, next);
6006     return 0;
6007 }
6008 
6009 /*!
6010  * MFLC Micro Operation - Move with Floating Currency Symbol Insertion
6011  * EXPLANATION:
6012  * IF specifies the number of characters of the sending field upon which the
6013  * operation is performed, where IF = 0 specifies 16 characters.
6014  * Starting with the next available sending field character, the next IF
6015  * characters are individually fetched and the following conditional actions
6016  * occur.
6017  * - If ES is OFF and the character is zero, edit insertion table entry 1 is
6018  * moved to the receiving field in place of the character.
6019  * - If ES is OFF and the character is not zero, then edit insertion table
6020  * entry 5 is moved to the receiving field, the character is also moved to the
6021  * receiving field, and ES is set ON.
6022  * - If ES is ON, the character is moved to the receiving field.
6023  * The number of characters placed in the receiving field is data-dependent. If
6024  * the entire sending field is zero, IF characters are placed in the receiving
6025  * field. However, if the sending field contains a nonzero character, IF+1
6026  * characters (the insertion character plus the characters from the sending
6027  * field) are placed in the receiving field.
6028  * An IPR fault occurs when the sending field is exhausted before the receiving
6029  * field is filled. In order to provide space in the receiving field for an
6030  * inserted currency symbol, the receiving field must have a string length one
6031  * character longer than the sending field. When the sending field is all
6032  * zeros, no currency symbol is inserted by the MFLC micro operation and the
6033  * receiving field is not filled when the sending field is exhausted. The user
6034  * should provide an ENF (ENF,12) micro operation after a MFLC micro operation
6035  * that has as its character count the number of characters in the sending
6036  * field. The ENF micro operation is engaged only when the MFLC micro operation
6037  * fails to fill the receiving field. Then it supplies a currency symbol to
6038  * fill the receiving field and blanks out the entire field.
6039  * FLAGS: (Flags not listed are not affected.)
6040  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
6041  * is unchanged.
6042  * NOTE: Since the number of characters moved to the receiving string is
6043  * data-dependent, a possible IPR fault may be avoided by ensuring that the Z
6044  * and BZ flags are ON.
6045  */
6046 
6047 static int mopMFLC (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6048 {
6049     EISstruct * e = & cpu.currentEISinstruction;
6050     if (e->mopIF == 0)
6051         e->mopIF = 16;
6052 
6053     //  Starting with the next available sending field character, the next IF
6054     //  characters are individually fetched and the following conditional
6055     //  actions occur.
6056     sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC IF %d, srcTally %d, dstTally %d\r\n", e->mopIF, e->srcTally, e->dstTally);
6057     for(int n = 0 ; n < e->mopIF ; n += 1)
6058     {
6059         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC n %d, srcTally %d, dstTally %d\r\n", n, e->srcTally, e->dstTally);
6060         if (e->dstTally == 0)
6061             break;
6062         if (e->srcTally == 0)
6063             return -1;
6064         // If ES is OFF and the character is zero, edit insertion table entry 1
6065         // is moved to the receiving field in place of the character.
6066         // If ES is OFF and the character is not zero, then edit insertion
6067         // table entry 5 is moved to the receiving field, the character is also
6068         // moved to the receiving field, and ES is set ON.
6069 
6070         word9 c = *(e->in);
6071         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC c %d (0%o)\r\n", c, c);
6072         if (!e->mopES) { // e->mopES is OFF
6073 
6074             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES off\r\n");
6075             if (isDecimalZero (c)) {
6076                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is zero\r\n");
6077                 // edit insertion table entry 1 is moved to the receiving field
6078                 // in place of the character.
6079                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6080                 e->in += 1;
6081                 e->srcTally -= 1;
6082             } else {
6083                 sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC is not zero\r\n");
6084                 // then edit insertion table entry 5 is moved to the receiving
6085                 // field, the character is also moved to the receiving field,
6086                 // and ES is set ON.
6087                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[4]);
6088 
6089                 writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6090                 e->mopZ = false; // iszero() tested above.
6091                 e->in += 1;
6092                 e->srcTally -= 1;
6093 
6094                 e->mopES = true;
6095             }
6096         } else {
6097             sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLC ES on\r\n");
6098             // If ES is ON, the character is moved to the receiving field.
6099             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6100 
6101             if (! isDecimalZero (c))
6102                 e->mopZ = false;
6103             e->in += 1;
6104             e->srcTally -= 1;
6105         }
6106     }
6107 
6108     return 0;
6109 }
6110 
6111 /*!
6112  * MFLS Micro Operation - Move with Floating Sign Insertion
6113  * EXPLANATION:
6114  * IF specifies the number of characters of the sending field upon which the
6115  * operation is performed, where IF = 0 specifies 16 characters.
6116  * Starting with the next available sending field character, the next IF
6117  * characters are individually fetched and the following conditional actions
6118  * occur.
6119  * - If ES is OFF and the character is zero, edit insertion table entry 1 is
6120  * moved to the receiving field in place of the character.
6121  * - If ES is OFF, the character is not zero, and SN is OFF; then edit
6122  * insertion table entry 3 is moved to the receiving field; the character is
6123  * also moved to the receiving field, and ES is set ON.
6124  * - If ES is OFF, the character is nonzero, and SN is ON; edit insertion table
6125  * entry 4 is moved to the receiving field; the character is also moved to the
6126  * receiving field, and ES is set ON.
6127  * - If ES is ON, the character is moved to the receiving field.
6128  * The number of characters placed in the receiving field is data-dependent. If
6129  * the entire sending field is zero, IF characters are placed in the receiving
6130  * field. However, if the sending field contains a nonzero character, IF+1
6131  * characters (the insertion character plus the characters from the sending
6132  * field) are placed in the receiving field.
6133  * An IPR fault occurs when the sending field is exhausted before the receiving
6134  * field is filled. In order to provide space in the receiving field for an
6135  * inserted sign, the receiving field must have a string length one character
6136  * longer than the sending field. When the sending field is all zeros, no sign
6137  * is inserted by the MFLS micro operation and the receiving field is not
6138  * filled when the sending field is exhausted. The user should provide an ENF
6139  * (ENF,4) micro operation after a MFLS micro operation that has as its
6140  * character count the number of characters in the sending field. The ENF micro
6141  * operation is engaged only when the MFLS micro operation fails to fill the
6142  * receiving field; then, it supplies a sign character to fill the receiving
6143  * field and blanks out the entire field.
6144  *
6145  * FLAGS: (Flags not listed are not affected.)
6146  *     ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6147  *     it is unchanged.
6148  * NOTE: Since the number of characters moved to the receiving string is
6149  * data-dependent, a possible Illegal Procedure fault may be avoided by
6150  * ensuring that the Z and BZ flags are ON.
6151  */
6152 
6153 static int mopMFLS (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6154 {
6155     EISstruct * e = & cpu.currentEISinstruction;
6156     if (e->mopIF == 0)
6157         e->mopIF = 16;
6158 
6159     for(int n = 0 ; n < e->mopIF; n += 1)
6160     {
6161         if (e->dstTally == 0)
6162             break;
6163         if (e->srcTally == 0)
6164             return -1;
6165 
6166         word9 c = *(e->in);
6167         sim_debug (DBG_TRACEEXT, & cpu_dev, "MFLS n %d c %o\r\n", n, c);
6168         if (!e->mopES) { // e->mopES is OFF
6169             if (isDecimalZero (c))
6170             {
6171                 // edit insertion table entry 1 is moved to the receiving field
6172                 // in place of the character.
6173                 sim_debug (DBG_TRACEEXT, & cpu_dev,
6174                            "ES is off, c is zero; edit insertion table entry 1"
6175                            " is moved to the receiving field in place of the character.\r\n");
6176                 writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6177                 e->in += 1;
6178                 e->srcTally -= 1;
6179             } else {
6180                 // c is non-zero
6181                 if (!e->mopSN)
6182                 {
6183                     // then edit insertion table entry 3 is moved to the
6184                     // receiving field; the character is also moved to the
6185                     // receiving field, and ES is set ON.
6186                     sim_debug (DBG_TRACEEXT, & cpu_dev,
6187                                "ES is off, c is non-zero, SN is off; edit insertion table entry 3"
6188                                " is moved to the receiving field; the character is also moved to"
6189                                " the receiving field, and ES is set ON.\r\n");
6190                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[2]);
6191 
6192                     e->in += 1;
6193                     e->srcTally -= 1;
6194                     e->mopZ = false; // iszero tested above
6195 
6196 
6197 
6198 
6199 
6200 
6201 
6202 
6203                     writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6204 
6205                     e->mopES = true;
6206                 } else {
6207                     //  SN is ON; edit insertion table entry 4 is moved to the
6208                     //  receiving field; the character is also moved to the
6209                     //  receiving field, and ES is set ON.
6210                     sim_debug (DBG_TRACEEXT, & cpu_dev,
6211                                "ES is off, c is non-zero, SN is OFF; edit insertion table entry 4"
6212                                " is moved to the receiving field; the character is also moved to"
6213                                " the receiving field, and ES is set ON.\r\n");
6214                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[3]);
6215 
6216                     e->in += 1;
6217                     e->srcTally -= 1;
6218                     e->mopZ = false; // iszero tested above
6219 
6220                     writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6221 
6222                     e->mopES = true;
6223                 }
6224             }
6225         } else {
6226             // If ES is ON, the character is moved to the receiving field.
6227             sim_debug (DBG_TRACEEXT, & cpu_dev, "ES is ON, the character is moved to the receiving field.\r\n");
6228             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6229 
6230             if (! isDecimalZero (c))
6231                 e->mopZ = false;
6232             e->in += 1;
6233             e->srcTally -= 1;
6234         }
6235     }
6236 
6237     // NOTE: Since the number of characters moved to the receiving string is
6238     // data-dependent, a possible Illegal Procedure fault may be avoided by
6239     // ensuring that the Z and BZ flags are ON.
6240 
6241     return 0;
6242 }
6243 
6244 /*!
6245  * MORS Micro Operation - Move and OR Sign
6246  * EXPLANATION:
6247  * IF specifies the number of characters of the sending field upon which the
6248  * operation is performed, where IF = 0 specifies 16 characters.
6249  * Starting with the next available sending field character, the next IF
6250  * characters are individually fetched and the following conditional actions
6251  * occur.
6252  * - If SN is OFF, the next IF characters in the source data field are moved to
6253  * the receiving data field and, during the move, edit insertion table entry 3
6254  * is ORed to each character.
6255  * - If SN is ON, the next IF characters in the source data field are moved to
6256  * the receiving data field and, during the move, edit insertion table entry 4
6257  * is ORed to each character.
6258  * MORS can be used to generate a negative overpunch for a receiving field to
6259  * be used later as a sending field.
6260  * FLAGS: None affected
6261  */
6262 
6263 static int mopMORS (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6264 {
6265     EISstruct * e = & cpu.currentEISinstruction;
6266     if (e->mopIF == 0)
6267         e->mopIF = 16;
6268 
6269     sim_debug (DBG_TRACEEXT, & cpu_dev, "MORS mopIF %d src %d dst %d\r\n", e->mopIF, e->srcTally, e->dstTally);
6270     for(int n = 0 ; n < e->mopIF ; n += 1)
6271     {
6272 // The micro operation sequence is terminated normally when the receiving
6273 // string length becomes exhausted. The micro operation sequence is terminated
6274 // abnormally (with an illegal procedure fault) if a move from an exhausted
6275 // sending string or the use of an exhausted MOP string is attempted.
6276 
6277         if (e->dstTally == 0)
6278             break;
6279         if (e->srcTally == 0)
6280             return -1;
6281 
6282         // XXX this is probably wrong regarding the ORing, but it's a start ....
6283         word9 c = (*e->in | (!e->mopSN ? e->editInsertionTable[2] : e->editInsertionTable[3]));
6284         if (! isDecimalZero (*e->in))
6285             e->mopZ = false;
6286         e->in += 1;
6287         e->srcTally -= 1;
6288 
6289         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6290     }
6291 
6292     return 0;
6293 }
6294 
6295 /*!
6296  * MVC Micro Operation - Move Source Characters
6297  * EXPLANATION:
6298  * IF specifies the number of characters to be moved, where IF = 0 specifies 16
6299  * characters.
6300  * The next IF characters in the source data field are moved to the receiving
6301  * data field.
6302  * FLAGS: None affected
6303  */
6304 
6305 static int mopMVC (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6306 {
6307     EISstruct * e = & cpu.currentEISinstruction;
6308     if (e->mopIF == 0)
6309         e->mopIF = 16;
6310 
6311     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC mopIF %d\r\n", e->mopIF);
6312 
6313     for(int n = 0 ; n < e->mopIF ; n += 1)
6314     {
6315         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC n %d srcTally %d dstTally %d\r\n", n, e->srcTally, e->dstTally);
6316 // GD's test_float shows that data exhaustion is not a fault.
6317 //#if 0
6318         if (e->dstTally == 0)
6319             break;
6320         if (e->srcTally == 0)
6321             return -1;
6322 
6323         sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC write to output buffer %o\r\n", *e->in);
6324         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, *e->in);
6325         if (! isDecimalZero (*e->in))
6326             e->mopZ = false;
6327         e->in += 1;
6328 
6329         e->srcTally -= 1;
6330     }
6331 
6332     sim_debug (DBG_TRACEEXT, & cpu_dev, "MVC done\r\n");
6333     return 0;
6334 }
6335 
6336 /*!
6337  * MSES Micro Operation - Move and Set Sign
6338  * EXPLANATION:
6339  * IF specifies the number of characters of the sending field upon which the
6340  * operation is performed, where IF = 0 specifies 16 characters. For MVE,
6341  * starting with the next available sending field character, the next IF
6342  * characters are individually fetched and the following conditional actions
6343  * occur.
6344  * Starting with the first character during the move, a comparative AND is made
6345  * first with edit insertion table entry 3. If the result is nonzero, the first
6346  * character and the rest of the characters are moved without further
6347  * comparative ANDs. If the result is zero, a comparative AND is made between
6348  * the character being moved and edit insertion table entry 4 If that result is
6349  * nonzero, the SN indicator is set ON (indicating negative) and the first
6350  * character and the rest of the characters are moved without further
6351  * comparative ANDs. If the result is zero, the second character is treated
6352  * like the first. This process continues until one of the comparative AND
6353  * results is nonzero or until all characters are moved.
6354  * For MVNE instruction, the sign (SN) flag is already set and IF characters
6355  * are moved to the destination field (MSES is equivalent to the MVC
6356  * instruction).
6357  * FLAGS: (Flags not listed are not affected.)
6358  * SN If edit insertion table entry 4 is found in C(Y-1), then ON; otherwise,
6359  * it is unchanged.
6360  */
6361 
6362 static int mopMSES (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6363 {
6364     EISstruct * e = & cpu.currentEISinstruction;
6365     if (e->mvne == true)
6366         return mopMVC (cpup);   // XXX I think!
6367 
6368     if (e->mopIF == 0)
6369         e->mopIF = 16;
6370 
6371     int overpunch = false;
6372 
6373     for(int n = 0 ; n < e->mopIF ; n += 1)
6374     {
6375         if (e->dstTally == 0)
6376             break;
6377         if (e->srcTally == 0)
6378             return -1;
6379 
6380         //Starting with the first character during the move, a comparative AND
6381         //is made first with edit insertion table entry 3. If the result is
6382         //nonzero, the first character and the rest of the characters are moved
6383         //without further comparative ANDs. If the result is zero, a
6384         //comparative AND is made between the character being moved and edit
6385         //insertion table entry 4 If that result is nonzero, the SN indicator
6386         //is set ON (indicating negative) and the first character and the rest
6387         //of the characters are moved without further comparative ANDs. If the
6388         //result is zero, the second character is treated like the first. This
6389         //process continues until one of the comparative AND results is nonzero
6390         //or until all characters are moved.
6391 
6392         word9 c = *(e->in);
6393 
6394         if (!overpunch) {
6395             if (c & e->editInsertionTable[2])  // XXX only lower 4-bits are considered
6396                 overpunch = true;
6397 
6398             else if (c & e->editInsertionTable[3])  // XXX only lower 4-bits are considered
6399             {
6400                 e->mopSN = true;
6401                 overpunch = true;
6402             }
6403         }
6404 
6405         e->in += 1;
6406         e->srcTally -= 1;   // XXX is this correct? No chars have been consumed, but ......
6407         if (! isDecimalZero (c))
6408             e->mopZ = false;
6409         writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6410     }
6411 
6412     return 0;
6413 }
6414 
6415 /*!
6416  * MVZA Micro Operation - Move with Zero Suppression and Asterisk Replacement
6417  * EXPLANATION:
6418  * MVZA is the same as MVZB except that if ES is OFF and the character is zero,
6419  * then edit insertion table entry 2 is moved to the receiving field.
6420  * FLAGS: (Flags not listed are not affected.)
6421  * ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise, it
6422  * is unchanged.
6423  */
6424 
6425 static int mopMVZA (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6426 {
6427     EISstruct * e = & cpu.currentEISinstruction;
6428     if (e->mopIF == 0)
6429         e->mopIF = 16;
6430 
6431     for(int n = 0 ; n < e->mopIF ; n += 1)
6432     {
6433         if (e->dstTally == 0)
6434             break;
6435         if (e->srcTally == 0)
6436             return -1;
6437 
6438         word9 c = *e->in;
6439         e->in += 1;
6440         e->srcTally -= 1;
6441 
6442         //if (!e->mopES && c == 0)
6443         // XXX See srcTA comment in MVNE
6444         if (!e->mopES && isDecimalZero (c))
6445         {
6446             //If ES is OFF and the character is zero, then edit insertion table
6447             //entry 2 is moved to the receiving field in place of the
6448             //character.
6449             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[1]);
6450         //} else if (!e->mopES && c != 0)
6451         // XXX See srcTA comment in MVNE
6452         }
6453         else if ((! e->mopES) && (! isDecimalZero (c)))
6454         {
6455             //If ES is OFF and the character is not zero, then the character is
6456             //moved to the receiving field and ES is set ON.
6457             e->mopZ = false;
6458             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6459 
6460             e->mopES = true;
6461         } else if (e->mopES)
6462         {
6463             //If ES is ON, the character is moved to the receiving field.
6464             if (! isDecimalZero (c))
6465                 e->mopZ = false;
6466             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6467         }
6468     }
6469 
6470     return 0;
6471 }
6472 
6473 /*!
6474  * MVZB Micro Operation - Move with Zero Suppression and Blank Replacement
6475  * EXPLANATION:
6476  * IF specifies the number of characters of the sending field upon which the
6477  * operation is performed, where IF = 0 specifies 16 characters.
6478  * Starting with the next available sending field character, the next IF
6479  * characters are individually fetched and the following conditional actions
6480  * occur.
6481  * - If ES is OFF and the character is zero, then edit insertion table entry 1
6482  * is moved to the receiving field in place of the character.
6483  * - If ES is OFF and the character is not zero, then the character is moved to
6484  * the receiving field and ES is set ON.
6485  * - If ES is ON, the character is moved to the receiving field.
6486  * FLAGS: (Flags not listed are not affected.)
6487  *   ES If OFF and any of C(Y) is less than decimal zero, then ON; otherwise,
6488  *   it is unchanged.
6489  */
6490 
6491 static int mopMVZB (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6492 {
6493     EISstruct * e = & cpu.currentEISinstruction;
6494     if (e->mopIF == 0)
6495         e->mopIF = 16;
6496 
6497     for(int n = 0 ; n < e->mopIF ; n += 1)
6498     {
6499         if (e->dstTally == 0)
6500             break;
6501         if (e->srcTally == 0)
6502           return -1;
6503 
6504         word9 c = *e->in;
6505         e->srcTally -= 1;
6506         e->in += 1;
6507 
6508         //if (!e->mopES && c == 0)
6509         // XXX See srcTA comment in MVNE
6510         if ((!e->mopES) && isDecimalZero (c))
6511         {
6512             //If ES is OFF and the character is zero, then edit insertion table
6513             //entry 1 is moved to the receiving field in place of the
6514             //character.
6515             writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6516         //} else if (!e->mopES && c != 0)
6517         // XXX See srcTA comment in MVNE
6518         }
6519         if ((! e->mopES) && (! isDecimalZero (c)))
6520         {
6521             //If ES is OFF and the character is not zero, then the character is
6522             //moved to the receiving field and ES is set ON.
6523             e->mopZ = false;
6524             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6525 
6526             e->mopES = true;
6527         } else if (e->mopES)
6528         {
6529             //If ES is ON, the character is moved to the receiving field.
6530             if (! isDecimalZero (c))
6531                 e->mopZ = false;
6532             writeToOutputBuffer(cpup, &e->out, e->srcSZ, e->dstSZ, c);
6533         }
6534     }
6535 
6536     return 0;
6537 }
6538 
6539 /*!
6540  * SES Micro Operation - Set End Suppression
6541  * EXPLANATION:
6542  * Bit 0 of IF (IF(0)) specifies the setting of the ES switch.
6543  * If IF(0) = 0, the ES flag is set OFF. If IF(0) = 1, the ES flag is set ON.
6544  * Bit 1 of IF (IF(1)) specifies the setting of the blank-when-zero option.
6545  * If IF(1) = 0, no action is taken.
6546  * If IF(1) = 1, the BZ flag is set ON.
6547  * FLAGS: (Flags not listed are not affected.)
6548  * ES set by this micro operation
6549  * BZ If bit 1 of C(IF) = 1, then ON; otherwise, it is unchanged.
6550  */
6551 
6552 static int mopSES (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6553 {
6554     EISstruct * e = & cpu.currentEISinstruction;
6555     if (e->mopIF & 010)
6556         e->mopES = true;
6557     else
6558         e->mopES = false;
6559 
6560     if (e->mopIF & 04)
6561         e->mopBZ = true;
6562 
6563     return 0;
6564 }
6565 
6566 // Table 4-9. Micro Operation Code Assignment Map
6567 #if !defined(QUIET_UNUSED)
6568 static char * mopCodes [040] =
6569   {
6570     //            0       1       2       3       4       5       6       7
6571     /* 00 */      0, "insm",  "enf",  "ses", "mvzb", "mvza", "mfls", "mflc",
6572     /* 10 */ "insb", "insa", "insn", "insp",  "ign",  "mvc", "mses", "mors",
6573     /* 20 */  "lte",  "cht",      0,      0,      0,      0,      0,      0,
6574     /* 30 */      0,      0,      0,      0,      0,      0,      0,      0
6575   };
6576 #endif
6577 
6578 static MOP_struct mopTab[040] = {
6579     {NULL, 0},
6580     {"insm", mopINSM },
6581     {"enf",  mopENF  },
6582     {"ses",  mopSES  },
6583     {"mvzb", mopMVZB },
6584     {"mvza", mopMVZA },
6585     {"mfls", mopMFLS },
6586     {"mflc", mopMFLC },
6587     {"insb", mopINSB },
6588     {"insa", mopINSA },
6589     {"insn", mopINSN },
6590     {"insp", mopINSP },
6591     {"ign",  mopIGN  },
6592     {"mvc",  mopMVC  },
6593     {"mses", mopMSES },
6594     {"mors", mopMORS },
6595     {"lte",  mopLTE  },
6596     {"cht",  mopCHT  },
6597     {NULL, 0},
6598     {NULL, 0},
6599     {NULL, 0},
6600     {NULL, 0},
6601     {NULL, 0},
6602     {NULL, 0},
6603     {NULL, 0},
6604     {NULL, 0},
6605     {NULL, 0},
6606     {NULL, 0},
6607     {NULL, 0},
6608     {NULL, 0},
6609     {NULL, 0},
6610     {NULL, 0}
6611 };
6612 
6613 /*!
6614  * fetch MOP from e->mopAddr/e->mopPos ...
6615  */
6616 
6617 static MOP_struct* EISgetMop (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6618 {
6619     EISstruct * e = & cpu.currentEISinstruction;
6620     //static word18 lastAddress;  // try to keep memory access' down
6621     //static word36 data;
6622 
6623     if (e == NULL) //-V547
6624     //{
6625     //    p->lastAddress = -1;
6626     //    p->data = 0;
6627         return NULL;
6628     //}
6629 
6630 #if defined(EIS_PTR2)
6631     EISaddr *p = &e->ADDR2;
6632 #else
6633     EISaddr *p = e->mopAddress;
6634 #endif
6635 
6636     //if (p->lastAddress != p->address)                 // read from memory if different address
6637         p->data = EISRead(cpup, p);   // read data word from memory
6638 
6639     if (e->mopPos > 3)   // overflows to next word?
6640     {   // yep....
6641         e->mopPos = 0;   // reset to 1st byte
6642 #if defined(EIS_PTR2)
6643         cpu.du.Dk_PTR_W[KMOP] = (cpu.du.Dk_PTR_W[KMOP] + 1) & AMASK;     // bump source to next address
6644         p->data = EISRead(cpup, &e->ADDR2);   // read it from memory
6645 #else
6646         PNL (cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK);     // bump source to next address
6647         PNL (p->data = EISRead(cpup, e->mopAddress));   // read it from memory
6648 # if defined(EIS_PTR)
6649         cpu.du.Dk_PTR_W[1] = (cpu.du.Dk_PTR_W[1] + 1) & AMASK;     // bump source to next address
6650         p->data = EISRead(cpup, e->mopAddress);   // read it from memory
6651 # else
6652         e->mopAddress->address = (e->mopAddress->address + 1) & AMASK;     // bump source to next address
6653         p->data = EISRead(cpup, e->mopAddress);   // read it from memory
6654 # endif
6655 #endif
6656     }
6657 
6658     word9 mop9  = (word9) get9 (p -> data, e -> mopPos); // get 9-bit mop
6659     word5 mop   = (mop9 >> 4) & 037;
6660     e->mopIF = mop9 & 0xf;
6661 
6662     MOP_struct *m = &mopTab[mop];
6663     sim_debug (DBG_TRACEEXT, & cpu_dev, "MOP %s(%o) %o\r\n", m -> mopName, mop, e->mopIF);
6664     e->m = m;
6665     if (e->m == NULL || e->m->f == NULL) //-V560
6666     {
6667         sim_debug (DBG_TRACEEXT, & cpu_dev, "getMop(e->m == NULL || e->m->f == NULL): mop:%d IF:%d\r\n", mop, e->mopIF);
6668         return NULL;
6669     }
6670 
6671     e->mopPos += 1;
6672     e->mopTally -= 1;
6673 
6674     //p->lastAddress = p->address;
6675 
6676     return m;
6677 }
6678 
6679 #if defined(EIS_PTR2)
6680 static void mopExecutor (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6681 #else
6682 static void mopExecutor (cpu_state_t * cpup, int kMop)
6683 #endif
6684   {
6685     EISstruct * e = & cpu.currentEISinstruction;
6686     PNL (L68_ (DU_CYCLE_FEXOP;))
6687 #if defined(EIS_PTR2)
6688     e->mopTally = (int) e->N[KMOP];        // number of micro-ops
6689     e->mopPos   = (int) e->CN[KMOP];        // starting at char pos CN
6690 #else
6691     e->mopAddress = &e->addr[kMop-1];
6692     e->mopTally = (int) e->N[kMop-1];        // number of micro-ops
6693     e->mopPos   = (int) e->CN[kMop-1];        // starting at char pos CN
6694 #endif
6695 
6696     word9 *p9 = e->editInsertionTable; // re-initialize edit insertion table
6697     char *q = defaultEditInsertionTable;
6698     while((*p9++ = (word9) (*q++)))
6699         ;
6700 
6701     e->in = e->inBuffer;    // reset input buffer pointer
6702     e->out = e->outBuffer;  // reset output buffer pointer
6703 
6704     e->_faults = 0; // No faults (yet!)
6705 
6706     // execute dstTally micro operations
6707     // The micro operation sequence is terminated normally when the receiving
6708     // string length becomes exhausted. The micro operation sequence is
6709     // terminated abnormally (with an illegal procedure fault) if a move from
6710     // an exhausted sending string or the use of an exhausted MOP string is
6711     // attempted.
6712 
6713     while (e->dstTally)
6714     {
6715         sim_debug (DBG_TRACEEXT, & cpu_dev,
6716                    "mopExecutor srcTally %d dstTally %d mopTally %d\r\n",
6717                    e->srcTally, e->dstTally, e->mopTally);
6718         MOP_struct *m = EISgetMop(cpup);
6719         if (! m)
6720           {
6721             sim_debug (DBG_TRACEEXT, & cpu_dev, "mopExecutor EISgetMop forced break\r\n");
6722             e->_faults |= FAULT_IPR;   // XXX ill proc fault
6723             break;
6724           }
6725         int mres = m->f(cpup);    // execute mop
6726 
6727         // PVS-Studio claims: Expression 'e->_faults & FAULT_IPR' is always false.
6728         if (e->_faults & FAULT_IPR) //-V547
6729             break; // hard IPR raised by a MOP
6730 
6731         // RJ78 specifies "if at completion of a move (L1 exhausted)", AL39
6732         // doesn't define "completion of a move".
6733         // But ISOLTS-845 asserts a case where L1 is NOT exhausted. Therefore I
6734         // assume "L2 exhausted" or "L1 or L2 exhausted" is the correct
6735         // interpretation. Both these options pass ISOLTS-845.
6736         // "L3 exhausted" is also an option but unlikely since that would fire
6737         // the BZ check even upon normal termination.
6738         // XXX DH03 7-295 suggests that there might be a difference between MVE
6739         // and MVNE. It might well be that DPS88/9000 behaves differently than
6740         // DPS8.
6741 
6742 
6743 
6744 
6745 
6746 
6747 
6748         // immediate (L1 or L2) srcTally test
6749         // perhaps more adherent to documentation
6750         if (e->mopTally == 0 || mres)
6751           {
6752             sim_debug (DBG_TRACEEXT, & cpu_dev,
6753                        "mopExecutor N1 or N2 exhausted\r\n");
6754 
6755             if (e->mopZ && e->mopBZ)
6756               {
6757                 e->out = e->outBuffer; //-V1048  // reset output buffer pointer
6758                 e->dstTally = (int) e->N3;       // number of chars in dst (max 63)
6759                 while (e->dstTally)
6760                   {
6761                     writeToOutputBuffer(cpup, &e->out, 9, e->dstSZ, e->editInsertionTable[0]);
6762                   }
6763               }
6764             else if (mres || e->dstTally) //-V560
6765               { // N1 or N2 exhausted and BZ wasn't enabled
6766                 e->_faults |= FAULT_IPR;
6767               } // otherwise normal termination
6768             break;
6769           }
6770     }
6771 
6772     sim_debug (DBG_TRACEEXT, & cpu_dev, "mop faults %o src %d dst %d mop %d\r\n",
6773                e->_faults, e->srcTally, e->dstTally, e->mopTally);
6774 
6775 //"The micro-operation sequence is terminated normally when the receiving string
6776 // length is exhausted. The micro-operation sequence is terminated abnormally (with
6777 // an IPR fault) if an attempt is made to move from an exhausted sending string or to
6778 // use an exhausted MOP string.
6779 
6780 // ISOLTS 845 is happy with no check at all
6781 
6782 
6783 
6784 
6785 
6786 
6787 
6788 
6789 
6790 
6791 
6792 
6793 
6794 
6795 
6796 
6797 
6798 
6799 
6800 
6801 
6802 
6803 
6804 
6805 
6806 
6807 
6808 
6809 
6810 
6811 
6812 
6813 
6814 
6815 
6816 
6817 
6818 
6819 
6820 
6821     if (e -> _faults)
6822       doFault (FAULT_IPR, fst_ill_proc, "mopExecutor");
6823 }
6824 
6825 void mve (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6826   {
6827     EISstruct * e = & cpu.currentEISinstruction;
6828 
6829     sim_debug(DBG_TRACEEXT, & cpu_dev, "mve\r\n");
6830 
6831     fault_ipr_subtype_ mod_fault = 0;
6832 
6833 #if !defined(EIS_SETUP)
6834     setupOperandDescriptor(cpup, 1, &mod_fault);
6835     setupOperandDescriptor(cpup, 2, &mod_fault);
6836     setupOperandDescriptor(cpup, 3, &mod_fault);
6837 #endif
6838 
6839     parseAlphanumericOperandDescriptor(cpup, 1, 1, false, &mod_fault);
6840     parseAlphanumericOperandDescriptor(cpup, 2, 2, false, &mod_fault);
6841     parseAlphanumericOperandDescriptor(cpup, 3, 3, false, &mod_fault);
6842 
6843     L68_ (
6844       // L68 raises it immediately
6845       if (mod_fault)
6846         {
6847           doFault (FAULT_IPR,
6848                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6849                    "Illegal modifier");
6850         }
6851     )
6852 
6853     // Bits 0, 1, 9, and 10 MBZ
6854     // According to RJ78, bit 9 is T, but is not mentioned in the text.
6855     if (IWB_IRODD & 0600600000000)
6856       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mve: 0, 1, 9, 10 MBZ");
6857 
6858     // Bit 23 of OP1 MBZ
6859     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
6860       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op1 23 MBZ");
6861 
6862 
6863 
6864 
6865 
6866 
6867     // only bit 23 according to RH03. this was fixed in DPS9000
6868     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000010000)
6869       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op2 23 MBZ");
6870 
6871     // Bit 23 of OP3 MBZ
6872     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
6873       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mve op3 23 MBZ");
6874 
6875     DPS8M_ (
6876       // DPS8M raises it delayed
6877       if (mod_fault)
6878         {
6879           doFault (FAULT_IPR,
6880                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6881                    "Illegal modifier");
6882         }
6883     )
6884 
6885     // initialize mop flags. Probably best done elsewhere.
6886     e->mopES = false; // End Suppression flag
6887     e->mopSN = false; // Sign flag
6888     e->mopBZ = false; // Blank-when-zero flag
6889     e->mopZ  = true;  // Zero flag
6890 
6891     e->srcTally = (int) e->N1;  // number of chars in src (max 63)
6892     e->dstTally = (int) e->N3;  // number of chars in dst (max 63)
6893 
6894 #if defined(EIS_PTR3)
6895     e->srcTA = (int) TA1;    // type of chars in src
6896 #else
6897     e->srcTA = (int) e->TA1;    // type of chars in src
6898 #endif
6899 
6900     switch (e -> srcTA)
6901       {
6902         case CTA4:
6903           e -> srcSZ = 4;
6904           break;
6905         case CTA6:
6906           e -> srcSZ = 6;
6907           break;
6908         case CTA9:
6909           e -> srcSZ = 9;
6910           break;
6911       }
6912 
6913 #if defined(EIS_PTR3)
6914     uint dstTA = TA3;    // type of chars in dst
6915 #else
6916     uint dstTA = e -> TA3;    // type of chars in dst
6917 #endif
6918 
6919     switch (dstTA)
6920       {
6921         case CTA4:
6922           e -> dstSZ = 4;
6923           break;
6924         case CTA6:
6925           e -> dstSZ = 6;
6926           break;
6927         case CTA9:
6928           e -> dstSZ = 9;
6929           break;
6930       }
6931 
6932     // 1. load sending string into inputBuffer
6933     EISloadInputBufferAlphnumeric (cpup, 1);   // according to MF1
6934 
6935     // 2. Execute micro operation string, starting with first (4-bit) digit.
6936     e -> mvne = false;
6937 
6938 #if defined(EIS_PTR2)
6939     mopExecutor (cpup);
6940 #else
6941     mopExecutor (cpup, 2);
6942 #endif
6943 
6944     e -> dstTally = (int) e -> N3;  // restore dstTally for output
6945 
6946     EISwriteOutputBufferToMemory (cpup, 3);
6947     cleanupOperandDescriptor (cpup, 1);
6948     cleanupOperandDescriptor (cpup, 2);
6949     cleanupOperandDescriptor (cpup, 3);
6950   }
6951 
6952 void mvne (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
6953   {
6954     EISstruct * e = & cpu.currentEISinstruction;
6955 
6956     fault_ipr_subtype_ mod_fault = 0;
6957 
6958 #if !defined(EIS_SETUP)
6959     setupOperandDescriptor (cpup, 1, &mod_fault);
6960     setupOperandDescriptor (cpup, 2, &mod_fault);
6961     setupOperandDescriptor (cpup, 3, &mod_fault);
6962 #endif
6963 
6964     parseNumericOperandDescriptor (cpup, 1, &mod_fault);
6965     parseAlphanumericOperandDescriptor (cpup, 2, 2, false, &mod_fault);
6966     parseAlphanumericOperandDescriptor (cpup, 3, 3, false, &mod_fault);
6967 
6968     L68_ (
6969       // L68 raises it immediately
6970       if (mod_fault)
6971         {
6972           doFault (FAULT_IPR,
6973                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
6974                    "Illegal modifier");
6975         }
6976     )
6977 
6978     // Bits 0, 1, 9, and 10 MBZ
6979     if (IWB_IRODD & 0600600000000)
6980       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvne: 0, 1, 9, 10 MBZ");
6981 
6982     // Bit 24-29 of OP1 MBZ
6983     // Multics has been observed to use 600162017511, cf RJ78
6984     //if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
6985       //doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op1 24-29 MBZ");
6986 
6987 
6988 
6989 
6990 
6991 
6992     // only bits 21-23 according to RJ78, maybe even less on DPS8
6993     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000070000)
6994       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op2 21-23 MBZ");
6995 
6996 
6997 
6998 
6999 
7000 
7001     // only bit 23 according to RJ78
7002     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000010000)
7003       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvne op3 23 MBZ");
7004 
7005     DPS8M_ (
7006       // DPS8M raises it delayed
7007       if (mod_fault)
7008         {
7009           doFault (FAULT_IPR,
7010                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7011                    "Illegal modifier");
7012         }
7013     )
7014 
7015     uint srcTN = e -> TN1;    // type of chars in src
7016 
7017     int n1 = 0;
7018 
7019     /*
7020      * Here we need to distinguish between 4 type of numbers.
7021      *
7022      * CSFL - Floating-point, leading sign
7023      * CSLS - Scaled fixed-point, leading sign
7024      * CSTS - Scaled fixed-point, trailing sign
7025      * CSNS - Scaled fixed-point, unsigned
7026      */
7027 
7028     // determine precision
7029     switch(e->S1)
7030     {
7031         case CSFL:
7032             n1 = (int) e->N1 - 1; // need to account for the - sign
7033             if (srcTN == CTN4)
7034                 n1 -= 2;    // 2 4-bit digits exponent
7035             else
7036                 n1 -= 1;    // 1 9-bit digit exponent
7037             break;
7038 
7039         case CSLS:
7040         case CSTS:
7041             n1 = (int) e->N1 - 1; // only 1 sign
7042             break;
7043 
7044         case CSNS:
7045             n1 = (int) e->N1;     // no sign
7046             break;  // no sign wysiwyg
7047     }
7048 
7049     if (n1 < 1)
7050         doFault (FAULT_IPR, fst_ill_proc, "mvne adjusted n1<1");
7051 
7052     // Putting this check in pAOD breaks Multics boot
7053     // From DH03 it seems that DPS8 does not check this explicitly, but L2 exhaust occurs which raises IPR anyway
7054     // So we may as well keep it here.
7055     if (e->N[1] == 0)
7056       doFault (FAULT_IPR, fst_ill_proc, "mvne N2 0");
7057 
7058     // this is a flaw in DPS8/70 which was corrected in DPS88 and later
7059     // ISOLTS-841 07h, RH03 p.7-295
7060     if (e->N[2] == 0)
7061       doFault (FAULT_IPR, fst_ill_proc, "mvne N3 0");
7062 
7063 //if ((e -> op [0]  & 0000000007700) ||
7064 //    (e -> op [1]  & 0000000077700) ||
7065 //    (e -> op [2]  & 0000000017700))
7066 //sim_printf ("%012"PRIo64"\r\n%012"PRIo64"\r\n%012"PRIo64"\r\n%012"PRIo64"\r\n", cpu.cu.IWB, e->op[0], e->op[1], e-> op[2]);
7067 //if (e -> op [0]  & 0000000007700) sim_printf ("op1\r\n");
7068 //if (e -> op [1]  & 0000000077700) sim_printf ("op2\r\n");
7069 //if (e -> op [2]  & 0000000017700) sim_printf ("op3\r\n");
7070 //000140  aa  100 004 024 500   mvne      (pr),(ic),(pr)
7071 //000141  aa  6 00162 01 7511   desc9ls   pr6|114,9,-3
7072 //000142  aa   000236 00 0007   desc9a    158,7               000376 = 403040144040
7073 //000143  aa  6 00134 00 0012   desc9a    pr6|92,10           vcpu
7074 //
7075 // The desc8ls is sign-extending the -3.
7076 
7077     // initialize mop flags. Probably best done elsewhere.
7078     e->mopES = false; // End Suppression flag
7079     e->mopSN = false; // Sign flag
7080     e->mopBZ = false; // Blank-when-zero flag
7081     e->mopZ  = true;  // Zero flag
7082 
7083     e -> srcTally = (int) e -> N1;  // number of chars in src (max 63)
7084     e -> dstTally = (int) e -> N3;  // number of chars in dst (max 63)
7085 
7086 // XXX Temp hack to get MOP to work. Merge TA/TN?
7087 // The MOP operators look at srcTA to make 9bit/not 9-bit decisions about
7088 // the contents of inBuffer; parseNumericOperandDescriptor(cpup, ) always puts
7089 // 4 bit data in inBuffer, so signal the MOPS code of that.
7090     e->srcTA = CTA4;    // type of chars in src
7091 
7092     switch(srcTN)
7093     {
7094         case CTN4:
7095             //e->srcAddr = e->YChar41;
7096             e->srcSZ = 4; //-V1037  // stored as 4-bit decimals
7097             break;
7098         case CTN9:
7099             //e->srcAddr = e->YChar91;
7100             e->srcSZ = 4; //-V1037  // 'cause everything is stored as 4-bit decimals
7101             break;
7102     }
7103 
7104 #if defined(EIS_PTR3)
7105     uint dstTA = TA3;     // type of chars in dst
7106 #else
7107     uint dstTA = e->TA3;  // type of chars in dst
7108 #endif
7109     switch(dstTA)
7110     {
7111         case CTA4:
7112             //e->dstAddr = e->YChar43;
7113             e->dstSZ = 4;
7114             break;
7115         case CTA6:
7116             //e->dstAddr = e->YChar63;
7117             e->dstSZ = 6;
7118             break;
7119         case CTA9:
7120             //e->dstAddr = e->YChar93;
7121             e->dstSZ = 9;
7122             break;
7123     }
7124 
7125 #if defined(EIS_PTR3)
7126     sim_debug (DBG_TRACEEXT, & cpu_dev,
7127       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\r\n",
7128       e->N1, e->N2, e->N3, e->TN1, e->CN1, TA3, e->CN3);
7129 #else
7130     sim_debug (DBG_TRACEEXT, & cpu_dev,
7131       "mvne N1 %d N2 %d N3 %d TN1 %d CN1 %d TA3 %d CN3 %d\r\n",
7132       e->N1, e->N2, e->N3, e->TN1, e->CN1, e->TA3, e->CN3);
7133 #endif
7134 
7135     // 1. load sending string into inputBuffer
7136     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7137 
7138     // 2. Test sign and, if required, set the SN flag. (Sign flag; initially
7139     // set OFF if the sending string has an alphanumeric descriptor or an
7140     // unsigned numeric descriptor. If the sending string has a signed numeric
7141     // descriptor, the sign is initially read from the sending string from the
7142     // digit position defined by the sign and the decimal type field (S); SN is
7143     // set OFF if positive, ON if negative. If all digits are zero, the data is
7144     // assumed positive and the SN flag is set OFF, even when the sign is
7145     // negative.)
7146 
7147     int sum = 0;
7148     for(int n = 0 ; n < e -> srcTally ; n ++)
7149         sum += e -> inBuffer [n];
7150     if ((e -> sign == -1) && sum)
7151         e -> mopSN = true;
7152 
7153     // 3. Execute micro operation string, starting with first (4-bit) digit.
7154     e -> mvne = true;
7155 
7156 #if defined(EIS_PTR2)
7157     mopExecutor (cpup);
7158 #else
7159     mopExecutor (cpup, 2);
7160 #endif
7161 
7162     e -> dstTally = (int) e -> N3;  // restore dstTally for output
7163 
7164     EISwriteOutputBufferToMemory (cpup, 3);
7165     cleanupOperandDescriptor (cpup, 1);
7166     cleanupOperandDescriptor (cpup, 2);
7167     cleanupOperandDescriptor (cpup, 3);
7168   }
7169 
7170 /*
7171  * MVT - Move Alphanumeric with Translation
7172  */
7173 
7174 void mvt (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7175   {
7176     EISstruct * e = & cpu.currentEISinstruction;
7177 
7178     // For i = 1, 2, ..., minimum (N1,N2)
7179     //    m = C(Y-charn1)i-1
7180     //    C(Y-char93)m -> C(Y-charn2)i-1
7181     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7182     //    m = C(FILL)
7183     //    C(Y-char93)m -> C(Y-charn2)i-1
7184 
7185     // Indicators: Truncation. If N1 > N2 then ON; otherwise OFF
7186 
7187     fault_ipr_subtype_ mod_fault = 0;
7188 
7189 #if !defined(EIS_SETUP)
7190     setupOperandDescriptor (cpup, 1, &mod_fault);
7191     setupOperandDescriptor (cpup, 2, &mod_fault);
7192     setupOperandDescriptorCache (cpup,3);
7193 #endif
7194 
7195     parseAlphanumericOperandDescriptor (cpup, 1, 1, false, &mod_fault);
7196     parseAlphanumericOperandDescriptor (cpup, 2, 2, false, &mod_fault);
7197     parseArgOperandDescriptor (cpup, 3, &mod_fault);
7198 
7199     L68_ (
7200       // L68 raises it immediately
7201       if (mod_fault)
7202         {
7203           doFault (FAULT_IPR,
7204                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7205                    "Illegal modifier");
7206         }
7207     )
7208 
7209 // ISOLTS 808 test-03b sets bit 0, 1
7210 // ISOLTS 808 test-03b sets bit 0, 1, 9
7211 
7212     // Bits 10 MBZ
7213     if (IWB_IRODD & 0000200000000)
7214       {
7215         //sim_printf ("mvt %012"PRIo64"\r\n", IWB_IRODD);
7216         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mvt 10 MBZ");
7217       }
7218 
7219 
7220 
7221 
7222 
7223 
7224 
7225 
7226 
7227     // Bit 23 of OP1 MBZ
7228     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000010000)
7229       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op1 23 MBZ");
7230 
7231 // This breaks eis_tester mvt 110
7232 
7233 
7234 
7235 
7236 
7237 
7238     // Bits 18-28 of OP3 MBZ
7239     if (!(e->MF[2] & MFkID) && e -> op [2]  & 0000000777600)
7240       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "mvt op3 18-28 MBZ");
7241 
7242     DPS8M_ (
7243       // DPS8M raises it delayed
7244       if (mod_fault)
7245         {
7246           doFault (FAULT_IPR,
7247                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7248                    "Illegal modifier");
7249         }
7250     )
7251 
7252 #if defined(EIS_PTR3)
7253     e->srcTA = (int) TA1;
7254     uint dstTA = TA2;
7255 
7256     switch (TA1)
7257 #else
7258     e->srcTA = (int) e->TA1;
7259     uint dstTA = e->TA2;
7260 
7261     switch (e -> TA1)
7262 #endif
7263       {
7264         case CTA4:
7265           e -> srcSZ = 4;
7266           break;
7267         case CTA6:
7268           e -> srcSZ = 6;
7269           break;
7270         case CTA9:
7271           e -> srcSZ = 9;
7272          break;
7273       }
7274 
7275 #if defined(EIS_PTR3)
7276     switch (TA2)
7277 #else
7278     switch (e -> TA2)
7279 #endif
7280       {
7281         case CTA4:
7282           e -> dstSZ = 4;
7283           break;
7284         case CTA6:
7285           e -> dstSZ = 6;
7286           break;
7287         case CTA9:
7288           e -> dstSZ = 9;
7289           break;
7290       }
7291 
7292     //  Prepage Check in a Multiword Instruction
7293     //  The MVT, TCT, TCTR, and CMPCT instruction have a prepage check. The
7294     //  size of the translate table is determined by the TA1 data type as shown
7295     //  in the table below. Before the instruction is executed, a check is made
7296     //  for allocation in memory for the page for the translate table. If the
7297     //  page is not in memory, a Missing Page fault occurs before execution of
7298     //  the instruction. (Bull RJ78 p.7-75)
7299 
7300     // TA1              TRANSLATE TABLE SIZE
7301     // 4-BIT CHARACTER      4 WORDS
7302     // 6-BIT CHARACTER     16 WORDS
7303     // 9-BIT CHARACTER    128 WORDS
7304 
7305     uint xlatSize = 0;   // size of xlation table in words .....
7306 #if defined(EIS_PTR3)
7307     switch(TA1)
7308 #else
7309     switch(e->TA1)
7310 #endif
7311     {
7312         case CTA4:
7313             xlatSize = 4;
7314             break;
7315         case CTA6:
7316             xlatSize = 16;
7317             break;
7318         case CTA9:
7319             xlatSize = 128;
7320             break;
7321     }
7322 
7323 
7324 
7325 
7326 
7327 
7328 
7329 
7330 
7331     // ISOLTS 878 01c - op1 and xlate table are prepaged, in that order
7332     // prepage op1
7333     int lastpageidx = ((int)e->N1 + (int)e->CN1 -1) / e->srcSZ;
7334     if (lastpageidx>0)
7335         EISReadIdx(cpup, &e->ADDR1, (uint)lastpageidx);
7336     // prepage xlate table
7337     if (xlatSize > 0)
7338     {
7339         EISReadIdx(cpup, &e->ADDR3, 0);
7340         EISReadIdx(cpup, &e->ADDR3, xlatSize-1);
7341     }
7342 
7343     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7344 
7345     word9 fill = getbits36_9 (cpu.cu.IWB, 0);
7346     word9 fillT = fill;  // possibly truncated fill pattern
7347     // play with fill if we need to use it
7348     switch(e->srcSZ)
7349     {
7350         case 4:
7351             fillT = fill & 017;    // truncate upper 5-bits
7352             break;
7353         case 6:
7354             fillT = fill & 077;    // truncate upper 3-bits
7355             break;
7356     }
7357 
7358     sim_debug (DBG_TRACEEXT, & cpu_dev,
7359       "%s srcCN:%d dstCN:%d srcSZ:%d dstSZ:%d T:%d fill:%03o/%03o N1:%d N2:%d\r\n",
7360       __func__, e -> CN1, e -> CN2, e -> srcSZ, e -> dstSZ, T,
7361       fill, fillT, e -> N1, e -> N2);
7362 
7363     PNL (L68_ (if (max (e->N1, e->N2) < 128)
7364       DU_CYCLE_FLEN_128;))
7365 
7366     for ( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY ++)
7367     {
7368         tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA2));
7369         word9 c = EISget469(cpup, 1, cpu.du.CHTALLY); // get src char
7370         int cidx = 0;
7371 
7372 #if defined(EIS_PTR3)
7373         if (TA1 == TA2)
7374 #else
7375         if (e->TA1 == e->TA2)
7376 #endif
7377             EISput469(cpup, 2, cpu.du.CHTALLY, xlate (cpup, &e->ADDR3, dstTA, c));
7378         else
7379         {
7380             // If data types are dissimilar (TA1 ≠ TA2), each character is high-order
7381             //   truncated or zero filled, as appropriate, as it is moved.
7382             //   No character conversion takes place.
7383             cidx = c;
7384 
7385             word9 cout = xlate(cpup, &e->ADDR3, dstTA, (uint) cidx);
7386 
7387 //            switch(e->dstSZ)
7388 //            {
7389 //                case 4:
7390 //                    cout &= 017;    // truncate upper 5-bits
7391 //                    break;
7392 //                case 6:
7393 //                    cout &= 077;    // truncate upper 3-bits
7394 //                    break;
7395 //            }
7396 
7397             switch (e->srcSZ)
7398             {
7399                 case 6:
7400                     switch(e->dstSZ)
7401                     {
7402                         case 4:
7403                             cout &= 017;    // truncate upper 2-bits
7404                             break;
7405                         case 9:
7406                             break;              // should already be 0-filled
7407                     }
7408                     break;
7409                 case 9:
7410                     switch(e->dstSZ)
7411                     {
7412                         case 4:
7413                             cout &= 017;    // truncate upper 5-bits
7414                             break;
7415                         case 6:
7416                             cout &= 077;    // truncate upper 3-bits
7417                             break;
7418                     }
7419                     break;
7420             }
7421 
7422             EISput469 (cpup, 2, cpu.du.CHTALLY, cout);
7423         }
7424     }
7425 
7426     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
7427     //    m = C(FILL)
7428     //    C(Y-char93)m -> C(Y-charn2)N2-i
7429 
7430     if (e->N1 < e->N2)
7431     {
7432         word9 cfill = xlate(cpup, &e->ADDR3, dstTA, fillT);
7433         switch (e->srcSZ)
7434         {
7435             case 6:
7436                 switch(e->dstSZ)
7437                 {
7438                     case 4:
7439                         cfill &= 017;    // truncate upper 2-bits
7440                         break;
7441                     case 9:
7442                         break;              // should already be 0-filled
7443                 }
7444                 break;
7445             case 9:
7446                 switch(e->dstSZ)
7447                 {
7448                     case 4:
7449                         cfill &= 017;    // truncate upper 5-bits
7450                         break;
7451                     case 6:
7452                         cfill &= 077;    // truncate upper 3-bits
7453                         break;
7454                 }
7455                 break;
7456         }
7457 
7458         for( ; cpu.du.CHTALLY < e->N2 ; cpu.du.CHTALLY ++)
7459           {
7460             tandd_eis_sample (cpup, cpu.du.CHTALLY, TDPER (e -> TA2));
7461             EISput469 (cpup, 2, cpu.du.CHTALLY, cfill);
7462           }
7463     }
7464 
7465     cleanupOperandDescriptor (cpup, 1);
7466     cleanupOperandDescriptor (cpup, 2);
7467     cleanupOperandDescriptor (cpup, 3);
7468 
7469     if (e->N1 > e->N2)
7470       {
7471         SET_I_TRUNC;
7472         if (T && ! TST_I_OMASK)
7473           doFault(FAULT_OFL, fst_zero, "mvt truncation fault");
7474       }
7475     else
7476       CLR_I_TRUNC;
7477   }
7478 
7479 /*
7480  * cmpn - Compare Numeric
7481  */
7482 
7483 void cmpn (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7484 {
7485     EISstruct * e = & cpu.currentEISinstruction;
7486 
7487     // C(Y-charn1) :: C(Y-charn2) as numeric values
7488 
7489     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7490     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7491     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7492 
7493     fault_ipr_subtype_ mod_fault = 0;
7494 
7495 #if !defined(EIS_SETUP)
7496     setupOperandDescriptor(cpup, 1, &mod_fault);
7497     setupOperandDescriptor(cpup, 2, &mod_fault);
7498 #endif
7499 
7500     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
7501     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
7502 
7503     L68_ (
7504       // L68 raises it immediately
7505       if (mod_fault)
7506         {
7507           doFault (FAULT_IPR,
7508                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7509                    "Illegal modifier");
7510         }
7511     )
7512 
7513     // Bits 0-10 MBZ
7514     if (IWB_IRODD & 0777600000000)
7515       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpn 0-10 MBZ");
7516 
7517     DPS8M_ (
7518       // DPS8M raises it delayed
7519       if (mod_fault)
7520         {
7521           doFault (FAULT_IPR,
7522                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7523                    "Illegal modifier");
7524         }
7525     )
7526 
7527     uint srcTN = e->TN1;    // type of chars in src
7528 
7529     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
7530 
7531     /*
7532      * Here we need to distinguish between 4 type of numbers.
7533      *
7534      * CSFL - Floating-point, leading sign
7535      * CSLS - Scaled fixed-point, leading sign
7536      * CSTS - Scaled fixed-point, trailing sign
7537      * CSNS - Scaled fixed-point, unsigned
7538      */
7539 
7540     // determine precision
7541     switch(e->S1)
7542     {
7543         case CSFL:
7544             n1 = (int) e->N1 - 1; // need to account for the - sign
7545             if (srcTN == CTN4)
7546                 n1 -= 2;    // 2 4-bit digits exponent
7547             else
7548                 n1 -= 1;    // 1 9-bit digit exponent
7549             sc1 = 0;        // no scaling factor
7550             break;
7551 
7552         case CSLS:
7553         case CSTS:
7554             n1 = (int) e->N1 - 1; // only 1 sign
7555             sc1 = -e->SF1;
7556             break;
7557 
7558         case CSNS:
7559             n1 = (int) e->N1;     // no sign
7560             sc1 = -e->SF1;
7561             break;  // no sign wysiwyg
7562     }
7563 
7564     if (n1 < 1)
7565         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n1<1");
7566 
7567     switch(e->S2)
7568     {
7569         case CSFL:
7570             n2 = (int) e->N2 - 1; // need to account for the sign
7571             if (e->TN2 == CTN4)
7572                 n2 -= 2;    // 2 4-bit digit exponent
7573             else
7574                 n2 -= 1;    // 1 9-bit digit exponent
7575             sc2 = 0;        // no scaling factor
7576             break;
7577 
7578         case CSLS:
7579         case CSTS:
7580             n2 = (int) e->N2 - 1; // 1 sign
7581             sc2 = -e->SF2;
7582             break;
7583 
7584         case CSNS:
7585             n2 = (int) e->N2;     // no sign
7586             sc2 = -e->SF2;
7587             break;  // no sign wysiwyg
7588     }
7589 
7590     if (n2 < 1)
7591         doFault (FAULT_IPR, fst_ill_proc, "cmpn adjusted n2<1");
7592 
7593     decContext set;
7594     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
7595     decContextDefaultDPS8(&set);
7596 
7597     set.traps=0;
7598 
7599     decNumber _1, _2, _3;
7600 
7601     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7602 
7603     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
7604     if (e->sign == -1)
7605         op1->bits |= DECNEG;
7606     if (e->S1 == CSFL)
7607         op1->exponent = e->exponent;
7608 
7609     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
7610 
7611     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
7612     if (e->sign == -1)
7613         op2->bits |= DECNEG;
7614     if (e->S2 == CSFL)
7615         op2->exponent = e->exponent;
7616 
7617     // signed-compare
7618     decNumber *cmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7619     int cSigned = decNumberToInt32(cmp, &set);
7620 
7621     // take absolute value of operands
7622     op1 = decNumberAbs(op1, op1, &set);
7623     op2 = decNumberAbs(op2, op2, &set);
7624 
7625     // magnitude-compare
7626     decNumber *mcmp = decNumberCompare(&_3, op1, op2, &set); // compare signed op1 :: op2
7627     int cMag = decNumberToInt32(mcmp, &set);
7628 
7629     // Zero If C(Y-charn1) = C(Y-charn2), then ON; otherwise OFF
7630     // Negative If C(Y-charn1) > C(Y-charn2), then ON; otherwise OFF
7631     // Carry If | C(Y-charn1) | > | C(Y-charn2) | , then OFF, otherwise ON
7632 
7633     SC_I_ZERO (cSigned == 0);
7634     SC_I_NEG (cSigned == 1);
7635     SC_I_CARRY (cMag != 1);
7636 
7637     cleanupOperandDescriptor (cpup, 1);
7638     cleanupOperandDescriptor (cpup, 2);
7639 }
7640 
7641 /*
7642  * mvn - move numeric (initial version was deleted by house gnomes)
7643  */
7644 
7645 /*
7646  * write 4-bit chars to memory @ pos ...
7647  */
7648 
7649 static void EISwrite4(cpu_state_t * cpup, EISaddr *p, int *pos, word4 char4)
     /* [previous][next][first][last][top][bottom][index][help] */
7650 {
7651     word36 w;
7652     if (*pos > 7)    // out-of-range?
7653     {
7654         *pos = 0;    // reset to 1st byte
7655 #if defined(EIS_PTR)
7656         long eisaddr_idx = EISADDR_IDX (p);
7657 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7658         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7659 #else
7660         p->address = (p->address + 1) & AMASK;        // goto next dstAddr in memory
7661 #endif
7662     }
7663 
7664     w = EISRead(cpup, p);      // read dst memory into w
7665 
7666 // AL39, Figure 2-3
7667     switch (*pos)
7668     {
7669         case 0:
7670             //w = bitfieldInsert36(w, char4, 31, 5);
7671             w = setbits36_4 (w, 1, char4);
7672             break;
7673         case 1:
7674             //w = bitfieldInsert36(w, char4, 27, 4);
7675             w = setbits36_4 (w, 5, char4);
7676             break;
7677         case 2:
7678             //w = bitfieldInsert36(w, char4, 22, 5);
7679             w = setbits36_4 (w, 10, char4);
7680             break;
7681         case 3:
7682             //w = bitfieldInsert36(w, char4, 18, 4);
7683             w = setbits36_4 (w, 14, char4);
7684             break;
7685         case 4:
7686             //w = bitfieldInsert36(w, char4, 13, 5);
7687             w = setbits36_4 (w, 19, char4);
7688             break;
7689         case 5:
7690             //w = bitfieldInsert36(w, char4, 9, 4);
7691             w = setbits36_4 (w, 23, char4);
7692             break;
7693         case 6:
7694             //w = bitfieldInsert36(w, char4, 4, 5);
7695             w = setbits36_4 (w, 28, char4);
7696             break;
7697         case 7:
7698             //w = bitfieldInsert36(w, char4, 0, 4);
7699             w = setbits36_4 (w, 32, char4);
7700             break;
7701     }
7702 
7703     EISWriteIdx(cpup, p, 0, w, true); // XXX this is the inefficient part!
7704 
7705     *pos += 1;       // to next char.
7706 }
7707 
7708 /*
7709  * write 9-bit bytes to memory @ pos ...
7710  */
7711 
7712 static void EISwrite9(cpu_state_t *cpup, EISaddr *p, int *pos, word9 char9)
     /* [previous][next][first][last][top][bottom][index][help] */
7713 {
7714     word36 w;
7715     if (*pos > 3)    // out-of-range?
7716     {
7717         *pos = 0;    // reset to 1st byte
7718 #if defined(EIS_PTR)
7719         long eisaddr_idx = EISADDR_IDX (p);
7720 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
7721         cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;     // bump source to next address
7722 #else
7723         p->address = (p->address + 1) & AMASK;       // goto next dstAddr in memory
7724 #endif
7725     }
7726 
7727     w = EISRead(cpup, p);      // read dst memory into w
7728 
7729 // AL39, Figure 2-5
7730     switch (*pos)
7731     {
7732         case 0:
7733             //w = bitfieldInsert36(w, char9, 27, 9);
7734             w = setbits36_9 (w, 0, char9);
7735             break;
7736         case 1:
7737             //w = bitfieldInsert36(w, char9, 18, 9);
7738             w = setbits36_9 (w, 9, char9);
7739             break;
7740         case 2:
7741             //w = bitfieldInsert36(w, char9, 9, 9);
7742             w = setbits36_9 (w, 18, char9);
7743             break;
7744         case 3:
7745             //w = bitfieldInsert36(w, char9, 0, 9);
7746             w = setbits36_9 (w, 27, char9);
7747             break;
7748     }
7749 
7750     EISWriteIdx (cpup, p, 0, w, true); // XXX this is the inefficient part!
7751 
7752     *pos += 1;       // to next byte.
7753 }
7754 
7755 /*
7756  * write a 4-, or 9-bit numeric char to dstAddr ....
7757  */
7758 
7759 static void EISwrite49(cpu_state_t * cpup, EISaddr *p, int *pos, int tn, word9 c49)
     /* [previous][next][first][last][top][bottom][index][help] */
7760 {
7761     switch(tn)
7762     {
7763         case CTN4:
7764             EISwrite4(cpup, p, pos, (word4) c49);
7765             return;
7766         case CTN9:
7767             EISwrite9(cpup, p, pos, c49);
7768             return;
7769     }
7770 }
7771 
7772 void mvn (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
7773 {
7774     /*
7775      * EXPLANATION:
7776      * Starting at location YC1, the decimal number of data type TN1 and sign
7777      * and decimal type S1 is moved, properly scaled, to the decimal number of
7778      * data type TN2 and sign and decimal type S2 that starts at location YC2.
7779      * If S2 indicates a fixed-point format, the results are stored as L2
7780      * digits using scale factor SF2, and thereby may cause
7781      * most-significant-digit overflow and/or least- significant-digit
7782      * truncation.
7783      * If P = 1, positive signed 4-bit results are stored using octal 13 as the
7784      * plus sign. Rounding is legal for both fixed-point and floating-point
7785      * formats. If P = 0, positive signed 4-bit results are stored using octal
7786      * 14 as the plus sign.
7787      * Provided that string 1 and string 2 are not overlapped, the contents of
7788      * the decimal number that starts in location YC1 remain unchanged.
7789      */
7790 
7791     EISstruct * e = & cpu.currentEISinstruction;
7792 
7793     fault_ipr_subtype_ mod_fault = 0;
7794 
7795 #if !defined(EIS_SETUP)
7796     setupOperandDescriptor(cpup, 1, &mod_fault);
7797     setupOperandDescriptor(cpup, 2, &mod_fault);
7798 #endif
7799 
7800     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
7801     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
7802 
7803     L68_ (
7804       // L68 raises it immediately
7805       if (mod_fault)
7806         {
7807           doFault (FAULT_IPR,
7808                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7809                    "Illegal modifier");
7810         }
7811     )
7812 
7813     // Bits 2-8 MBZ
7814     if (IWB_IRODD & 0377000000000)
7815      doFault (FAULT_IPR,
7816               (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault},
7817               "mvn 2-8 MBZ");
7818 
7819     DPS8M_ (
7820       // DPS8M raises it delayed
7821       if (mod_fault)
7822         {
7823           doFault (FAULT_IPR,
7824                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
7825                    "Illegal modifier");
7826         }
7827     )
7828 
7829     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character
7830                                               //  control
7831     word1 T = getbits36_1 (cpu.cu.IWB, 9);
7832     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
7833     PNL (L68_ (if (R)
7834       DU_CYCLE_FRND;))
7835 
7836     uint srcTN = e->TN1;    // type of chars in src
7837 
7838     uint dstTN = e->TN2;    // type of chars in dst
7839     uint dstCN = e->CN2;    // starting at char pos CN
7840 
7841     sim_debug (DBG_CAC, & cpu_dev,
7842                "mvn(1): TN1 %d CN1 %d N1 %d TN2 %d CN2 %d N2 %d\r\n",
7843                e->TN1, e->CN1, e->N1, e->TN2, e->CN2, e->N2);
7844     sim_debug (DBG_CAC, & cpu_dev,
7845                "mvn(2): SF1 %d              SF2 %d\r\n",
7846                e->SF1, e->SF2);
7847     sim_debug (DBG_CAC, & cpu_dev,
7848                "mvn(3): OP1 %012"PRIo64" OP2 %012"PRIo64"\r\n",
7849                e->OP1, e->OP2);
7850 
7851     int n1 = 0, n2 = 0, sc1 = 0;
7852 
7853     /*
7854      * Here we need to distinguish between 4 type of numbers.
7855      *
7856      * CSFL - Floating-point, leading sign
7857      * CSLS - Scaled fixed-point, leading sign
7858      * CSTS - Scaled fixed-point, trailing sign
7859      * CSNS - Scaled fixed-point, unsigned
7860      */
7861 
7862     // determine precision
7863     switch(e->S1)
7864     {
7865         case CSFL:
7866             n1 = (int) e->N1 - 1; // need to account for the - sign
7867             if (srcTN == CTN4)
7868                 n1 -= 2;    // 2 4-bit digits exponent
7869             else
7870                 n1 -= 1;    // 1 9-bit digit exponent
7871             sc1 = 0;        // no scaling factor
7872             break;
7873 
7874         case CSLS:
7875         case CSTS:
7876             n1 = (int) e->N1 - 1; // only 1 sign
7877             sc1 = -e->SF1;
7878             break;
7879 
7880         case CSNS:
7881             n1 = (int) e->N1;     // no sign
7882             sc1 = -e->SF1;
7883             break;  // no sign wysiwyg
7884     }
7885 
7886     sim_debug (DBG_CAC, & cpu_dev, "n1 %d sc1 %d\r\n", n1, sc1);
7887 
7888     // RJ78: An Illegal Procedure fault occurs if:
7889     // The values for the number of characters (N1 or N2) of the data
7890     // descriptors are not large enough to hold the number of characters
7891     // required for the specified sign and/or exponent, plus at least one
7892     // digit.
7893 
7894     if (n1 < 1)
7895         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n1<1");
7896 
7897     switch(e->S2)
7898     {
7899         case CSFL:
7900             n2 = (int) e->N2 - 1; // need to account for the sign
7901             if (dstTN == CTN4)
7902                 n2 -= 2;    // 2 4-bit digit exponent
7903             else
7904                 n2 -= 1;    // 1 9-bit digit exponent
7905             break;
7906 
7907         case CSLS:
7908         case CSTS:
7909             n2 = (int) e->N2 - 1; // 1 sign
7910             break;
7911 
7912         case CSNS:
7913             n2 = (int) e->N2;     // no sign
7914             break;          // no sign wysiwyg
7915     }
7916 
7917     sim_debug (DBG_CAC, & cpu_dev, "n2 %d\r\n", n2);
7918 
7919     if (n2 < 1)
7920         doFault (FAULT_IPR, fst_ill_proc, "mvn adjusted n2<1");
7921 
7922     decContext set;
7923     decContextDefaultDPS8(&set);
7924     set.traps=0;
7925 
7926     decNumber _1;
7927 
7928     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
7929 
7930     decNumber *op1 = decBCD9ToNumber (e->inBuffer, n1, sc1, &_1);
7931 
7932     if (e->sign == -1)
7933         op1->bits |= DECNEG;
7934     if (e->S1 == CSFL)
7935         op1->exponent = e->exponent;
7936     if (decNumberIsZero (op1))
7937         op1->exponent = 127;
7938 
7939     if_sim_debug (DBG_CAC, & cpu_dev)
7940     {
7941         PRINTDEC ("mvn input (op1)", op1);
7942     }
7943 
7944     bool Ovr = false, EOvr = false, Trunc = false;
7945 
7946     uint8_t out [256];
7947     char * res = formatDecimal (out, & set, op1, n2, (int) e->S2, e->SF2, R,
7948                                 & Ovr, & Trunc);
7949 
7950     sim_debug (DBG_CAC, & cpu_dev, "mvn res: '%s'\r\n", res);
7951 
7952     // now write to memory in proper format.....
7953 
7954     //word18 dstAddr = e->dstAddr;
7955     int pos = (int) dstCN;
7956 
7957     // 1st, take care of any leading sign .......
7958     switch(e->S2)
7959     {
7960         case CSFL:  // floating-point, leading sign.
7961         case CSLS:  // fixed-point, leading sign
7962             switch(dstTN)
7963             {
7964                 case CTN4:
7965  // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
7966  // sign character is placed appropriately if the result of the operation is
7967  // positive.
7968                     if (e->P)
7969                         // special +
7970                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7971                                    (decNumberIsNegative (op1) &&
7972                                     ! decNumberIsZero(op1)) ? 015 : 013);
7973                     else
7974                         // default +
7975                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7976                                     (decNumberIsNegative (op1) &&
7977                                      ! decNumberIsZero (op1)) ? 015 : 014);
7978                     break;
7979                 case CTN9:
7980                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7981                                 (decNumberIsNegative (op1) &&
7982                                  ! decNumberIsZero (op1)) ? '-' : '+');
7983                     break;
7984             }
7985             break;
7986 
7987         case CSTS:  // nuttin' to do here .....
7988         case CSNS:
7989             break;  // no sign wysiwyg
7990     }
7991 
7992     // 2nd, write the digits .....
7993     for (int i = 0 ; i < n2 ; i ++)
7994         switch (dstTN)
7995         {
7996             case CTN4:
7997                 EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
7998                             (word9) (res[i] - '0'));
7999                 break;
8000             case CTN9:
8001                 EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN, (word9) res[i]);
8002                 break;
8003         }
8004 
8005     // 3rd, take care of any trailing sign or exponent ...
8006     switch(e->S2)
8007     {
8008         case CSTS:  // write trailing sign ....
8009             switch(dstTN)
8010             {
8011                 case CTN4:
8012 // If TN2 and S2 specify a 4-bit signed number and P = 1, then the 13(8) plus
8013 // sign character is placed appropriately if the result of the operation is
8014 // positive.
8015                     if (e->P)
8016                         // special +
8017                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
8018                                     (decNumberIsNegative (op1) &&
8019                                      ! decNumberIsZero(op1)) ? 015 :  013);
8020                     else
8021                         // default +
8022                         EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
8023                                     (decNumberIsNegative (op1) &&
8024                                      ! decNumberIsZero (op1)) ? 015 :  014);
8025                     break;
8026 
8027                 case CTN9:
8028                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
8029                                 (decNumberIsNegative (op1) &&
8030                                  ! decNumberIsZero(op1)) ? '-' : '+');
8031                     break;
8032             }
8033             break;
8034 
8035         case CSFL:  // floating-point, leading sign.
8036             // write the exponent
8037             switch(dstTN)
8038             {
8039                 case CTN4:
8040                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
8041                                 (op1->exponent >> 4) & 0xf); // upper 4-bits
8042                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
8043                                 op1->exponent       & 0xf); // lower 4-bits
8044                     break;
8045                 case CTN9:
8046                     EISwrite49 (cpup, & e->ADDR2, & pos, (int) dstTN,
8047                                  op1->exponent & 0xff); // write 8-bit exponent
8048                 break;
8049             }
8050             break;
8051 
8052         case CSLS:  // fixed point, leading sign - already done
8053         case CSNS:  // fixed point, unsigned - nuttin' needed to do
8054             break;
8055     }
8056 
8057     // set flags, etc ...
8058     if (e->S2 == CSFL)
8059     {
8060         if (op1->exponent > 127)
8061         {
8062             SET_I_EOFL;
8063             EOvr = true;
8064         }
8065         if (op1->exponent < -128)
8066         {
8067             SET_I_EUFL;
8068             EOvr = true;
8069         }
8070     }
8071 
8072 sim_debug (DBG_CAC, & cpu_dev, "is neg %o\r\n", decNumberIsNegative(op1));
8073 sim_debug (DBG_CAC, & cpu_dev, "is zero %o\r\n", decNumberIsZero(op1));
8074 sim_debug (DBG_CAC, & cpu_dev, "R %o\r\n", R);
8075 sim_debug (DBG_CAC, & cpu_dev, "Trunc %o\r\n", Trunc);
8076 sim_debug (DBG_CAC, & cpu_dev, "TRUNC %o\r\n", TST_I_TRUNC);
8077 sim_debug (DBG_CAC, & cpu_dev, "OMASK %o\r\n", TST_I_OMASK);
8078 sim_debug (DBG_CAC, & cpu_dev, "tstOVFfault %o\r\n", tstOVFfault (cpup));
8079 sim_debug (DBG_CAC, & cpu_dev, "T %o\r\n", T);
8080 sim_debug (DBG_CAC, & cpu_dev, "EOvr %o\r\n", EOvr);
8081 sim_debug (DBG_CAC, & cpu_dev, "Ovr %o\r\n", Ovr);
8082     // set negative indicator if op3 < 0
8083     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));
8084 
8085     // set zero indicator if op3 == 0
8086     SC_I_ZERO (decNumberIsZero(op1));
8087 
8088     // If the truncation condition exists without rounding, then ON;
8089     // otherwise OFF
8090     SC_I_TRUNC (!R && Trunc);
8091 
8092     cleanupOperandDescriptor (cpup, 1);
8093     cleanupOperandDescriptor (cpup, 2);
8094 
8095     if (TST_I_TRUNC && T && tstOVFfault (cpup))
8096         doFault (FAULT_OFL, fst_zero, "mvn truncation(overflow) fault");
8097     if (EOvr && tstOVFfault (cpup))
8098         doFault (FAULT_OFL, fst_zero, "mvn over/underflow fault");
8099     if (Ovr)
8100     {
8101         SET_I_OFLOW;
8102         if (tstOVFfault (cpup))
8103           doFault (FAULT_OFL, fst_zero, "mvn overflow fault");
8104     }
8105 }
8106 
8107 void csl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8108   {
8109     EISstruct * e = & cpu.currentEISinstruction;
8110 
8111     // For i = bits 1, 2, ..., minimum (N1,N2)
8112     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
8113     //   C(BOLR)m -> C(Y-bit2)i-1
8114     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
8115     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
8116     //   C(BOLR)m -> C(Y-bit2)i-1
8117     //
8118     // INDICATORS: (Indicators not listed are not affected)
8119     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8120     //     Truncation If N1 > N2, then ON; otherwise OFF
8121     //
8122     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8123     // processed and the truncation indicator is set ON.
8124     //
8125     // If T = 1 and the truncation indicator is set ON by execution of the
8126     // instruction, then a truncation (overflow) fault occurs.
8127     //
8128     // BOLR
8129     // If first operand    and    second operand    then result
8130     // bit is:                    bit is:           is from bit:
8131     //        0                          0                      5
8132     //        0                          1                      6
8133     //        1                          0                      7
8134     //        1                          1                      8
8135     //
8136     // The Boolean operations most commonly used are
8137     //                  BOLR Field Bits
8138     // Operation        5      6      7      8
8139     //
8140     // MOVE             0      0      1      1
8141     // AND              0      0      0      1
8142     // OR               0      1      1      1
8143     // NAND             1      1      1      0
8144     // EXCLUSIVE OR     0      1      1      0
8145     // Clear            0      0      0      0
8146     // Invert           1      1      0      0
8147     //
8148 
8149 // 0 0 0 0  Clear
8150 // 0 0 0 1  a AND b
8151 // 0 0 1 0  a AND !b
8152 // 0 0 1 1  a
8153 // 0 1 0 0  !a AND b
8154 // 0 1 0 1  b
8155 // 0 1 1 0  a XOR b
8156 // 0 1 1 1  a OR b
8157 // 1 0 0 0  !a AND !b     !(a OR b)
8158 // 1 0 0 1  a == b        !(a XOR b)
8159 // 1 0 1 0  !b
8160 // 1 0 1 1  !b OR A
8161 // 1 1 0 0  !a
8162 // 1 1 0 1  !b AND a
8163 // 1 1 1 0  a NAND b
8164 // 1 1 1 1  Set
8165 
8166     fault_ipr_subtype_ mod_fault = 0;
8167 
8168 #if !defined(EIS_SETUP)
8169     setupOperandDescriptor (cpup, 1, & mod_fault);
8170     setupOperandDescriptor (cpup, 2, & mod_fault);
8171 #endif
8172 
8173     parseBitstringOperandDescriptor (cpup, 1, & mod_fault);
8174     parseBitstringOperandDescriptor (cpup, 2, & mod_fault);
8175 
8176     L68_ (
8177       // L68 raises it immediately
8178       if (mod_fault)
8179           doFault (FAULT_IPR,
8180                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8181                    "Illegal modifier");
8182     )
8183 
8184     // Bits 1-4 and 10 MBZ
8185     if (IWB_IRODD & 0360200000000)
8186       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8187 
8188     DPS8M_ (
8189       // DPS8M raises it delayed
8190       if (mod_fault)
8191           doFault (FAULT_IPR,
8192                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8193                    "Illegal modifier");
8194     )
8195 
8196     e->ADDR1.cPos = (int) e->C1;
8197     e->ADDR2.cPos = (int) e->C2;
8198 
8199     e->ADDR1.bPos = (int) e->B1;
8200     e->ADDR2.bPos = (int) e->B2;
8201 
8202     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8203     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8204 
8205     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8206     bool B5 = !! (BOLR & 8);
8207     bool B6 = !! (BOLR & 4);
8208     bool B7 = !! (BOLR & 2);
8209     bool B8 = !! (BOLR & 1);
8210 
8211     e->ADDR1.mode = eRWreadBit;
8212 
8213 #if !defined(EIS_PTR)
8214     sim_debug (DBG_TRACEEXT, & cpu_dev,
8215                "CSL N1 %d N2 %d\r\n"
8216                "CSL C1 %d C2 %d B1 %d B2 %d F %o T %d\r\n"
8217                "CSL BOLR %u%u%u%u\r\n"
8218                "CSL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\r\n"
8219                "CSL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\r\n",
8220                e -> N1, e -> N2,
8221                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8222                B5, B6, B7, B8,
8223                e -> addr [0].SNR, e -> addr [0].address,
8224                e -> addr [0].cPos, e -> addr [0].bPos,
8225                e -> addr [1].SNR, e -> addr [1].address,
8226                e -> addr [1].cPos, e -> addr [1].bPos);
8227 #endif
8228 
8229     bool bR = false; // result bit
8230 
8231     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8232                  DU_CYCLE_FLEN_128;))
8233 
8234     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8235       {
8236         tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8237         bool b1 = EISgetBitRWN(cpup, &e->ADDR1, true);
8238         e->ADDR2.mode = eRWreadBit;
8239         bool b2 = EISgetBitRWN(cpup, &e->ADDR2, true);
8240 
8241         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8242 
8243         if (bR)
8244           {
8245             //CLR_I_ZERO);
8246             cpu.du.Z = 0;
8247           }
8248 
8249         // write out modified bit
8250         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8251         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8252         // if ADDR1 is on a word boundary, it might fault on the next loop,
8253         // so we flush the write in case.
8254         EISgetBitRWN(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8255     }
8256 
8257     if (e->N1 < e->N2)
8258       {
8259         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8260           {
8261             tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8262             bool b1 = F;
8263 
8264             e->ADDR2.mode = eRWreadBit;
8265             bool b2 = EISgetBitRWN(cpup, &e->ADDR2, true);
8266 
8267             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8268 
8269             if (bR)
8270               {
8271                 //CLR_I_ZERO;
8272                 cpu.du.Z = 0;
8273               }
8274 
8275             // write out modified bit
8276             e->ADDR2.bit = bR ? 1 : 0;
8277             e->ADDR2.mode = eRWwriteBit;
8278             // if ADDR1 is on a word boundary, it might fault on the next loop,
8279             // so we flush the write in case.
8280             EISgetBitRWN(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 35);    // write bit w/ addr increment to memory
8281           }
8282       }
8283 
8284     EISWriteCache (cpup, &e->ADDR2);
8285 
8286     cleanupOperandDescriptor (cpup, 1);
8287     cleanupOperandDescriptor (cpup, 2);
8288 
8289     SC_I_ZERO (cpu.du.Z);
8290     if (e->N1 > e->N2)
8291       {
8292         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8293         // processed and the truncation indicator is set ON.
8294         //
8295         // If T = 1 and the truncation indicator is set ON by execution of the
8296         // instruction, then a truncation (overflow) fault occurs.
8297 
8298         SET_I_TRUNC;
8299         if (T && tstOVFfault (cpup))
8300           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8301       }
8302     else
8303       {
8304         CLR_I_TRUNC;
8305       }
8306   }
8307 
8308 /*
8309  * return B (bit position), C (char position) and word offset given:
8310  *  'length' # of bits, etc ....
8311  *  'initC' initial char position (C)
8312  *  'initB' initial bit position
8313  */
8314 
8315 static void getBitOffsets(int length, int initC, int initB, int *nWords, int *newC, int *newB)
     /* [previous][next][first][last][top][bottom][index][help] */
8316 {
8317     if (length == 0)
8318         return;
8319 
8320     int endBit = (length + 9 * initC + initB - 1) % 36;
8321 
8322     //int numWords = (length + 35) / 36;  // how many additional words will the bits take up?
8323     int numWords = (length + 9 * initC + initB + 35) / 36;  // how many additional words will the bits take up?
8324     int lastWordOffset = numWords - 1;
8325 
8326     if (lastWordOffset > 0)          // more that the 1 word needed?
8327         *nWords = lastWordOffset;  // # of additional words
8328     else
8329         *nWords = 0;    // no additional words needed
8330 
8331     *newC = endBit / 9; // last character number
8332     *newB = endBit % 9; // last bit number
8333 }
8334 
8335 static bool EISgetBitRWNR (cpu_state_t * cpup, EISaddr * p, bool flush)
     /* [previous][next][first][last][top][bottom][index][help] */
8336   {
8337     int baseCharPosn = (p -> cPos * 9);     // 9-bit char bit position
8338     int baseBitPosn = baseCharPosn + p -> bPos;
8339     baseBitPosn -= (int) cpu.du.CHTALLY;
8340 
8341     int bitPosn = baseBitPosn % 36;
8342     int woff = baseBitPosn / 36;
8343     while (bitPosn < 0)
8344       {
8345         bitPosn += 36;
8346         woff -= 1;
8347       }
8348 
8349 /* if (bitPosn < 0) { */
8350 /* sim_printf ("cPos %d bPos %d\r\n", p->cPos, p->bPos); */
8351 /* sim_printf ("baseCharPosn %d baseBitPosn %d\r\n", baseCharPosn, baseBitPosn); */
8352 /* sim_printf ("CHTALLY %d baseBitPosn %d\r\n", cpu.du.CHTALLY, baseBitPosn); */
8353 /* sim_printf ("bitPosn %d woff %d\r\n", bitPosn, woff); */
8354 /* sim_warn ("EISgetBitRWNR oops\r\n"); */
8355 /* return false; */
8356 /* } */
8357 
8358 #if defined(EIS_PTR)
8359     long eisaddr_idx = EISADDR_IDX (p);
8360 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8361     word18 saveAddr = cpu.du.Dk_PTR_W[eisaddr_idx];
8362     cpu.du.Dk_PTR_W[eisaddr_idx] += (word18) woff;
8363     cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
8364 #else
8365     word18 saveAddr = p -> address;
8366     //p -> address += (word18) woff;
8367     //ubsan
8368     p->address = (word18) (((word18s) p->address) + (word18s) woff);
8369 #endif
8370 
8371     p -> data = EISRead (cpup, p); // read data word from memory
8372 
8373     if (p -> mode == eRWreadBit)
8374       {
8375         p -> bit = getbits36_1 (p -> data, (uint) bitPosn);
8376       }
8377     else if (p -> mode == eRWwriteBit)
8378       {
8379         //p -> data = bitfieldInsert36 (p -> data, p -> bit, bitPosn, 1);
8380         p -> data = setbits36_1 (p -> data, (uint) bitPosn, p -> bit);
8381 
8382         EISWriteIdx (cpup, p, 0, p -> data, flush); // write data word to memory
8383       }
8384 
8385     p->last_bit_posn = bitPosn;
8386 
8387 #if defined(EIS_PTR)
8388     cpu.du.Dk_PTR_W[eisaddr_idx] = saveAddr;
8389 #else
8390     p -> address = saveAddr;
8391 #endif
8392     return p -> bit;
8393   }
8394 
8395 void csr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8396   {
8397     EISstruct * e = & cpu.currentEISinstruction;
8398 
8399     // For i = bits 1, 2, ..., minimum (N1,N2)
8400     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8401     //   C(BOLR)m -> C( Y-bit2)N2-i
8402     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8403     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8404     //    C(BOLR)m -> C( Y-bit2)N2-i
8405     // INDICATORS: (Indicators not listed are not affected)
8406     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8407     //     Truncation If N1 > N2, then ON; otherwise OFF
8408     //
8409     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8410     // processed and the truncation indicator is set ON.
8411     //
8412     // If T = 1 and the truncation indicator is set ON by execution of the
8413     // instruction, then a truncation (overflow) fault occurs.
8414     //
8415     // BOLR
8416     // If first operand    and    second operand    then result
8417     // bit is:                    bit is:           is from bit:
8418     //        0                          0                      5
8419     //        0                          1                      6
8420     //        1                          0                      7
8421     //        1                          1                      8
8422     //
8423     // The Boolean operations most commonly used are
8424     //                  BOLR Field Bits
8425     // Operation        5      6      7      8
8426     //
8427     // MOVE             0      0      1      1
8428     // AND              0      0      0      1
8429     // OR               0      1      1      1
8430     // NAND             1      1      1      0
8431     // EXCLUSIVE OR     0      1      1      0
8432     // Clear            0      0      0      0
8433     // Invert           1      1      0      0
8434     //
8435 
8436     fault_ipr_subtype_ mod_fault = 0;
8437 
8438 #if !defined(EIS_SETUP)
8439     setupOperandDescriptor(cpup, 1, &mod_fault);
8440     setupOperandDescriptor(cpup, 2, &mod_fault);
8441 #endif
8442 
8443     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8444     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8445 
8446     L68_ (
8447       // L68 raises it immediately
8448       if (mod_fault)
8449           doFault (FAULT_IPR,
8450                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8451                    "Illegal modifier");
8452     )
8453 
8454     // Bits 1-4 and 10 MBZ
8455     if (IWB_IRODD & 0360200000000)
8456       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8457 
8458     DPS8M_ (
8459       // DPS8M raises it delayed
8460       if (mod_fault)
8461           doFault (FAULT_IPR,
8462                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8463                    "Illegal modifier");
8464     )
8465 
8466     e->ADDR1.cPos = (int) e->C1;
8467     e->ADDR2.cPos = (int) e->C2;
8468 
8469     e->ADDR1.bPos = (int) e->B1;
8470     e->ADDR2.bPos = (int) e->B2;
8471 
8472     // get new char/bit offsets
8473     int numWords1=0, numWords2=0;
8474 
8475     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8476     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8477     PNL (cpu.du.D1_PTR_W &= AMASK);
8478 #if defined(EIS_PTR)
8479     cpu.du.D1_PTR_W += (word18) numWords1;
8480     cpu.du.D1_PTR_W &= AMASK;
8481 #else
8482     e->ADDR1.address += (word18) numWords1;
8483 #endif
8484 
8485     sim_debug (DBG_TRACEEXT, & cpu_dev,
8486                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\r\n",
8487                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8488     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8489     sim_debug (DBG_TRACEEXT, & cpu_dev,
8490                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\r\n",
8491                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8492     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8493     PNL (cpu.du.D2_PTR_W &= AMASK);
8494 #if defined(EIS_PTR)
8495     cpu.du.D2_PTR_W += (word18) numWords1;
8496     cpu.du.D2_PTR_W &= AMASK;
8497 #else
8498     e->ADDR2.address += (word18) numWords2;
8499 #endif
8500 
8501     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8502     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8503 
8504     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8505     bool B5 = !! (BOLR & 8);
8506     bool B6 = !! (BOLR & 4);
8507     bool B7 = !! (BOLR & 2);
8508     bool B8 = !! (BOLR & 1);
8509 
8510     e->ADDR1.mode = eRWreadBit;
8511 
8512     CLR_I_TRUNC;     // assume N1 <= N2
8513 
8514     bool bR = false; // result bit
8515 
8516     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8517                  DU_CYCLE_FLEN_128;))
8518 
8519     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8520       {
8521         tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8522         bool b1 = EISgetBitRWNR(cpup, &e->ADDR1, true);
8523 
8524         e->ADDR2.mode = eRWreadBit;
8525         bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8526 
8527         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8528 
8529         if (bR)
8530           cpu.du.Z = 0;
8531 
8532         // write out modified bit
8533         e->ADDR2.bit = bR ? 1 : 0;              // set bit contents to write
8534         e->ADDR2.mode = eRWwriteBit;    // we want to write the bit
8535         // if ADDR1 is on a word boundary, it might fault on the next loop,
8536         // so we flush the write in case.
8537         EISgetBitRWNR(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 0);
8538       }
8539 
8540     if (e->N1 < e->N2)
8541       {
8542         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8543           {
8544             tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8545             bool b1 = F;
8546 
8547             e->ADDR2.mode = eRWreadBit;
8548             bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8549 
8550             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8551 
8552             if (bR)
8553               {
8554                 //CLR_I_ZERO;
8555                 cpu.du.Z = 0;
8556               }
8557 
8558             // write out modified bit
8559             e->ADDR2.bit = bR ? 1 : 0;
8560             e->ADDR2.mode = eRWwriteBit;
8561             // if ADDR1 is on a word boundary, it might fault on the next loop,
8562             // so we flush the write in case.
8563             EISgetBitRWNR(cpup, &e->ADDR2, e->ADDR1.last_bit_posn == 0);
8564           }
8565       }
8566 
8567     EISWriteCache (cpup, &e->ADDR2);
8568 
8569     cleanupOperandDescriptor (cpup, 1);
8570     cleanupOperandDescriptor (cpup, 2);
8571 
8572     SC_I_ZERO (cpu.du.Z);
8573     if (e->N1 > e->N2)
8574       {
8575         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8576         // processed and the truncation indicator is set ON.
8577         //
8578         // If T = 1 and the truncation indicator is set ON by execution of the
8579         // instruction, then a truncation (overflow) fault occurs.
8580 
8581         SET_I_TRUNC;
8582         if (T && tstOVFfault (cpup))
8583           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8584       }
8585     else
8586       {
8587         CLR_I_TRUNC;
8588       }
8589   }
8590 
8591 void sztl (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8592   {
8593     // The execution of this instruction is identical to the Combine
8594     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8595     // not placed into C(Y-bit2)i-1.
8596 
8597     EISstruct * e = & cpu.currentEISinstruction;
8598 
8599     // For i = bits 1, 2, ..., minimum (N1,N2)
8600     //   m = C(Y-bit1)i-1 || C(Y-bit2)i-1 (a 2-bit number)
8601     //   C(BOLR)m -> C(Y-bit2)i-1
8602     // If N1 < N2, then for i = N1+l, N1+2, ..., N2
8603     //   m = C(F) || C(Y-bit2)i-1 (a 2-bit number)
8604     //   C(BOLR)m -> C(Y-bit2)i-1
8605     //
8606     // INDICATORS: (Indicators not listed are not affected)
8607     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8608     //     Truncation If N1 > N2, then ON; otherwise OFF
8609     //
8610     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8611     // processed and the truncation indicator is set ON.
8612     //
8613     // If T = 1 and the truncation indicator is set ON by execution of the
8614     // instruction, then a truncation (overflow) fault occurs.
8615     //
8616     // BOLR
8617     // If first operand    and    second operand    then result
8618     // bit is:                    bit is:           is from bit:
8619     //        0                          0                      5
8620     //        0                          1                      6
8621     //        1                          0                      7
8622     //        1                          1                      8
8623     //
8624     // The Boolean operations most commonly used are
8625     //                  BOLR Field Bits
8626     // Operation        5      6      7      8
8627     //
8628     // MOVE             0      0      1      1
8629     // AND              0      0      0      1
8630     // OR               0      1      1      1
8631     // NAND             1      1      1      0
8632     // EXCLUSIVE OR     0      1      1      0
8633     // Clear            0      0      0      0
8634     // Invert           1      1      0      0
8635     //
8636 
8637 // 0 0 0 0  Clear
8638 // 0 0 0 1  a AND b
8639 // 0 0 1 0  a AND !b
8640 // 0 0 1 1  a
8641 // 0 1 0 0  !a AND b
8642 // 0 1 0 1  b
8643 // 0 1 1 0  a XOR b
8644 // 0 1 1 1  a OR b
8645 // 1 0 0 0  !a AND !b     !(a OR b)
8646 // 1 0 0 1  a == b        !(a XOR b)
8647 // 1 0 1 0  !b
8648 // 1 0 1 1  !b OR A
8649 // 1 1 0 0  !a
8650 // 1 1 0 1  !b AND a
8651 // 1 1 1 0  a NAND b
8652 // 1 1 1 1  Set
8653 
8654     fault_ipr_subtype_ mod_fault = 0;
8655 
8656 #if !defined(EIS_SETUP)
8657     setupOperandDescriptor (cpup, 1, &mod_fault);
8658     setupOperandDescriptor (cpup, 2, &mod_fault);
8659 #endif
8660 
8661     parseBitstringOperandDescriptor (cpup, 1, &mod_fault);
8662     parseBitstringOperandDescriptor (cpup, 2, &mod_fault);
8663 
8664     L68_ (
8665       // L68 raises it immediately
8666       if (mod_fault)
8667           doFault (FAULT_IPR,
8668                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8669                    "Illegal modifier");
8670     )
8671 
8672     // Bits 1-4 and 10 MBZ
8673     if (IWB_IRODD & 0360200000000)
8674       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csl 1-4,10 MBZ");
8675 
8676     DPS8M_ (
8677       // DPS8M raises it delayed
8678       if (mod_fault)
8679           doFault (FAULT_IPR,
8680                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8681                    "Illegal modifier");
8682     )
8683 
8684     e->ADDR1.cPos = (int) e->C1;
8685     e->ADDR2.cPos = (int) e->C2;
8686 
8687     e->ADDR1.bPos = (int) e->B1;
8688     e->ADDR2.bPos = (int) e->B2;
8689 
8690     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8691     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8692 
8693     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8694     bool B5 = !! (BOLR & 8);
8695     bool B6 = !! (BOLR & 4);
8696     bool B7 = !! (BOLR & 2);
8697     bool B8 = !! (BOLR & 1);
8698 
8699     e->ADDR1.mode = eRWreadBit;
8700     e->ADDR2.mode = eRWreadBit;
8701 
8702 #if !defined(EIS_PTR)
8703     sim_debug (DBG_TRACEEXT, & cpu_dev,
8704                "SZTL N1 %d N2 %d\r\n"
8705                "SZTL C1 %d C2 %d B1 %d B2 %d F %o T %d\r\n"
8706                "SZTL BOLR %u%u%u%u\r\n"
8707                "SZTL op1 SNR %06o WORDNO %06o CHAR %d BITNO %d\r\n"
8708                "SZTL op2 SNR %06o WORDNO %06o CHAR %d BITNO %d\r\n",
8709                e -> N1, e -> N2,
8710                e -> C1, e -> C2, e -> B1, e -> B2, F, T,
8711                B5, B6, B7, B8,
8712                e -> addr [0].SNR, e -> addr [0].address,
8713                e -> addr [0].cPos, e -> addr [0].bPos,
8714                e -> addr [1].SNR, e -> addr [1].address,
8715                e -> addr [1].cPos, e -> addr [1].bPos);
8716 #endif
8717 
8718     bool bR = false; // result bit
8719 
8720     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8721                  DU_CYCLE_FLEN_128;))
8722 
8723     for( ; cpu.du.CHTALLY < min (e->N1, e->N2); cpu.du.CHTALLY += 1)
8724     {
8725         tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8726         bool b1 = EISgetBitRWN (cpup, & e->ADDR1, true);
8727         bool b2 = EISgetBitRWN (cpup, & e->ADDR2, true);
8728 
8729         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8730 
8731         if (bR)
8732           {
8733             //CLR_I_ZERO);
8734             cpu.du.Z = 0;
8735             break;
8736           }
8737       }
8738 
8739     if (e->N1 < e->N2)
8740       {
8741         for (; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8742           {
8743             tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8744             bool b1 = F;
8745             bool b2 = EISgetBitRWN (cpup, & e->ADDR2, true);
8746 
8747             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8748 
8749             if (bR)
8750               {
8751                 //CLR_I_ZERO;
8752                 cpu.du.Z = 0;
8753                 break;
8754               }
8755           }
8756       }
8757 
8758     cleanupOperandDescriptor (cpup, 1);
8759     cleanupOperandDescriptor (cpup, 2);
8760 
8761     SC_I_ZERO (cpu.du.Z);
8762     if (e->N1 > e->N2)
8763       {
8764         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8765         // processed and the truncation indicator is set ON.
8766         //
8767         // If T = 1 and the truncation indicator is set ON by execution of the
8768         // instruction, then a truncation (overflow) fault occurs.
8769 
8770         SET_I_TRUNC;
8771         if (T && tstOVFfault (cpup))
8772           doFault(FAULT_OFL, fst_zero, "csl truncation fault");
8773       }
8774     else
8775       {
8776         CLR_I_TRUNC;
8777       }
8778   }
8779 
8780 void sztr (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
8781   {
8782     // The execution of this instruction is identical to the Combine
8783     // Bit Strings Left (csl) instruction except that C(BOLR)m is
8784     // not placed into C(Y-bit2)i-1.
8785 
8786     EISstruct * e = & cpu.currentEISinstruction;
8787 
8788     // For i = bits 1, 2, ..., minimum (N1,N2)
8789     //   m = C(Y-bit1)N1-i || C(Y-bit2)N2-i (a 2-bit number)
8790     //   C(BOLR)m -> C( Y-bit2)N2-i
8791     // If N1 < N2, then for i = N1+i, N1+2, ..., N2
8792     //   m = C(F) || C(Y-bit2)N2-i (a 2-bit number)
8793     //    C(BOLR)m -> C( Y-bit2)N2-i
8794     // INDICATORS: (Indicators not listed are not affected)
8795     //     Zero If C(Y-bit2) = 00...0, then ON; otherwise OFF
8796     //     Truncation If N1 > N2, then ON; otherwise OFF
8797     //
8798     // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8799     // processed and the truncation indicator is set ON.
8800     //
8801     // If T = 1 and the truncation indicator is set ON by execution of the
8802     // instruction, then a truncation (overflow) fault occurs.
8803     //
8804     // BOLR
8805     // If first operand    and    second operand    then result
8806     // bit is:                    bit is:           is from bit:
8807     //        0                          0                      5
8808     //        0                          1                      6
8809     //        1                          0                      7
8810     //        1                          1                      8
8811     //
8812     // The Boolean operations most commonly used are
8813     //                  BOLR Field Bits
8814     // Operation        5      6      7      8
8815     //
8816     // MOVE             0      0      1      1
8817     // AND              0      0      0      1
8818     // OR               0      1      1      1
8819     // NAND             1      1      1      0
8820     // EXCLUSIVE OR     0      1      1      0
8821     // Clear            0      0      0      0
8822     // Invert           1      1      0      0
8823     //
8824 
8825     fault_ipr_subtype_ mod_fault = 0;
8826 
8827 #if !defined(EIS_SETUP)
8828     setupOperandDescriptor(cpup, 1, &mod_fault);
8829     setupOperandDescriptor(cpup, 2, &mod_fault);
8830 #endif
8831 
8832     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
8833     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
8834 
8835     L68_ (
8836       // L68 raises it immediately
8837       if (mod_fault)
8838           doFault (FAULT_IPR,
8839                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8840                    "Illegal modifier");
8841     )
8842 
8843     // Bits 1-4 and 10 MBZ
8844     if (IWB_IRODD & 0360200000000)
8845       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "csr 1-4,10 MBZ");
8846 
8847     DPS8M_ (
8848       // DPS8M raises it delayed
8849       if (mod_fault)
8850           doFault (FAULT_IPR,
8851                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
8852                    "Illegal modifier");
8853     )
8854 
8855     e->ADDR1.cPos = (int) e->C1;
8856     e->ADDR2.cPos = (int) e->C2;
8857 
8858     e->ADDR1.bPos = (int) e->B1;
8859     e->ADDR2.bPos = (int) e->B2;
8860 
8861     // get new char/bit offsets
8862     int numWords1=0, numWords2=0;
8863 
8864     getBitOffsets((int) e->N1, (int) e->C1, (int) e->B1, &numWords1, &e->ADDR1.cPos, &e->ADDR1.bPos);
8865     PNL (cpu.du.D1_PTR_W += (word18) numWords1);
8866     PNL (cpu.du.D1_PTR_W &= AMASK);
8867 #if defined(EIS_PTR)
8868     cpu.du.D1_PTR_W += (word18) numWords1;
8869     cpu.du.D1_PTR_W &= AMASK;
8870 #else
8871     e->ADDR1.address += (word18) numWords1;
8872 #endif
8873 
8874     sim_debug (DBG_TRACEEXT, & cpu_dev,
8875                "CSR N1 %d C1 %d B1 %d numWords1 %d cPos %d bPos %d\r\n",
8876                e->N1, e->C1, e->B1, numWords1, e->ADDR1.cPos, e->ADDR1.bPos);
8877     getBitOffsets((int) e->N2, (int) e->C2, (int) e->B2, &numWords2, &e->ADDR2.cPos, &e->ADDR2.bPos);
8878     sim_debug (DBG_TRACEEXT, & cpu_dev,
8879                "CSR N2 %d C2 %d B2 %d numWords2 %d cPos %d bPos %d\r\n",
8880                e->N2, e->C2, e->B2, numWords2, e->ADDR2.cPos, e->ADDR2.bPos);
8881     PNL (cpu.du.D2_PTR_W += (word18) numWords1);
8882     PNL (cpu.du.D2_PTR_W &= AMASK);
8883 #if defined(EIS_PTR)
8884     cpu.du.D2_PTR_W += (word18) numWords1;
8885     cpu.du.D2_PTR_W &= AMASK;
8886 #else
8887     e->ADDR2.address += (word18) numWords2;
8888 #endif
8889 
8890     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
8891     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;   // T (enablefault) bit
8892 
8893     uint BOLR = getbits36_4 (cpu.cu.IWB, 5);   // T (enablefault) bit
8894     bool B5 = !! (BOLR & 8);
8895     bool B6 = !! (BOLR & 4);
8896     bool B7 = !! (BOLR & 2);
8897     bool B8 = !! (BOLR & 1);
8898 
8899     e->ADDR1.mode = eRWreadBit;
8900 
8901     CLR_I_TRUNC;     // assume N1 <= N2
8902 
8903     bool bR = false; // result bit
8904 
8905     PNL (L68_ (if (max (e->N1, e->N2) < 128)
8906                  DU_CYCLE_FLEN_128;))
8907 
8908     for( ; cpu.du.CHTALLY < min(e->N1, e->N2); cpu.du.CHTALLY += 1)
8909       {
8910         tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8911         bool b1 = EISgetBitRWNR(cpup, &e->ADDR1, true);
8912 
8913         e->ADDR2.mode = eRWreadBit;
8914         bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8915 
8916         if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8917 
8918         if (bR)
8919           {
8920             cpu.du.Z = 0;
8921             break;
8922           }
8923 
8924       }
8925 
8926     if (e->N1 < e->N2)
8927       {
8928         for(; cpu.du.CHTALLY < e->N2; cpu.du.CHTALLY += 1)
8929           {
8930             tandd_eis_sample (cpup, cpu.du.CHTALLY, 36);
8931             bool b1 = F;
8932 
8933             e->ADDR2.mode = eRWreadBit;
8934             bool b2 = EISgetBitRWNR(cpup, &e->ADDR2, true);
8935 
8936             if (b1) if (b2) bR = B8; else bR = B7; else if (b2) bR = B6; else bR = B5;
8937 
8938             if (bR)
8939             {
8940                 //CLR_I_ZERO;
8941                 cpu.du.Z = 0;
8942                 break;
8943             }
8944 
8945           }
8946       }
8947 
8948     cleanupOperandDescriptor (cpup, 1);
8949     cleanupOperandDescriptor (cpup, 2);
8950 
8951     SC_I_ZERO (cpu.du.Z);
8952     if (e->N1 > e->N2)
8953       {
8954         // NOTES: If N1 > N2, the low order (N1-N2) bits of C(Y-bit1) are not
8955         // processed and the truncation indicator is set ON.
8956         //
8957         // If T = 1 and the truncation indicator is set ON by execution of the
8958         // instruction, then a truncation (overflow) fault occurs.
8959 
8960         SET_I_TRUNC;
8961         if (T && tstOVFfault (cpup))
8962           doFault(FAULT_OFL, fst_zero, "csr truncation fault");
8963       }
8964     else
8965       {
8966         CLR_I_TRUNC;
8967       }
8968   }
8969 
8970 /*
8971  * CMPB - Compare Bit Strings
8972  */
8973 
8974 /*
8975  * get a bit from memory ....
8976  */
8977 // XXX this is terribly inefficient, but it'll do for now ......
8978 
8979 static bool EISgetBit(cpu_state_t * cpup, EISaddr *p, int *cpos, int *bpos)
     /* [previous][next][first][last][top][bottom][index][help] */
8980 {
8981 #if defined(EIS_PTR)
8982     long eisaddr_idx = EISADDR_IDX (p);
8983 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
8984 #endif
8985 
8986     if (!p)
8987     {
8988         //lastAddress = -1;
8989         return 0;
8990     }
8991 
8992     if (*bpos > 8)      // bits 0-8
8993     {
8994         *bpos = 0;
8995         *cpos += 1;
8996         if (*cpos > 3)  // chars 0-3
8997         {
8998             *cpos = 0;
8999 #if defined(EIS_PTR)
9000             cpu.du.Dk_PTR_W[eisaddr_idx] += 1;
9001             cpu.du.Dk_PTR_W[eisaddr_idx] &= AMASK;
9002 #else
9003             p->address += 1;
9004             p->address &= AMASK;
9005 #endif
9006         }
9007     }
9008 
9009     p->data = EISRead(cpup, p); // read data word from memory
9010 
9011     int charPosn = *cpos * 9;
9012     int bitPosn = charPosn + *bpos;
9013     bool b = getbits36_1 (p->data, (uint) bitPosn) != 0;
9014 
9015     *bpos += 1;
9016 
9017     return b;
9018 }
9019 
9020 void cmpb (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
9021 {
9022     EISstruct * e = & cpu.currentEISinstruction;
9023 
9024     // For i = 1, 2, ..., minimum (N1,N2)
9025     //   C(Y-bit1)i-1 :: C(Y-bit2)i-1
9026     // If N1 < N2, then for i = N1+1, N1+2, ..., N2
9027     //   C(FILL) :: C(Y-bit2)i-1
9028     // If N1 > N2, then for i = N2+l, N2+2, ..., N1
9029     //   C(Y-bit1)i-1 :: C(FILL)
9030     //
9031     // Indicators:
9032     //    Zero:  If C(Y-bit1)i = C(Y-bit2)i for all i, then ON; otherwise, OFF
9033     //    Carry: If C(Y-bit1)i < C(Y-bit2)i for any i, then OFF; otherwise ON
9034 
9035     fault_ipr_subtype_ mod_fault = 0;
9036 
9037 #if !defined(EIS_SETUP)
9038     setupOperandDescriptor(cpup, 1, &mod_fault);
9039     setupOperandDescriptor(cpup, 2, &mod_fault);
9040 #endif
9041 
9042     parseBitstringOperandDescriptor(cpup, 1, &mod_fault);
9043     parseBitstringOperandDescriptor(cpup, 2, &mod_fault);
9044 
9045     L68_ (
9046       // L68 raises it immediately
9047       if (mod_fault)
9048         {
9049           doFault (FAULT_IPR,
9050                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9051                    "Illegal modifier");
9052         }
9053     )
9054 
9055     // Bits 1-8 and 10 MBZ
9056     if (IWB_IRODD & 0377200000000)
9057       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "cmpb 1-8,10 MBZ");
9058 
9059     DPS8M_ (
9060       // DPS8M raises it delayed
9061       if (mod_fault)
9062         {
9063           doFault (FAULT_IPR,
9064                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9065                    "Illegal modifier");
9066         }
9067     )
9068 
9069     int charPosn1 = (int) e->C1;
9070     int charPosn2 = (int) e->C2;
9071 
9072     int bitPosn1 = (int) e->B1;
9073     int bitPosn2 = (int) e->B2;
9074 
9075     bool F = getbits36_1 (cpu.cu.IWB, 0) != 0;   // fill bit
9076 
9077     SET_I_ZERO;  // assume all =
9078     SET_I_CARRY; // assume all >=
9079 
9080 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb N1 %d N2 %d\r\n", e -> N1, e -> N2);
9081 
9082 
9083 
9084 
9085 
9086 
9087 
9088 
9089 
9090 
9091 
9092 
9093 
9094 
9095 
9096 
9097 
9098     PNL (L68_ (if (max (e->N1, e->N2) < 128)
9099       DU_CYCLE_FLEN_128;))
9100 
9101     uint i = 0;
9102     // T&D: resuming after an interrupt (PM842); bits before CHTALLY
9103     // compared equal
9104     if (cpu.tweaks.tandd_mode)
9105       for ( ; i < cpu.du.CHTALLY; i ++)
9106         {
9107           if (i < e->N1)
9108             (void) EISgetBit (cpup, &e->ADDR1, &charPosn1, &bitPosn1);
9109           if (i < e->N2)
9110             (void) EISgetBit (cpup, &e->ADDR2, &charPosn2, &bitPosn2);
9111         }
9112     for( ; i < min(e->N1, e->N2) ; i += 1)
9113     {
9114         tandd_eis_sample (cpup, i, 36);
9115         bool b1 = EISgetBit (cpup, &e->ADDR1, &charPosn1, &bitPosn1);
9116         bool b2 = EISgetBit (cpup, &e->ADDR2, &charPosn2, &bitPosn2);
9117 
9118 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(min(e->N1, e->N2)) i %d b1 %d b2 %d\r\n", i, b1, b2);
9119         if (b1 != b2)
9120         {
9121             CLR_I_ZERO;
9122             if (!b1 && b2)  // 0 < 1
9123                 CLR_I_CARRY;
9124 
9125             cleanupOperandDescriptor (cpup, 1);
9126             cleanupOperandDescriptor (cpup, 2);
9127 
9128             return;
9129         }
9130 
9131     }
9132     if (e->N1 < e->N2)
9133     {
9134         for(; i < e->N2 ; i += 1)
9135         {
9136             tandd_eis_sample (cpup, i, 36);
9137             bool b1 = F;
9138             bool b2 = EISgetBit(cpup, &e->ADDR2, &charPosn2, &bitPosn2);
9139 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 < e->N2) i %d b1fill %d b2 %d\r\n", i, b1, b2);
9140 
9141             if (b1 != b2)
9142             {
9143                 CLR_I_ZERO;
9144                 if (!b1 && b2)  // 0 < 1
9145                     CLR_I_CARRY;
9146 
9147                 cleanupOperandDescriptor (cpup, 1);
9148                 cleanupOperandDescriptor (cpup, 2);
9149 
9150                 return;
9151             }
9152         }
9153     } else if (e->N1 > e->N2)
9154     {
9155         for(; i < e->N1 ; i += 1)
9156         {
9157             tandd_eis_sample (cpup, i, 36);
9158             bool b1 = EISgetBit(cpup, &e->ADDR1, &charPosn1, &bitPosn1);
9159             bool b2 = F;
9160 sim_debug (DBG_TRACEEXT, & cpu_dev, "cmpb(e->N1 > e->N2) i %d b1 %d b2fill %d\r\n", i, b1, b2);
9161 
9162             if (b1 != b2)
9163             {
9164                 CLR_I_ZERO;
9165                 if (!b1 && b2)  // 0 < 1
9166                     CLR_I_CARRY;
9167 
9168                 cleanupOperandDescriptor (cpup, 1);
9169                 cleanupOperandDescriptor (cpup, 2);
9170 
9171                 return;
9172             }
9173         }
9174     }
9175     cleanupOperandDescriptor (cpup, 1);
9176     cleanupOperandDescriptor (cpup, 2);
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 
9263 
9264 
9265 
9266 
9267 
9268 
9269 
9270 
9271 
9272 
9273 
9274 
9275 
9276 
9277 
9278 
9279 
9280 
9281 
9282 
9283 
9284 
9285 
9286 
9287 
9288 
9289 
9290 
9291 
9292 
9293 
9294 
9295 
9296 
9297 
9298 
9299 
9300 
9301 
9302 
9303 
9304 
9305 
9306 
9307 
9308 
9309 
9310 
9311 
9312 
9313 
9314 
9315 
9316 
9317 
9318 
9319 
9320 
9321 
9322 
9323 
9324 
9325 
9326 
9327 
9328 
9329 
9330 
9331 
9332 
9333 
9334 
9335 
9336 
9337 
9338 
9339 
9340 
9341 
9342 
9343 
9344 
9345 
9346 
9347 
9348 
9349 
9350 
9351 
9352 
9353 
9354 
9355 
9356 
9357 
9358 
9359 
9360 
9361 
9362 
9363 
9364 
9365 
9366 
9367 
9368 
9369 
9370 
9371 
9372 
9373 
9374 
9375 
9376 
9377 
9378 
9379 
9380 
9381 
9382 
9383 
9384 
9385 
9386 
9387 
9388 
9389 
9390 
9391 
9392 
9393 
9394 
9395 
9396 
9397 
9398 
9399 
9400 /*
9401  * determine sign of N*9-bit length word
9402  */
9403 static bool sign9n(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9404 {
9405     // sign bit of  9-bit is bit 8  (1 << 8)
9406     // sign bit of 18-bit is bit 17 (1 << 17)
9407     // .
9408     // .
9409     // .
9410     // sign bit of 72-bit is bit 71 (1 << 71)
9411 
9412     if (N < 1 || N > 8) // XXX largest int we'll play with is 72-bits? Makes sense
9413         return false;
9414 
9415 #if defined(NEED_128)
9416     word72 sgnmask = lshift_128 (construct_128 (0, 1), (uint) (N * 9 - 1));
9417     return isnonzero_128 (and_128 (sgnmask, n128));
9418 #else
9419     word72 sgnmask = (word72)1 << ((N * 9) - 1);
9420 
9421     return (bool)(sgnmask & n128);
9422 #endif /* if defined(NEED_128) */
9423 }
9424 
9425 /*
9426  * sign extend a N*9 length word to a (word72) 128-bit word
9427  */
9428 static word72s signExt9(word72 n128, int N)
     /* [previous][next][first][last][top][bottom][index][help] */
9429 {
9430     // ext mask for  9-bit = 037777777777777777777777777777777777777400  8 0's
9431     // ext mask for 18-bit = 037777777777777777777777777777777777400000 17 0's
9432     // ext mask for 36-bit = 037777777777777777777777777777400000000000 35 0's
9433     // etc...
9434 
9435     int bits = (N * 9) - 1;
9436     if (sign9n(n128, N))
9437     {
9438 #if defined(NEED_128)
9439         uint128 extBits = lshift_128 (construct_128 (MASK64, MASK64), (uint) bits);
9440         uint128 or = or_128 (n128, extBits);
9441         return cast_s128 (or);
9442 #else
9443         uint128 extBits = ((uint128)-1 << bits);
9444         return (word72s) (n128 | extBits);
9445 #endif /* if defined(NEED_128) */
9446     }
9447 #if defined(NEED_128)
9448     uint128 zeroBits = complement_128 (lshift_128 (construct_128 (MASK64, MASK64), (uint) bits));
9449     uint128 and = and_128 (n128, zeroBits);
9450     return cast_s128 (and);
9451 #else
9452     uint128 zeroBits = ~((uint128)-1 << bits);
9453     return (word72s) (n128 & zeroBits);
9454 #endif /* if defined(NEED_128) */
9455 }
9456 
9457 /*
9458  * load a 9*n bit integer into e->x ...
9459  */
9460 
9461 static void load9x(cpu_state_t * cpup, int n, EISaddr *addr, int pos)
     /* [previous][next][first][last][top][bottom][index][help] */
9462 {
9463     EISstruct * e = & cpu.currentEISinstruction;
9464 #if defined(NEED_128)
9465     word72 x = construct_128 (0, 0);
9466 #else
9467     word72 x = 0;
9468 #endif /* if defined(NEED_128) */
9469 #if defined(EIS_PTR)
9470     long eisaddr_idx = EISADDR_IDX (addr);
9471 if (eisaddr_idx < 0 || eisaddr_idx > 2) { sim_warn ("IDX1"); return }
9472 #endif
9473 
9474     word36 data = EISRead(cpup, addr);
9475 
9476     int m = n;
9477     while (m)
9478     {
9479 #if defined(NEED_128)
9480         x = lshift_128 (x, 9);
9481 #else
9482         x <<= 9;         // make room for next 9-bit byte
9483 #endif /* if defined(NEED_128) */
9484 
9485         if (pos > 3)        // overflows to next word?
9486         {   // yep....
9487             pos = 0;        // reset to 1st byte
9488 #if EIS_PTR
9489             cpu.du.Dk_PTR_W[eisaddr_idx] = (cpu.du.Dk_PTR_W[eisaddr_idx] + 1) & AMASK;          // bump source to next address
9490 #else
9491             addr->address = (addr->address + 1) & AMASK;          // bump source to next address
9492 #endif
9493             data = EISRead(cpup, addr);    // read it from memory
9494         }
9495 
9496 #if defined(NEED_128)
9497         x = or_128 (x, construct_128 (0, GETBYTE (data, pos)));
9498 #else
9499         x |= GETBYTE(data, pos);   // fetch byte at position pos and 'or' it in
9500 #endif /* if defined(NEED_128) */
9501 
9502         pos += 1;           // onto next position
9503 
9504         m -= 1;             // decrement byte counter
9505     }
9506     e->x = signExt9(x, n);  // form proper 2's-complement integer
9507 }
9508 
9509 
9510 
9511 
9512 
9513 
9514 
9515 
9516 
9517 
9518 
9519 
9520 
9521 
9522 
9523 
9524 
9525 
9526 
9527 
9528 
9529 
9530 
9531 
9532 
9533 
9534 
9535 
9536 
9537 
9538 
9539 
9540 
9541 
9542 
9543 
9544 
9545 
9546 
9547 
9548 
9549 
9550 
9551 
9552 
9553 
9554 
9555 
9556 
9557 
9558 
9559 
9560 
9561 
9562 
9563 
9564 
9565 
9566 
9567 
9568 
9569 
9570 
9571 
9572 
9573 
9574 
9575 
9576 
9577 
9578 
9579 
9580 
9581 
9582 
9583 
9584 
9585 
9586 
9587 
9588 
9589 
9590 
9591 
9592 
9593 
9594 
9595 
9596 
9597 
9598 
9599 
9600 
9601 
9602 
9603 
9604 
9605 
9606 
9607 
9608 
9609 
9610 
9611 
9612 
9613 
9614 
9615 
9616 
9617 
9618 
9619 
9620 
9621 
9622 
9623 
9624 
9625 
9626 
9627 
9628 
9629 void btd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
9630 {
9631     EISstruct * e = & cpu.currentEISinstruction;
9632 
9633     // C(Y-char91) converted to decimal -> C(Y-charn2)
9634     /*!
9635      * C(Y-char91) contains a twos complement binary integer aligned on 9-bit
9636      * character boundaries with length 0 < N1 <= 8.
9637      *
9638      * If TN2 and S2 specify a 4-bit signed number and P = 1, then if
9639      * C(Y-char91) is positive (bit 0 of C(Y-char91)0 = 0), then the 13(8) plus
9640      * sign character is moved to C(Y-charn2) as appropriate.
9641      *
9642      *   The scaling factor of C(Y-charn2), SF2, must be 0.
9643      *
9644      *   If N2 is not large enough to hold the digits generated by conversion
9645      *   of C(Y-char91) an overflow condition exists; the overflow indicator is
9646      *   set ON and an overflow fault occurs. This implies that an unsigned
9647      *   fixed-point receiving field has a minimum length of 1 character and a
9648      *   signed fixed- point field, 2 characters.
9649      *
9650      * If MFk.RL = 1, then Nk does not contain the operand length; instead; it
9651      * contains a register code for a register holding the operand length.
9652      *
9653      * If MFk.ID = 1, then the kth word following the instruction word does not
9654      * contain an operand descriptor; instead, it contains an indirect pointer
9655      * to the operand descriptor.
9656      *
9657      * C(Y-char91) and C(Y-charn2) may be overlapping strings; no check is made.
9658      *
9659      * Attempted conversion to a floating-point number (S2 = 0) or attempted
9660      * use of a scaling factor (SF2 ≠ 0) causes an illegal procedure fault.
9661      *
9662      * If N1 = 0 or N1 > 8 an illegal procedure fault occurs.
9663      *
9664      * Attempted execution with the xed instruction causes an illegal procedure fault.
9665      *
9666      * Attempted repetition with the rpt, rpd, or rpl instructions causes an illegal procedure fault.
9667      *
9668      */
9669 
9670     // C(string 1) -> C(string 2) (converted)
9671 
9672     // The two's complement binary integer starting at location YC1 is
9673     // converted into a signed string of decimal characters of data type TN2,
9674     // sign and decimal type S2 (S2 = 00 is illegal) and scale factor 0; and is
9675     // stored, right-justified, as a string of length L2 starting at location
9676     // YC2. If the string generated is longer than L2, the high-order excess is
9677     // truncated and the overflow indicator is set. If strings 1 and 2 are not
9678     // overlapped, the contents of string 1 remain unchanged. The length of
9679     // string 1 (L1) is given as the number of 9-bit segments that make up the
9680     // string. L1 is equal to or is less than 8. Thus, the binary string to be
9681     // converted can be 9, 18, 27, 36, 45, 54, 63, or 72 bits long. CN1
9682     // designates a 9-bit character boundary. If P=1, positive signed 4-bit
9683     // results are stored using octal 13 as the plus sign. If P=0, positive
9684     // signed 4-bit results are stored with octal 14 as the plus sign.
9685 
9686     fault_ipr_subtype_ mod_fault = 0;
9687 
9688 #if !defined(EIS_SETUP)
9689     setupOperandDescriptor(cpup, 1, &mod_fault);
9690     setupOperandDescriptor(cpup, 2, &mod_fault);
9691 #endif
9692 
9693     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
9694     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
9695 
9696     L68_ (
9697       // L68 raises it immediately
9698       if (mod_fault)
9699         {
9700           doFault (FAULT_IPR,
9701                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9702                    "Illegal modifier");
9703         }
9704     )
9705 
9706     // Bits 1-10 MBZ
9707     if (IWB_IRODD & 0377600000000)
9708       {
9709         //sim_printf ("sb2d %012"PRIo64"\r\n", IWB_IRODD);
9710         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "btd 0-8 MBZ");
9711       }
9712 
9713     // Bits 21-29 of OP1 MBZ
9714     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000077700)
9715       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op1 21-29 MBZ");
9716 
9717     // Bits 24-29 of OP2 MBZ
9718     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000007700)
9719       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 24-29 MBZ");
9720 
9721     if (e->S[1] == 0)
9722       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "btd op2 S=0");
9723 
9724     DPS8M_ (
9725       // DPS8 raises it delayed
9726       if (mod_fault)
9727         {
9728           doFault (FAULT_IPR,
9729                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
9730                    "Illegal modifier");
9731         }
9732     )
9733 
9734     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
9735 
9736     if (e->N1 == 0 || e->N1 > 8)
9737         doFault(FAULT_IPR, fst_ill_proc, "btd(1): N1 == 0 || N1 > 8");
9738 
9739     uint dstTN = e->TN2;    // type of chars in dst
9740     uint dstCN = e->CN2;    // starting at char pos CN
9741 
9742     int n2 = 0;
9743 
9744     switch(e->S2)
9745     {
9746         case CSLS:
9747         case CSTS:
9748             n2 = (int) e->N2 - 1; // 1 sign
9749             break;
9750 
9751         case CSNS:
9752             n2 = (int) e->N2;     // no sign
9753             break;          // no sign wysiwyg
9754     }
9755 
9756     sim_debug (DBG_CAC, & cpu_dev,
9757       "n2 %d\r\n",
9758       n2);
9759 
9760     if (n2 < 1)
9761         doFault (FAULT_IPR, fst_ill_proc, "btd adjusted n2<1");
9762 
9763     decContext set;
9764     decContextDefaultDPS8(&set);
9765     set.traps=0;
9766 
9767     load9x(cpup, (int) e->N1, &e->ADDR1, (int) e->CN1);
9768 
9769     // handle sign
9770     e->sign = 1;
9771 #if defined(NEED_128)
9772     word72 x = cast_128 (e->x);
9773     if (islt_s128 (e->x, construct_s128 (0, 0)))
9774       {
9775         e->sign = -1;
9776         x = and_128 (negate_128 (x), MASK72);
9777 
9778       }
9779 
9780     // convert to decimal string, workaround missing sprintf uint128
9781     char tmp[32];
9782     tmp[31] = 0;
9783     int i;
9784     for (i=30;i>=0;i--) {
9785         //tmp[i] = x%10 + '0';
9786         //x /= 10;
9787         uint16_t r;
9788         x = divide_128_16 (x, 10, & r);
9789         tmp[i] = (char) r + '0';
9790         if (iszero_128 (x))
9791             break;
9792     }
9793 #else
9794     word72 x = (word72)e->x;
9795     if (e->x < 0) {
9796         e->sign = -1;
9797         //x = (-x) & MASK72;
9798         // ubsan
9799         x = ((word72) (- (word72s) x)) & MASK72;
9800     }
9801 
9802     // convert to decimal string, workaround missing sprintf uint128
9803     char tmp[32];
9804     tmp[31] = 0;
9805     int i;
9806     for (i=30;i>=0;i--) {
9807         tmp[i] = x%10 + '0';
9808         x /= 10;
9809         if (x == 0)
9810             break;
9811     }
9812 #endif /* if defined(NEED_128) */
9813 
9814     decNumber _1;
9815     decNumber *op1 = decNumberFromString(&_1, tmp+i, &set);
9816     if (e->sign == -1)
9817         op1->bits |= DECNEG;
9818 
9819     bool Ovr = false, Trunc = false;
9820 
9821     uint8_t out [256];
9822     char * res = formatDecimal (out, &set, op1, n2, (int) e->S2, e->SF2, 0, &Ovr, &Trunc);
9823 
9824     // now write to memory in proper format.....
9825 
9826     //word18 dstAddr = e->dstAddr;
9827     int pos = (int) dstCN;
9828 
9829     // 1st, take care of any leading sign .......
9830     switch(e->S2)
9831     {
9832         case CSLS:  // fixed-point, leading sign
9833             switch(dstTN)
9834             {
9835                 case CTN4:
9836                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
9837                               //   then the 13(8) plus sign character is placed appropriately
9838                               //   if the result of the operation is positive.
9839                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9840                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 013);  // special +
9841                     else
9842                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9843                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 : 014);  // default +
9844                     break;
9845                 case CTN9:
9846                     EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9847                                (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9848                     break;
9849             }
9850             break;
9851 
9852         case CSTS:  // nuttin' to do here .....
9853         case CSNS:
9854             break;  // no sign wysiwyg
9855     }
9856 
9857     // 2nd, write the digits .....
9858     for(int i = 0 ; i < n2 ; i++)
9859         switch(dstTN)
9860         {
9861             case CTN4:
9862                 EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN, (word9) (res[i] - '0'));
9863                 break;
9864             case CTN9:
9865                 EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN, (word9) res[i]);
9866                 break;
9867         }
9868 
9869     // 3rd, take care of any trailing sign or exponent ...
9870     switch(e->S2)
9871     {
9872         case CSTS:  // write trailing sign ....
9873             switch(dstTN)
9874             {
9875                 case CTN4:
9876                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
9877                               //   then the 13(8) plus sign character is placed appropriately
9878                               //   if the result of the operation is positive.
9879                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9880                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  013);  // special +
9881                     else
9882                         EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9883                                    (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? 015 :  014);  // default +
9884                     break;
9885 
9886                 case CTN9:
9887                     EISwrite49(cpup, &e->ADDR2, &pos, (int) dstTN,
9888                                (decNumberIsNegative(op1) && !decNumberIsZero(op1)) ? '-' : '+');
9889                     break;
9890             }
9891             break;
9892 
9893         case CSLS:  // fixed point, leading sign - already done
9894         case CSNS:  // fixed point, unsigned - nuttin' needed to do
9895             break;
9896     }
9897 
9898     SC_I_NEG (decNumberIsNegative(op1) && !decNumberIsZero(op1));  // set negative indicator if op3 < 0
9899     SC_I_ZERO (decNumberIsZero(op1));     // set zero indicator if op3 == 0
9900 
9901     cleanupOperandDescriptor (cpup, 1);
9902     cleanupOperandDescriptor (cpup, 2);
9903 
9904     if (Ovr)
9905     {
9906         SET_I_OFLOW;
9907         if (tstOVFfault (cpup))
9908           doFault(FAULT_OFL, fst_zero, "btd overflow fault");
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 
9980 
9981 
9982 
9983 
9984 
9985 
9986 
9987 
9988 
9989 
9990 
9991 
9992 
9993 
9994 
9995 
9996 
9997 
9998 
9999 
10000 
10001 
10002 
10003 
10004 
10005 
10006 
10007 
10008 
10009 
10010 
10011 
10012 
10013 
10014 
10015 
10016 
10017 
10018 
10019 
10020 
10021 
10022 
10023 
10024 
10025 
10026 
10027 
10028 
10029 
10030 
10031 
10032 
10033 
10034 
10035 
10036 
10037 
10038 
10039 
10040 
10041 
10042 
10043 
10044 
10045 
10046 
10047 
10048 
10049 
10050 
10051 
10052 
10053 
10054 
10055 
10056 
10057 
10058 
10059 
10060 
10061 
10062 
10063 
10064 
10065 
10066 
10067 
10068 
10069 
10070 
10071 
10072 
10073 
10074 
10075 
10076 
10077 
10078 
10079 
10080 
10081 
10082 
10083 
10084 
10085 
10086 
10087 
10088 
10089 
10090 
10091 
10092 
10093 
10094 
10095 
10096 
10097 
10098 
10099 
10100 
10101 
10102 
10103 
10104 
10105 
10106 
10107 
10108 
10109 
10110 
10111 
10112 
10113 
10114 
10115 
10116 
10117 
10118 void dtb (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10119 {
10120     EISstruct * e = & cpu.currentEISinstruction;
10121 
10122     fault_ipr_subtype_ mod_fault = 0;
10123 
10124 #if !defined(EIS_SETUP)
10125     setupOperandDescriptor(cpup, 1, &mod_fault);
10126     setupOperandDescriptor(cpup, 2, &mod_fault);
10127 #endif
10128 
10129     PNL (L68_ (DU_CYCLE_DGDB;))
10130 
10131     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10132     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10133 
10134     L68_ (
10135       // L68 raises it immediately
10136       if (mod_fault)
10137         {
10138           doFault (FAULT_IPR,
10139                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10140                    "Illegal modifier");
10141         }
10142     )
10143 
10144     // Bits 0 to 10 of the instruction Must Be Zero. So Say We ISOLTS.
10145     uint mbz = (uint) getbits36 (IWB_IRODD, 0, 11);
10146     if (mbz)
10147       {
10148         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dtb(): 0-10 MBZ");
10149       }
10150 
10151     // Bits 24-29 of OP1 MBZ
10152     if (!(e->MF[0] & MFkID) && e -> op [0]  & 0000000007700)
10153       {
10154         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op1 24-29 MBZ");
10155       }
10156 
10157     // Bits 21-29 of OP2 MBZ
10158     if (!(e->MF[1] & MFkID) && e -> op [1]  & 0000000077700)
10159       {
10160         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb op2 21-29 MBZ");
10161        }
10162 
10163     // Attempted conversion of a floating-point number (S1 = 0) or attempted
10164     // use of a scaling factor (SF1 ≠ 0) causes an illegal procedure fault.
10165     if (e->S1 == 0 || e->SF1 != 0)
10166     {
10167         doFault(FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC|mod_fault}, "dtb():  S1=0 or SF1!=0");
10168     }
10169 
10170     DPS8M_ (
10171       // DPS8M raises it delayed
10172       if (mod_fault)
10173         {
10174           doFault (FAULT_IPR,
10175                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10176                    "Illegal modifier");
10177         }
10178     )
10179 
10180     // If N2 = 0 or N2 > 8 an illegal procedure fault occurs.
10181     if (e->N2 == 0 || e->N2 > 8)
10182     {
10183         doFault(FAULT_IPR, fst_ill_proc, "dtb():  N2 = 0 or N2 > 8 etc.");
10184     }
10185 
10186     int n1 = 0;
10187 
10188     /*
10189      * Here we need to distinguish between 4 type of numbers.
10190      *
10191      * CSFL - Floating-point, leading sign
10192      * CSLS - Scaled fixed-point, leading sign
10193      * CSTS - Scaled fixed-point, trailing sign
10194      * CSNS - Scaled fixed-point, unsigned
10195      */
10196 
10197     // determine precision
10198     switch(e->S1)
10199     {
10200         case CSLS:
10201         case CSTS:
10202             n1 = (int) e->N1 - 1; // only 1 sign
10203             break;
10204 
10205         case CSNS:
10206             n1 = (int) e->N1;     // no sign
10207             break;  // no sign wysiwyg
10208     }
10209     // RJ78: An Illegal Procedure fault occurs if:
10210     // N1 is not large enough to specify the number of characters required for the
10211     // specified sign and/or exponent, plus at least one digit.
10212 
10213     if (n1 < 1)
10214         doFault (FAULT_IPR, fst_ill_proc, "dtb adjusted n1<1");
10215 
10216     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10217 
10218     // prepare output mask
10219 #if defined(NEED_128)
10220     word72 msk = subtract_128 (lshift_128 (construct_128 (0, 1), (9*e->N2-1)),construct_128 (0, 1));
10221 #else
10222     word72 msk = ((word72)1<<(9*e->N2-1))-1; // excluding sign
10223 #endif /* if defined(NEED_128) */
10224 
10225 
10226 
10227 
10228 
10229 
10230 
10231 
10232 
10233 
10234 
10235 
10236 
10237 
10238     // input is unscaled fixed point, so just get the digits
10239     bool Ovr = false;
10240 #if defined(NEED_128)
10241     word72 x = construct_128 (0, 0);
10242     for (int i = 0; i < n1; i++) {
10243         //x *= 10;
10244         x = multiply_128 (x, construct_128 (0, 10));
10245         //x += e->inBuffer[i];
10246         x = add_128 (x, construct_128 (0, (uint) e->inBuffer[i]));
10247         //Ovr |= x>msk?1:0;
10248         Ovr |= isgt_128 (x, msk) ? 1 : 0;
10249         //x &= msk; // multiplication and addition mod msk+1
10250         x = and_128 (x, msk); // multiplication and addition mod msk+1
10251     }
10252     if (e->sign == -1)
10253         //x = -x; // no need to mask it
10254         x = negate_128 (x); // no need to mask it
10255 
10256 #else
10257     word72 x = 0;
10258     for (int i = 0; i < n1; i++) {
10259         x *= 10;
10260         x += e->inBuffer[i];
10261         //sim_printf("%d %012"PRIo64" %012"PRIo64"\r\n",e->inBuffer[i],(word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10262         Ovr |= x>msk?1:0;
10263         x &= msk; // multiplication and addition mod msk+1
10264     }
10265     if (e->sign == -1)
10266         //x = -x; // no need to mask it
10267         // ubsan
10268         x = (word72) (- (word72s) x); // no need to mask it
10269 
10270     //sim_printf ("dtb out %012"PRIo64" %012"PRIo64"\r\n", (word36)((x >> 36) & DMASK), (word36)(x & DMASK));
10271 #endif /* if defined(NEED_128) */
10272     int pos = (int)e->CN2;
10273 
10274     // now write to memory in proper format.....
10275 
10276     int shift = 9*((int)e->N2-1);
10277     for(int i = 0; i < (int)e->N2; i++) {
10278 #if defined(NEED_128)
10279         EISwrite9(cpup, &e->ADDR2, &pos, (word9) rshift_128 (x, (uint) shift).l & 0777);
10280 #else
10281         EISwrite9(cpup, &e->ADDR2, &pos, (word9) (x >> shift )& 0777);
10282 #endif /* if defined(NEED_128) */
10283         shift -= 9;
10284     }
10285 
10286     SC_I_NEG (e->sign == -1);  // set negative indicator
10287 #if defined(NEED_128)
10288     SC_I_ZERO (iszero_128 (x)); // set zero indicator
10289 #else
10290     SC_I_ZERO (x==0);     // set zero indicator
10291 #endif /* if defined(NEED_128) */
10292 
10293     cleanupOperandDescriptor (cpup, 1);
10294     cleanupOperandDescriptor (cpup, 2);
10295 
10296     if (Ovr)
10297     {
10298         SET_I_OFLOW;
10299         if (tstOVFfault (cpup))
10300           doFault(FAULT_OFL, fst_zero, "dtb overflow fault");
10301     }
10302 }
10303 
10304 /*
10305  * decimal EIS instructions ...
10306  */
10307 
10308 #define ASC(x)  ((x) + '0')
10309 
10310 /*
10311  * ad2d - Add Using Two Decimal Operands
10312  */
10313 
10314 void ad2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10315 {
10316     EISstruct * e = & cpu.currentEISinstruction;
10317 
10318     fault_ipr_subtype_ mod_fault = 0;
10319 
10320 #if !defined(EIS_SETUP)
10321     setupOperandDescriptor(cpup, 1, &mod_fault);
10322     setupOperandDescriptor(cpup, 2, &mod_fault);
10323     setupOperandDescriptorCache(cpup,3);
10324 #endif
10325 
10326     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10327     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10328 
10329     L68_ (
10330       // L68 raises it immediately
10331       if (mod_fault)
10332         {
10333           doFault (FAULT_IPR,
10334                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10335                    "Illegal modifier");
10336         }
10337     )
10338 
10339     // Bits 1-8 MBZ
10340     if (IWB_IRODD & 0377000000000)
10341       doFault (FAULT_IPR, fst_ill_op, "ad2d 1-8 MBZ");
10342 
10343     DPS8M_ (
10344       // DPS8M raises it delayed
10345       if (mod_fault)
10346         {
10347           doFault (FAULT_IPR,
10348                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10349                    "Illegal modifier");
10350         }
10351     )
10352 
10353     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10354     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10355     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10356 
10357     PNL (L68_ (if (R)
10358       DU_CYCLE_FRND;))
10359 
10360     uint srcTN = e->TN1;    // type of chars in src
10361 
10362     uint dstTN = e->TN2;    // type of chars in dst
10363     uint dstCN = e->CN2;    // starting at char pos CN
10364 
10365     e->ADDR3 = e->ADDR2;
10366 
10367     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
10368 
10369     /*
10370      * Here we need to distinguish between 4 type of numbers.
10371      *
10372      * CSFL - Floating-point, leading sign
10373      * CSLS - Scaled fixed-point, leading sign
10374      * CSTS - Scaled fixed-point, trailing sign
10375      * CSNS - Scaled fixed-point, unsigned
10376      */
10377 
10378     // determine precision
10379     switch(e->S1)
10380     {
10381         case CSFL:
10382             n1 = (int) e->N1 - 1; // need to account for the - sign
10383             if (srcTN == CTN4)
10384                 n1 -= 2;    // 2 4-bit digits exponent
10385             else
10386                 n1 -= 1;    // 1 9-bit digit exponent
10387             sc1 = 0;        // no scaling factor
10388             break;
10389 
10390         case CSLS:
10391         case CSTS:
10392             n1 = (int) e->N1 - 1; // only 1 sign
10393             sc1 = -e->SF1;
10394             break;
10395 
10396         case CSNS:
10397             n1 = (int) e->N1;     // no sign
10398             sc1 = -e->SF1;
10399             break;  // no sign wysiwyg
10400     }
10401 
10402     if (n1 < 1)
10403         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n1<1");
10404 
10405     switch(e->S2)
10406     {
10407         case CSFL:
10408             n2 = (int) e->N2 - 1; // need to account for the sign
10409             if (e->TN2 == CTN4)
10410                 n2 -= 2;    // 2 4-bit digit exponent
10411             else
10412                 n2 -= 1;    // 1 9-bit digit exponent
10413             sc2 = 0;        // no scaling factor
10414             break;
10415 
10416         case CSLS:
10417         case CSTS:
10418             n2 = (int) e->N2 - 1; // 1 sign
10419             sc2 = -e->SF2;
10420             break;
10421 
10422         case CSNS:
10423             n2 = (int) e->N2;     // no sign
10424             sc2 = -e->SF2;
10425             break;  // no sign wysiwyg
10426     }
10427 
10428     if (n2 < 1)
10429         doFault (FAULT_IPR, fst_ill_proc, "ad2d adjusted n2<1");
10430 
10431     decContext set;
10432     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10433     decContextDefaultDPS8(&set);
10434 
10435     set.traps=0;
10436 
10437     decNumber _1, _2, _3;
10438 
10439     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10440 
10441     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10442     if (e->sign == -1)
10443         op1->bits |= DECNEG;
10444     if (e->S1 == CSFL)
10445         op1->exponent = e->exponent;
10446 
10447     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
10448 
10449     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10450     if (e->sign == -1)
10451         op2->bits |= DECNEG;
10452     if (e->S2 == CSFL)
10453         op2->exponent = e->exponent;
10454 
10455     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10456 
10457     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
10458     bool iOvr = 0;
10459     if (op3->digits > 63) {
10460         uint8_t pr[256];
10461         // if sf<=0, trailing zeroes can't be shifted out
10462         // if sf> 0, (some of) trailing zeroes can be shifted out
10463         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10464 
10465         int ctz = 0;
10466         if (sf>0) {     // optimize: we don't care when sf>0
10467             decNumberGetBCD(op3,pr);
10468             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10469                  ctz ++;
10470         }
10471 
10472         if (op3->digits - min(max(sf,0),ctz) > 63) {
10473             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10474             int safe = set.digits;
10475             decNumber tmp;
10476 
10477             // discard MS digits
10478             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10479             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10480             decNumberPlus(&tmp, op3, &set);
10481             set.digits = safe;
10482 
10483             decNumberSubtract(op3, op3, &tmp, &set);
10484 
10485             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\r\n",pr);
10486 
10487             decContextSetRounding(&set, safeR);
10488             iOvr = 1;
10489         }
10490     }
10491 
10492     bool Ovr = false, EOvr = false, Trunc = false;
10493 
10494     uint8_t out [256];
10495     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
10496 
10497     Ovr |= iOvr;
10498 
10499     if (decNumberIsZero(op3))
10500         op3->exponent = 127;
10501 
10502     //(void)printf("%s\r\n", res);
10503 
10504     // now write to memory in proper format.....
10505 
10506     //word18 dstAddr = e->dstAddr;
10507     int pos = (int) dstCN;
10508 
10509     // 1st, take care of any leading sign .......
10510     switch(e->S2)
10511     {
10512         case CSFL:  // floating-point, leading sign.
10513         case CSLS:  // fixed-point, leading sign
10514             switch(dstTN)
10515             {
10516                 case CTN4:
10517                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10518                               //   then the 13(8) plus sign character is placed appropriately
10519                               //   if the result of the operation is positive.
10520                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10521                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10522                     else
10523                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10524                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10525                     break;
10526                 case CTN9:
10527                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10528                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10529                     break;
10530             }
10531             break;
10532 
10533         case CSTS:  // nuttin' to do here .....
10534         case CSNS:
10535             break;  // no sign wysiwyg
10536     }
10537 
10538     // 2nd, write the digits .....
10539     for(int j = 0 ; j < n2 ; j++)
10540         switch(dstTN)
10541         {
10542             case CTN4:
10543                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[j] - '0'));
10544                 break;
10545             case CTN9:
10546                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[j]);
10547                 break;
10548         }
10549 
10550     // 3rd, take care of any trailing sign or exponent ...
10551     switch(e->S2)
10552     {
10553         case CSTS:  // write trailing sign ....
10554             switch(dstTN)
10555             {
10556                 case CTN4:
10557                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10558                               //   then the 13(8) plus sign character is placed appropriately
10559                               //   if the result of the operation is positive.
10560                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10561                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10562                     else
10563                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10564                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10565                     break;
10566                 case CTN9:
10567                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10568                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10569                     break;
10570             }
10571             break;
10572 
10573         case CSFL:  // floating-point, leading sign.
10574             // write the exponent
10575             switch(dstTN)
10576             {
10577                 case CTN4:
10578                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10579                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10580                     break;
10581                 case CTN9:
10582                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10583                     break;
10584             }
10585             break;
10586 
10587         case CSLS:  // fixed point, leading sign - already done
10588         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10589             break;
10590     }
10591 
10592     // set flags, etc ...
10593     if (e->S2 == CSFL)
10594     {
10595         if (op3->exponent > 127)
10596         {
10597             SET_I_EOFL;
10598             EOvr = true;
10599         }
10600         if (op3->exponent < -128)
10601         {
10602             SET_I_EUFL;
10603             EOvr = true;
10604         }
10605     }
10606 
10607     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
10608     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
10609 
10610     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
10611 
10612     cleanupOperandDescriptor (cpup, 1);
10613     cleanupOperandDescriptor (cpup, 2);
10614     cleanupOperandDescriptor (cpup, 3);
10615 
10616     if (TST_I_TRUNC && T && tstOVFfault (cpup))
10617       doFault(FAULT_OFL, fst_zero, "ad2d truncation(overflow) fault");
10618     if (EOvr && tstOVFfault (cpup))
10619         doFault(FAULT_OFL, fst_zero, "ad2d over/underflow fault");
10620     if (Ovr)
10621     {
10622         SET_I_OFLOW;
10623         if (tstOVFfault (cpup))
10624           doFault(FAULT_OFL, fst_zero, "ad2d overflow fault");
10625     }
10626 }
10627 
10628 
10629 
10630 
10631 
10632 
10633 
10634 
10635 
10636 
10637 
10638 
10639 
10640 
10641 
10642 
10643 
10644 
10645 
10646 
10647 
10648 
10649 
10650 
10651 
10652 
10653 
10654 
10655 
10656 
10657 
10658 
10659 
10660 
10661 
10662 
10663 
10664 
10665 
10666 
10667 
10668 
10669 /*
10670  * ad3d - Add Using Three Decimal Operands
10671  */
10672 
10673 void ad3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
10674 {
10675     EISstruct * e = & cpu.currentEISinstruction;
10676 
10677     fault_ipr_subtype_ mod_fault = 0;
10678 
10679 #if !defined(EIS_SETUP)
10680     setupOperandDescriptor(cpup, 1, &mod_fault);
10681     setupOperandDescriptor(cpup, 2, &mod_fault);
10682     setupOperandDescriptor(cpup, 3, &mod_fault);
10683 #endif
10684 
10685     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
10686     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
10687     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
10688 
10689     L68_ (
10690       // L68 raises it immediately
10691       if (mod_fault)
10692         {
10693           doFault (FAULT_IPR,
10694                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10695                    "Illegal modifier");
10696         }
10697     )
10698 
10699     // Bit 1 MBZ
10700     if (IWB_IRODD & 0200000000000)
10701       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "ad3d(): 1 MBZ");
10702 
10703     DPS8M_ (
10704       // DPS8M raises it delayed
10705       if (mod_fault)
10706         {
10707           doFault (FAULT_IPR,
10708                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
10709                    "Illegal modifier");
10710         }
10711     )
10712 
10713     // initialize mop flags. Probably best done elsewhere.
10714     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
10715     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
10716     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
10717 
10718     PNL (L68_ (if (R)
10719       DU_CYCLE_FRND;))
10720 
10721     uint srcTN = e->TN1;    // type of chars in src
10722 
10723     uint dstTN = e->TN3;    // type of chars in dst
10724     uint dstCN = e->CN3;    // starting at char pos CN
10725 
10726     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
10727 
10728     /*
10729      * Here we need to distinguish between 4 type of numbers.
10730      *
10731      * CSFL - Floating-point, leading sign
10732      * CSLS - Scaled fixed-point, leading sign
10733      * CSTS - Scaled fixed-point, trailing sign
10734      * CSNS - Scaled fixed-point, unsigned
10735      */
10736 
10737     // determine precision
10738     switch(e->S1)
10739     {
10740         case CSFL:
10741             n1 = (int) e->N1 - 1; // need to account for the - sign
10742             if (srcTN == CTN4)
10743                 n1 -= 2;    // 2 4-bit digits exponent
10744             else
10745                 n1 -= 1;    // 1 9-bit digit exponent
10746             sc1 = 0;        // no scaling factor
10747             break;
10748 
10749         case CSLS:
10750         case CSTS:
10751             n1 = (int) e->N1 - 1; // only 1 sign
10752             sc1 = -e->SF1;
10753             break;
10754 
10755         case CSNS:
10756             n1 = (int) e->N1;     // no sign
10757             sc1 = -e->SF1;
10758             break;  // no sign wysiwyg
10759     }
10760 
10761     if (n1 < 1)
10762         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n1<1");
10763 
10764     switch(e->S2)
10765     {
10766         case CSFL:
10767             n2 = (int) e->N2 - 1; // need to account for the sign
10768             if (e->TN2 == CTN4)
10769                 n2 -= 2;    // 2 4-bit digit exponent
10770             else
10771                 n2 -= 1;    // 1 9-bit digit exponent
10772             sc2 = 0;        // no scaling factor
10773             break;
10774 
10775         case CSLS:
10776         case CSTS:
10777             n2 = (int) e->N2 - 1; // 1 sign
10778             sc2 = -e->SF2;
10779             break;
10780 
10781         case CSNS:
10782             n2 = (int) e->N2;     // no sign
10783             sc2 = -e->SF2;
10784             break;  // no sign wysiwyg
10785     }
10786 
10787     if (n2 < 1)
10788         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n2<1");
10789 
10790     switch(e->S3)
10791     {
10792         case CSFL:
10793             n3 = (int) e->N3 - 1; // need to account for the sign
10794             if (dstTN == CTN4)
10795                 n3 -= 2;    // 2 4-bit digit exponent
10796             else
10797                 n3 -= 1;    // 1 9-bit digit exponent
10798             break;
10799 
10800         case CSLS:
10801         case CSTS:
10802             n3 = (int) e->N3 - 1; // 1 sign
10803             break;
10804 
10805         case CSNS:
10806             n3 = (int) e->N3;     // no sign
10807             break;  // no sign wysiwyg
10808     }
10809 
10810     if (n3 < 1)
10811         doFault (FAULT_IPR, fst_ill_proc, "ad3d adjusted n3<1");
10812 
10813     decContext set;
10814     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
10815     decContextDefaultDPS8(&set);
10816     set.traps=0;
10817 
10818     decNumber _1, _2, _3;
10819 
10820     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
10821 
10822     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
10823     if (e->sign == -1)
10824         op1->bits |= DECNEG;
10825     if (e->S1 == CSFL)
10826         op1->exponent = e->exponent;
10827 
10828     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
10829 
10830     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
10831     if (e->sign == -1)
10832         op2->bits |= DECNEG;
10833     if (e->S2 == CSFL)
10834         op2->exponent = e->exponent;
10835 
10836     decNumber *op3 = decNumberAdd(&_3, op1, op2, &set);
10837 
10838     // RJ78: significant digits in the result may be lost if:
10839     // The difference between the scaling factors (exponents) of the source
10840     // operands is large enough to cause the expected length of the intermediate
10841     // result to exceed 63 digits after decimal point alignment of source operands, followed by addition.
10842     // ISOLTS 846 07c, 10a, 11b internal register overflow
10843     // trailing zeros are not counted towards the limit
10844 
10845     // XXX it is not clear which digits are lost, but I suppose it should be the most significant.
10846     // ISOLTS doesn't check for this.
10847 
10848     // XXX the algorithm should be similar/the same as dv3d NQ? It is to some extent already...
10849     bool iOvr = 0;
10850     if (op3->digits > 63) {
10851         uint8_t pr[256];
10852         // if sf<=0, trailing zeroes can't be shifted out
10853         // if sf> 0, (some of) trailing zeroes can be shifted out
10854         int sf = e->S3==CSFL?op3->exponent:e->SF3;
10855 
10856         int ctz = 0;
10857         if (sf>0) {     // optimize: we don't care when sf>0
10858             decNumberGetBCD(op3,pr);
10859             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
10860                  ctz ++;
10861         }
10862 
10863         if (op3->digits - min(max(sf,0),ctz) > 63) {
10864             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
10865             int safe = set.digits;
10866             decNumber tmp;
10867 
10868             // discard MS digits
10869             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
10870             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
10871             decNumberPlus(&tmp, op3, &set);
10872             set.digits = safe;
10873 
10874             decNumberSubtract(op3, op3, &tmp, &set);
10875 
10876             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\r\n",pr);
10877 
10878             decContextSetRounding(&set, safeR);
10879             iOvr = 1;
10880         }
10881     }
10882 
10883     bool Ovr = false, EOvr = false, Trunc = false;
10884 
10885     uint8_t out [256];
10886     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
10887 
10888     Ovr |= iOvr;
10889 
10890     if (decNumberIsZero(op3))
10891         op3->exponent = 127;
10892 
10893     //(void)printf("%s\r\n", res);
10894 
10895     // now write to memory in proper format.....
10896 
10897     //word18 dstAddr = e->dstAddr;
10898     int pos = (int) dstCN;
10899 
10900     // 1st, take care of any leading sign .......
10901     switch(e->S3)
10902     {
10903         case CSFL:  // floating-point, leading sign.
10904         case CSLS:  // fixed-point, leading sign
10905             switch(dstTN)
10906             {
10907             case CTN4:
10908                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10909                           //   then the 13(8) plus sign character is placed appropriately
10910                           //   if the result of the operation is positive.
10911                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10912                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10913                 else
10914                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10915                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10916                 break;
10917             case CTN9:
10918                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10919                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10920                 break;
10921             }
10922             break;
10923 
10924         case CSTS:  // nuttin' to do here .....
10925         case CSNS:
10926             break;  // no sign wysiwyg
10927     }
10928 
10929     // 2nd, write the digits .....
10930     for(int i = 0 ; i < n3 ; i++)
10931         switch(dstTN)
10932         {
10933         case CTN4:
10934             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
10935             break;
10936         case CTN9:
10937             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
10938             break;
10939         }
10940 
10941     // 3rd, take care of any trailing sign or exponent ...
10942     switch(e->S3)
10943     {
10944         case CSTS:  // write trailing sign ....
10945             switch(dstTN)
10946             {
10947             case CTN4:
10948                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
10949                           //   then the 13(8) plus sign character is placed appropriately
10950                           //   if the result of the operation is positive.
10951                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10952                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
10953                 else
10954                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10955                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
10956                 break;
10957             case CTN9:
10958                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
10959                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
10960                 break;
10961             }
10962             break;
10963 
10964         case CSFL:  // floating-point, leading sign.
10965             // write the exponent
10966             switch(dstTN)
10967             {
10968             case CTN4:
10969                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
10970                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
10971 
10972                     break;
10973             case CTN9:
10974                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
10975                 break;
10976             }
10977             break;
10978 
10979         case CSLS:  // fixed point, leading sign - already done
10980         case CSNS:  // fixed point, unsigned - nuttin' needed to do
10981             break;
10982     }
10983 
10984     // set flags, etc ...
10985     if (e->S3 == CSFL)
10986     {
10987         if (op3->exponent > 127)
10988         {
10989             SET_I_EOFL;
10990             EOvr = true;
10991         }
10992         if (op3->exponent < -128)
10993         {
10994             SET_I_EUFL;
10995             EOvr = true;
10996         }
10997     }
10998 
10999     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11000     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11001 
11002     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11003 
11004     cleanupOperandDescriptor (cpup, 1);
11005     cleanupOperandDescriptor (cpup, 2);
11006     cleanupOperandDescriptor (cpup, 3);
11007 
11008     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11009       doFault(FAULT_OFL, fst_zero, "ad3d truncation(overflow) fault");
11010     if (EOvr && tstOVFfault (cpup))
11011         doFault(FAULT_OFL, fst_zero, "ad3d over/underflow fault");
11012     if (Ovr)
11013     {
11014         SET_I_OFLOW;
11015         if (tstOVFfault (cpup))
11016           doFault(FAULT_OFL, fst_zero, "ad3d overflow fault");
11017     }
11018 }
11019 
11020 /*
11021  * sb2d - Subtract Using Two Decimal Operands
11022  */
11023 
11024 void sb2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11025 {
11026     EISstruct * e = & cpu.currentEISinstruction;
11027 
11028     fault_ipr_subtype_ mod_fault = 0;
11029 
11030 #if !defined(EIS_SETUP)
11031     setupOperandDescriptor(cpup, 1, &mod_fault);
11032     setupOperandDescriptor(cpup, 2, &mod_fault);
11033     setupOperandDescriptorCache(cpup,3);
11034 #endif
11035 
11036     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11037     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11038 
11039     L68_ (
11040       // L68 raises it immediately
11041       if (mod_fault)
11042         {
11043           doFault (FAULT_IPR,
11044                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11045                    "Illegal modifier");
11046         }
11047     )
11048 
11049     // Bits 1-8 MBZ
11050     if (IWB_IRODD & 0377000000000)
11051       {
11052         //sim_printf ("sb2d %012"PRIo64"\r\n", IWB_IRODD);
11053         doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb2d 0-8 MBZ");
11054       }
11055 
11056     DPS8M_ (
11057       // DPS8M raises it delayed
11058       if (mod_fault)
11059         {
11060           doFault (FAULT_IPR,
11061                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11062                    "Illegal modifier");
11063         }
11064     )
11065 
11066     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11067     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11068     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11069 
11070     PNL (L68_ (if (R)
11071       DU_CYCLE_FRND;))
11072 
11073     uint srcTN = e->TN1;    // type of chars in src
11074 
11075     uint dstTN = e->TN2;    // type of chars in dst
11076     uint dstCN = e->CN2;    // starting at char pos CN
11077 
11078     e->ADDR3 = e->ADDR2;
11079 
11080     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
11081 
11082     /*
11083      * Here we need to distinguish between 4 type of numbers.
11084      *
11085      * CSFL - Floating-point, leading sign
11086      * CSLS - Scaled fixed-point, leading sign
11087      * CSTS - Scaled fixed-point, trailing sign
11088      * CSNS - Scaled fixed-point, unsigned
11089      */
11090 
11091     // determine precision
11092     switch(e->S1)
11093     {
11094         case CSFL:
11095             n1 = (int) e->N1 - 1; // need to account for the - sign
11096             if (srcTN == CTN4)
11097                 n1 -= 2;    // 2 4-bit digits exponent
11098             else
11099                 n1 -= 1;    // 1 9-bit digit exponent
11100             sc1 = 0;        // no scaling factor
11101             break;
11102 
11103         case CSLS:
11104         case CSTS:
11105             n1 = (int) e->N1 - 1; // only 1 sign
11106             sc1 = -e->SF1;
11107             break;
11108 
11109         case CSNS:
11110             n1 = (int) e->N1;     // no sign
11111             sc1 = -e->SF1;
11112             break;  // no sign wysiwyg
11113     }
11114 
11115     if (n1 < 1)
11116         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n1<1");
11117 
11118     switch(e->S2)
11119     {
11120         case CSFL:
11121             n2 = (int) e->N2 - 1; // need to account for the sign
11122             if (e->TN2 == CTN4)
11123                 n2 -= 2;    // 2 4-bit digit exponent
11124             else
11125                 n2 -= 1;    // 1 9-bit digit exponent
11126             sc2 = 0;        // no scaling factor
11127             break;
11128 
11129         case CSLS:
11130         case CSTS:
11131             n2 = (int) e->N2 - 1; // 1 sign
11132             sc2 = -e->SF2;
11133             break;
11134 
11135         case CSNS:
11136             n2 = (int) e->N2;     // no sign
11137             sc2 = -e->SF2;
11138             break;  // no sign wysiwyg
11139     }
11140 
11141     if (n2 < 1)
11142         doFault (FAULT_IPR, fst_ill_proc, "sb2d adjusted n2<1");
11143 
11144     decContext set;
11145     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11146     decContextDefaultDPS8(&set);
11147     set.traps=0;
11148 
11149     decNumber _1, _2, _3;
11150 
11151     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11152 
11153     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11154     if (e->sign == -1)
11155         op1->bits |= DECNEG;
11156     if (e->S1 == CSFL)
11157         op1->exponent = e->exponent;
11158 
11159     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11160 
11161     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11162     if (e->sign == -1)
11163         op2->bits |= DECNEG;
11164     if (e->S2 == CSFL)
11165         op2->exponent = e->exponent;
11166 
11167     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11168 
11169     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11170     bool iOvr = 0;
11171     if (op3->digits > 63) {
11172         uint8_t pr[256];
11173         // if sf<=0, trailing zeroes can't be shifted out
11174         // if sf> 0, (some of) trailing zeroes can be shifted out
11175         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11176 
11177         int ctz = 0;
11178         if (sf>0) {     // optimize: we don't care when sf>0
11179             decNumberGetBCD(op3,pr);
11180             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11181                  ctz ++;
11182         }
11183 
11184         if (op3->digits - min(max(sf,0),ctz) > 63) {
11185             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11186             int safe = set.digits;
11187             decNumber tmp;
11188 
11189             // discard MS digits
11190             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11191             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11192             decNumberPlus(&tmp, op3, &set);
11193             set.digits = safe;
11194 
11195             decNumberSubtract(op3, op3, &tmp, &set);
11196 
11197             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\r\n",pr);
11198 
11199             decContextSetRounding(&set, safeR);
11200             iOvr = 1;
11201         }
11202     }
11203 
11204     bool Ovr = false, EOvr = false, Trunc = false;
11205 
11206     uint8_t out [256];
11207     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11208 
11209     Ovr |= iOvr;
11210 
11211     if (decNumberIsZero(op3))
11212         op3->exponent = 127;
11213 
11214     //(void)printf("%s\r\n", res);
11215 
11216     // now write to memory in proper format.....
11217 
11218     //word18 dstAddr = e->dstAddr;
11219     int pos = (int) dstCN;
11220 
11221     // 1st, take care of any leading sign .......
11222     switch(e->S2)
11223     {
11224         case CSFL:  // floating-point, leading sign.
11225         case CSLS:  // fixed-point, leading sign
11226             switch(dstTN)
11227             {
11228                 case CTN4:
11229                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11230                               //   then the 13(8) plus sign character is placed appropriately
11231                               //   if the result of the operation is positive.
11232                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11233                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11234                     else
11235                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11236                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11237                     break;
11238                 case CTN9:
11239                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11240                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11241                     break;
11242             }
11243             break;
11244 
11245         case CSTS:  // nuttin' to do here .....
11246         case CSNS:
11247             break;  // no sign wysiwyg
11248     }
11249 
11250     // 2nd, write the digits .....
11251     for(int i = 0 ; i < n2 ; i++)
11252         switch(dstTN)
11253         {
11254             case CTN4:
11255                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11256                 break;
11257             case CTN9:
11258                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11259                 break;
11260         }
11261 
11262     // 3rd, take care of any trailing sign or exponent ...
11263     switch(e->S2)
11264     {
11265         case CSTS:  // write trailing sign ....
11266             switch(dstTN)
11267             {
11268                 case CTN4:
11269                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11270                               //   then the 13(8) plus sign character is placed appropriately
11271                               //   if the result of the operation is positive.
11272                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11273                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11274                     else
11275                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11276                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11277                     break;
11278                 case CTN9:
11279                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11280                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11281                     break;
11282             }
11283             break;
11284 
11285         case CSFL:  // floating-point, leading sign.
11286             // write the exponent
11287             switch(dstTN)
11288             {
11289                 case CTN4:
11290                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11291                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11292 
11293                     break;
11294                 case CTN9:
11295                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11296                     break;
11297             }
11298             break;
11299 
11300         case CSLS:  // fixed point, leading sign - already done
11301         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11302             break;
11303     }
11304 
11305     // set flags, etc ...
11306     if (e->S2 == CSFL)
11307     {
11308         if (op3->exponent > 127)
11309         {
11310             SET_I_EOFL;
11311             EOvr = true;
11312         }
11313         if (op3->exponent < -128)
11314         {
11315             SET_I_EUFL;
11316             EOvr = true;
11317         }
11318     }
11319 
11320     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11321     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11322 
11323     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11324 
11325     cleanupOperandDescriptor (cpup, 1);
11326     cleanupOperandDescriptor (cpup, 2);
11327     cleanupOperandDescriptor (cpup, 3);
11328 
11329     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11330       doFault(FAULT_OFL, fst_zero, "sb2d truncation(overflow) fault");
11331     if (EOvr && tstOVFfault (cpup))
11332         doFault(FAULT_OFL, fst_zero, "sb2d over/underflow fault");
11333     if (Ovr)
11334     {
11335         SET_I_OFLOW;
11336         if (tstOVFfault (cpup))
11337           doFault(FAULT_OFL, fst_zero, "sb2d overflow fault");
11338     }
11339 }
11340 
11341 /*
11342  * sb3d - Subtract Using Three Decimal Operands
11343  */
11344 
11345 void sb3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11346 {
11347     EISstruct * e = & cpu.currentEISinstruction;
11348 
11349     fault_ipr_subtype_ mod_fault = 0;
11350 
11351 #if !defined(EIS_SETUP)
11352     setupOperandDescriptor(cpup, 1, &mod_fault);
11353     setupOperandDescriptor(cpup, 2, &mod_fault);
11354     setupOperandDescriptor(cpup, 3, &mod_fault);
11355 #endif
11356 
11357     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11358     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11359     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
11360 
11361     L68_ (
11362       // L68 raises it immediately
11363       if (mod_fault)
11364         {
11365           doFault (FAULT_IPR,
11366                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11367                    "Illegal modifier");
11368         }
11369     )
11370 
11371     // Bit 1 MBZ
11372     if (IWB_IRODD & 0200000000000)
11373       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "sb3d(): 1 MBZ");
11374 
11375     DPS8M_ (
11376       // DPS8M raises it delayed
11377       if (mod_fault)
11378         {
11379           doFault (FAULT_IPR,
11380                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11381                    "Illegal modifier");
11382         }
11383     )
11384 
11385     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11386     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11387     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11388 
11389     PNL (L68_ (if (R)
11390       DU_CYCLE_FRND;))
11391 
11392     uint srcTN = e->TN1;    // type of chars in src
11393 
11394     uint dstTN = e->TN3;    // type of chars in dst
11395     uint dstCN = e->CN3;    // starting at char pos CN
11396 
11397     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
11398 
11399     /*
11400      * Here we need to distinguish between 4 type of numbers.
11401      *
11402      * CSFL - Floating-point, leading sign
11403      * CSLS - Scaled fixed-point, leading sign
11404      * CSTS - Scaled fixed-point, trailing sign
11405      * CSNS - Scaled fixed-point, unsigned
11406      */
11407 
11408     // determine precision
11409     switch(e->S1)
11410     {
11411         case CSFL:
11412             n1 = (int) e->N1 - 1; // need to account for the - sign
11413             if (srcTN == CTN4)
11414                 n1 -= 2;    // 2 4-bit digits exponent
11415             else
11416                 n1 -= 1;    // 1 9-bit digit exponent
11417             sc1 = 0;        // no scaling factor
11418             break;
11419 
11420         case CSLS:
11421         case CSTS:
11422             n1 = (int) e->N1 - 1; // only 1 sign
11423             sc1 = -e->SF1;
11424             break;
11425 
11426         case CSNS:
11427             n1 = (int) e->N1;     // no sign
11428             sc1 = -e->SF1;
11429             break;  // no sign wysiwyg
11430     }
11431 
11432     if (n1 < 1)
11433         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n1<1");
11434 
11435     switch(e->S2)
11436     {
11437         case CSFL:
11438             n2 = (int) e->N2 - 1; // need to account for the sign
11439             if (e->TN2 == CTN4)
11440                 n2 -= 2;    // 2 4-bit digit exponent
11441             else
11442                 n2 -= 1;    // 1 9-bit digit exponent
11443             sc2 = 0;        // no scaling factor
11444             break;
11445 
11446         case CSLS:
11447         case CSTS:
11448             n2 = (int) e->N2 - 1; // 1 sign
11449             sc2 = -e->SF2;
11450             break;
11451 
11452         case CSNS:
11453             n2 = (int) e->N2;     // no sign
11454             sc2 = -e->SF2;
11455             break;  // no sign wysiwyg
11456     }
11457 
11458     if (n2 < 1)
11459         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n2<1");
11460 
11461     switch(e->S3)
11462     {
11463         case CSFL:
11464             n3 = (int) e->N3 - 1; // need to account for the sign
11465             if (dstTN == CTN4)
11466                 n3 -= 2;    // 2 4-bit digit exponent
11467             else
11468                 n3 -= 1;    // 1 9-bit digit exponent
11469             break;
11470 
11471         case CSLS:
11472         case CSTS:
11473             n3 = (int) e->N3 - 1; // 1 sign
11474             break;
11475 
11476         case CSNS:
11477             n3 = (int) e->N3;     // no sign
11478             break;  // no sign wysiwyg
11479     }
11480 
11481     if (n3 < 1)
11482         doFault (FAULT_IPR, fst_ill_proc, "sb3d adjusted n3<1");
11483 
11484     decContext set;
11485     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
11486     decContextDefaultDPS8(&set);
11487 
11488     set.traps=0;
11489 
11490     decNumber _1, _2, _3;
11491 
11492     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11493 
11494     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11495     if (e->sign == -1)
11496         op1->bits |= DECNEG;
11497     if (e->S1 == CSFL)
11498         op1->exponent = e->exponent;
11499 
11500     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11501 
11502     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11503     if (e->sign == -1)
11504         op2->bits |= DECNEG;
11505     if (e->S2 == CSFL)
11506         op2->exponent = e->exponent;
11507 
11508     decNumber *op3 = decNumberSubtract(&_3, op2, op1, &set);
11509 
11510     // ISOLTS 846 07c, 10a, 11b internal register overflow - see ad3d
11511     bool iOvr = 0;
11512     if (op3->digits > 63) {
11513         uint8_t pr[256];
11514         // if sf<=0, trailing zeroes can't be shifted out
11515         // if sf> 0, (some of) trailing zeroes can be shifted out
11516         int sf = e->S3==CSFL?op3->exponent:e->SF3;
11517 
11518         int ctz = 0;
11519         if (sf>0) {     // optimize: we don't care when sf>0
11520             decNumberGetBCD(op3,pr);
11521             for (int i=op3->digits-1;i>=0 && pr[i]==0;i--)
11522                  ctz ++;
11523         }
11524 
11525         if (op3->digits - min(max(sf,0),ctz) > 63) {
11526             enum rounding safeR = decContextGetRounding(&set);         // save rounding mode
11527             int safe = set.digits;
11528             decNumber tmp;
11529 
11530             // discard MS digits
11531             decContextSetRounding(&set, DEC_ROUND_DOWN);     // Round towards 0 (truncation).
11532             set.digits = op3->digits - min(max(sf,0),ctz) - 63;
11533             decNumberPlus(&tmp, op3, &set);
11534             set.digits = safe;
11535 
11536             decNumberSubtract(op3, op3, &tmp, &set);
11537 
11538             //decNumberToString(op3,(char*)pr); sim_printf("discarded: %s\r\n",pr);
11539 
11540             decContextSetRounding(&set, safeR);
11541             iOvr = 1;
11542         }
11543     }
11544 
11545     bool Ovr = false, EOvr = false, Trunc = false;
11546 
11547     uint8_t out [256];
11548     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
11549 
11550     Ovr |= iOvr;
11551 
11552     if (decNumberIsZero(op3))
11553         op3->exponent = 127;
11554 
11555     // now write to memory in proper format.....
11556 
11557     //word18 dstAddr = e->dstAddr;
11558     int pos = (int) dstCN;
11559 
11560     // 1st, take care of any leading sign .......
11561     switch(e->S3)
11562     {
11563         case CSFL:  // floating-point, leading sign.
11564         case CSLS:  // fixed-point, leading sign
11565             switch(dstTN)
11566         {
11567             case CTN4:
11568                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11569                           //   then the 13(8) plus sign character is placed appropriately
11570                           //   if the result of the operation is positive.
11571                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11572                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11573                 else
11574                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11575                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11576                 break;
11577             case CTN9:
11578                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11579                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11580                 break;
11581         }
11582             break;
11583 
11584         case CSTS:  // nuttin' to do here .....
11585         case CSNS:
11586             break;  // no sign wysiwyg
11587     }
11588 
11589     // 2nd, write the digits .....
11590     for(int i = 0 ; i < n3 ; i++)
11591         switch(dstTN)
11592     {
11593         case CTN4:
11594             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11595             break;
11596         case CTN9:
11597             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11598             break;
11599     }
11600 
11601     // 3rd, take care of any trailing sign or exponent ...
11602     switch(e->S3)
11603     {
11604         case CSTS:  // write trailing sign ....
11605             switch(dstTN)
11606             {
11607                 case CTN4:
11608                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11609                               //   then the 13(8) plus sign character is placed appropriately
11610                               //   if the result of the operation is positive.
11611                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11612                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11613                     else
11614                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11615                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11616                     break;
11617                 case CTN9:
11618                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11619                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11620                     break;
11621             }
11622             break;
11623 
11624         case CSFL:  // floating-point, leading sign.
11625             // write the exponent
11626             switch(dstTN)
11627             {
11628                 case CTN4:
11629                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11630                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11631 
11632                     break;
11633                 case CTN9:
11634                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11635                     break;
11636             }
11637             break;
11638 
11639         case CSLS:  // fixed point, leading sign - already done
11640         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11641             break;
11642     }
11643 
11644     // set flags, etc ...
11645     if (e->S3 == CSFL)
11646     {
11647         if (op3->exponent > 127)
11648         {
11649             SET_I_EOFL;
11650             EOvr = true;
11651         }
11652         if (op3->exponent < -128)
11653         {
11654             SET_I_EUFL;
11655             EOvr = true;
11656         }
11657     }
11658 
11659     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11660     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11661 
11662     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11663 
11664     cleanupOperandDescriptor (cpup, 1);
11665     cleanupOperandDescriptor (cpup, 2);
11666     cleanupOperandDescriptor (cpup, 3);
11667 
11668     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11669       doFault(FAULT_OFL, fst_zero, "sb3d truncation(overflow) fault");
11670     if (EOvr && tstOVFfault (cpup))
11671         doFault(FAULT_OFL, fst_zero, "sb3d over/underflow fault");
11672     if (Ovr)
11673     {
11674         SET_I_OFLOW;
11675         if (tstOVFfault (cpup))
11676           doFault(FAULT_OFL, fst_zero, "sb3d overflow fault");
11677     }
11678 }
11679 
11680 /*
11681  * mp2d - Multiply Using Two Decimal Operands
11682  */
11683 
11684 void mp2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11685 {
11686     EISstruct * e = & cpu.currentEISinstruction;
11687 
11688     fault_ipr_subtype_ mod_fault = 0;
11689 
11690 #if !defined(EIS_SETUP)
11691     setupOperandDescriptor(cpup, 1, &mod_fault);
11692     setupOperandDescriptor(cpup, 2, &mod_fault);
11693     setupOperandDescriptorCache(cpup,3);
11694 #endif
11695 
11696     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11697     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11698 
11699     L68_ (
11700       // L68 raises it immediately
11701       if (mod_fault)
11702         {
11703           doFault (FAULT_IPR,
11704                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11705                    "Illegal modifier");
11706         }
11707     )
11708 
11709     // Bits 1-8 MBZ
11710     if (IWB_IRODD & 0377000000000)
11711       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp2d 1-8 MBZ");
11712 
11713     DPS8M_ (
11714       // DPS8M raises it delayed
11715       if (mod_fault)
11716         {
11717           doFault (FAULT_IPR,
11718                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11719                    "Illegal modifier");
11720         }
11721     )
11722 
11723     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
11724     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
11725     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
11726 
11727     PNL (L68_ (if (R)
11728       DU_CYCLE_FRND;))
11729 
11730     uint srcTN = e->TN1;    // type of chars in src
11731 
11732     uint dstTN = e->TN2;    // type of chars in dst
11733     uint dstCN = e->CN2;    // starting at char pos CN
11734 
11735     e->ADDR3 = e->ADDR2;
11736 
11737     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
11738 
11739     /*
11740      * Here we need to distinguish between 4 type of numbers.
11741      *
11742      * CSFL - Floating-point, leading sign
11743      * CSLS - Scaled fixed-point, leading sign
11744      * CSTS - Scaled fixed-point, trailing sign
11745      * CSNS - Scaled fixed-point, unsigned
11746      */
11747 
11748     // determine precision
11749     switch(e->S1)
11750     {
11751         case CSFL:
11752             n1 = (int) e->N1 - 1; // need to account for the - sign
11753             if (srcTN == CTN4)
11754                 n1 -= 2;    // 2 4-bit digits exponent
11755             else
11756                 n1 -= 1;    // 1 9-bit digit exponent
11757             sc1 = 0;        // no scaling factor
11758             break;
11759 
11760         case CSLS:
11761         case CSTS:
11762             n1 = (int) e->N1 - 1; // only 1 sign
11763             sc1 = -e->SF1;
11764             break;
11765 
11766         case CSNS:
11767             n1 = (int) e->N1;     // no sign
11768             sc1 = -e->SF1;
11769             break;  // no sign wysiwyg
11770     }
11771 
11772     if (n1 < 1)
11773         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n1<1");
11774 
11775     switch(e->S2)
11776     {
11777         case CSFL:
11778             n2 = (int) e->N2 - 1; // need to account for the sign
11779             if (e->TN2 == CTN4)
11780                 n2 -= 2;    // 2 4-bit digit exponent
11781             else
11782                 n2 -= 1;    // 1 9-bit digit exponent
11783             sc2 = 0;        // no scaling factor
11784             break;
11785 
11786         case CSLS:
11787         case CSTS:
11788             n2 = (int) e->N2 - 1; // 1 sign
11789             sc2 = -e->SF2;
11790             break;
11791 
11792         case CSNS:
11793             n2 = (int) e->N2;     // no sign
11794             sc2 = -e->SF2;
11795             break;  // no sign wysiwyg
11796     }
11797 
11798     if (n2 < 1)
11799         doFault (FAULT_IPR, fst_ill_proc, "mp2d adjusted n2<1");
11800 
11801     decContext set;
11802     decContextDefaultDPS8Mul(&set); // 126 digits for multiply
11803 
11804     set.traps=0;
11805 
11806     decNumber _1, _2, _3;
11807 
11808     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
11809 
11810     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
11811     if (e->sign == -1)
11812         op1->bits |= DECNEG;
11813     if (e->S1 == CSFL)
11814         op1->exponent = e->exponent;
11815 
11816     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
11817 
11818     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
11819     if (e->sign == -1)
11820         op2->bits |= DECNEG;
11821     if (e->S2 == CSFL)
11822         op2->exponent = e->exponent;
11823 
11824     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
11825 
11826     bool Ovr = false, EOvr = false, Trunc = false;
11827 
11828     uint8_t out [256];
11829     char *res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
11830 
11831     if (decNumberIsZero(op3))
11832         op3->exponent = 127;
11833 
11834     // now write to memory in proper format.....
11835 
11836     //word18 dstAddr = e->dstAddr;
11837     int pos = (int) dstCN;
11838 
11839     // 1st, take care of any leading sign .......
11840     switch(e->S2)
11841     {
11842         case CSFL:  // floating-point, leading sign.
11843         case CSLS:  // fixed-point, leading sign
11844             switch(dstTN)
11845         {
11846             case CTN4:
11847                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11848                           //   then the 13(8) plus sign character is placed appropriately
11849                           //   if the result of the operation is positive.
11850                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11851                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11852                 else
11853                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11854                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11855                 break;
11856             case CTN9:
11857                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11858                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11859                 break;
11860         }
11861             break;
11862 
11863         case CSTS:  // nuttin' to do here .....
11864         case CSNS:
11865             break;  // no sign wysiwyg
11866     }
11867 
11868     // 2nd, write the digits .....
11869     for(int i = 0 ; i < n2 ; i++)
11870         switch(dstTN)
11871     {
11872         case CTN4:
11873             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
11874             break;
11875         case CTN9:
11876             EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
11877             break;
11878     }
11879 
11880     // 3rd, take care of any trailing sign or exponent ...
11881     switch(e->S2)
11882     {
11883         case CSTS:  // write trailing sign ....
11884             switch(dstTN)
11885         {
11886             case CTN4:
11887                 if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
11888                           //   then the 13(8) plus sign character is placed appropriately
11889                           //   if the result of the operation is positive.
11890                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11891                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
11892                 else
11893                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11894                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
11895                 break;
11896             case CTN9:
11897                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
11898                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
11899                 break;
11900         }
11901             break;
11902 
11903         case CSFL:  // floating-point, leading sign.
11904             // write the exponent
11905             switch(dstTN)
11906             {
11907                 case CTN4:
11908                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
11909                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
11910 
11911                     break;
11912                 case CTN9:
11913                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
11914                     break;
11915             }
11916             break;
11917 
11918         case CSLS:  // fixed point, leading sign - already done
11919         case CSNS:  // fixed point, unsigned - nuttin' needed to do
11920             break;
11921     }
11922 
11923     // set flags, etc ...
11924     if (e->S2 == CSFL)
11925     {
11926         if (op3->exponent > 127)
11927         {
11928             SET_I_EOFL;
11929             EOvr = true;
11930         }
11931         if (op3->exponent < -128)
11932         {
11933             SET_I_EUFL;
11934             EOvr = true;
11935         }
11936     }
11937 
11938     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
11939     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
11940 
11941     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
11942 
11943     cleanupOperandDescriptor (cpup, 1);
11944     cleanupOperandDescriptor (cpup, 2);
11945     cleanupOperandDescriptor (cpup, 3);
11946 
11947     if (TST_I_TRUNC && T && tstOVFfault (cpup))
11948       doFault(FAULT_OFL, fst_zero, "mp2d truncation(overflow) fault");
11949     if (EOvr && tstOVFfault (cpup))
11950         doFault(FAULT_OFL, fst_zero, "mp2d over/underflow fault");
11951     if (Ovr)
11952     {
11953         SET_I_OFLOW;
11954         if (tstOVFfault (cpup))
11955           doFault(FAULT_OFL, fst_zero, "mp2d overflow fault");
11956     }
11957 }
11958 
11959 /*
11960  * mp3d - Multiply Using Three Decimal Operands
11961  */
11962 
11963 void mp3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
11964 {
11965     EISstruct * e = & cpu.currentEISinstruction;
11966 
11967     fault_ipr_subtype_ mod_fault = 0;
11968 
11969 #if !defined(EIS_SETUP)
11970     setupOperandDescriptor(cpup, 1, &mod_fault);
11971     setupOperandDescriptor(cpup, 2, &mod_fault);
11972     setupOperandDescriptor(cpup, 3, &mod_fault);
11973 #endif
11974 
11975     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
11976     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
11977     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
11978 
11979     L68_ (
11980       // L68 raises it immediately
11981       if (mod_fault)
11982         {
11983           doFault (FAULT_IPR,
11984                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11985                    "Illegal modifier");
11986         }
11987     )
11988 
11989     // Bit 1 MBZ
11990     if (IWB_IRODD & 0200000000000)
11991       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "mp3d(): 1 MBZ");
11992 
11993     DPS8M_ (
11994       // DPS8M raises it delayed
11995       if (mod_fault)
11996         {
11997           doFault (FAULT_IPR,
11998                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
11999                    "Illegal modifier");
12000         }
12001     )
12002 
12003     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
12004     bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
12005     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
12006 
12007     PNL (L68_ (if (R)
12008       DU_CYCLE_FRND;))
12009 
12010     uint srcTN = e->TN1;    // type of chars in src
12011 
12012     uint dstTN = e->TN3;    // type of chars in dst
12013     uint dstCN = e->CN3;    // starting at char pos CN
12014 
12015     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
12016 
12017     /*
12018      * Here we need to distinguish between 4 type of numbers.
12019      *
12020      * CSFL - Floating-point, leading sign
12021      * CSLS - Scaled fixed-point, leading sign
12022      * CSTS - Scaled fixed-point, trailing sign
12023      * CSNS - Scaled fixed-point, unsigned
12024      */
12025 
12026     // determine precision
12027     switch(e->S1)
12028     {
12029         case CSFL:
12030             n1 = (int) e->N1 - 1; // need to account for the - sign
12031             if (srcTN == CTN4)
12032                 n1 -= 2;    // 2 4-bit digits exponent
12033             else
12034                 n1 -= 1;    // 1 9-bit digit exponent
12035             sc1 = 0;        // no scaling factor
12036             break;
12037 
12038         case CSLS:
12039         case CSTS:
12040             n1 = (int) e->N1 - 1; // only 1 sign
12041             sc1 = -e->SF1;
12042             break;
12043 
12044         case CSNS:
12045             n1 = (int) e->N1;     // no sign
12046             sc1 = -e->SF1;
12047             break;  // no sign wysiwyg
12048     }
12049 
12050     if (n1 < 1)
12051         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n1<1");
12052 
12053     switch(e->S2)
12054     {
12055         case CSFL:
12056             n2 = (int) e->N2 - 1; // need to account for the sign
12057             if (e->TN2 == CTN4)
12058                 n2 -= 2;    // 2 4-bit digit exponent
12059             else
12060                 n2 -= 1;    // 1 9-bit digit exponent
12061             sc2 = 0;        // no scaling factor
12062             break;
12063 
12064         case CSLS:
12065         case CSTS:
12066             n2 = (int) e->N2 - 1; // 1 sign
12067             sc2 = -e->SF2;
12068             break;
12069 
12070         case CSNS:
12071             n2 = (int) e->N2;     // no sign
12072             sc2 = -e->SF2;
12073             break;  // no sign wysiwyg
12074     }
12075 
12076     if (n2 < 1)
12077         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n2<1");
12078 
12079     switch(e->S3)
12080     {
12081         case CSFL:
12082             n3 = (int) e->N3 - 1; // need to account for the sign
12083             if (dstTN == CTN4)
12084                 n3 -= 2;    // 2 4-bit digit exponent
12085             else
12086                 n3 -= 1;    // 1 9-bit digit exponent
12087             break;
12088 
12089         case CSLS:
12090         case CSTS:
12091             n3 = (int) e->N3 - 1; // 1 sign
12092             break;
12093 
12094         case CSNS:
12095             n3 = (int) e->N3;     // no sign
12096             break;  // no sign wysiwyg
12097     }
12098 
12099     if (n3 < 1)
12100         doFault (FAULT_IPR, fst_ill_proc, "mp3d adjusted n3<1");
12101 
12102     decContext set;
12103     //decContextDefault(&set, DEC_INIT_BASE);         // initialize
12104     decContextDefaultDPS8Mul(&set);     // 126 digits for multiply
12105 
12106     set.traps=0;
12107 
12108     decNumber _1, _2, _3;
12109 
12110     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
12111 
12112     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
12113     if (e->sign == -1)
12114         op1->bits |= DECNEG;
12115     if (e->S1 == CSFL)
12116         op1->exponent = e->exponent;
12117 
12118     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
12119 
12120     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
12121     if (e->sign == -1)
12122         op2->bits |= DECNEG;
12123     if (e->S2 == CSFL)
12124         op2->exponent = e->exponent;
12125 
12126     decNumber *op3 = decNumberMultiply(&_3, op1, op2, &set);
12127 
12128 //    char c1[1024];
12129 //    char c2[1024];
12130 //    char c3[1024];
12131 //
12132 //    decNumberToString(op1, c1);
12133 //    sim_printf("c1:%s\r\n", c1);
12134 //    decNumberToString(op2, c2);
12135 //    sim_printf("c2:%s\r\n", c2);
12136 //    decNumberToString(op3, c3);
12137 //    sim_printf("c3:%s\r\n", c3);
12138 
12139     bool Ovr = false, EOvr = false, Trunc = false;
12140 
12141     uint8_t out [256];
12142     char *res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
12143 
12144     if (decNumberIsZero(op3))
12145         op3->exponent = 127;
12146 
12147     // now write to memory in proper format.....
12148 
12149     //word18 dstAddr = e->dstAddr;
12150     int pos = (int) dstCN;
12151 
12152     // 1st, take care of any leading sign .......
12153     switch(e->S3)
12154     {
12155         case CSFL:  // floating-point, leading sign.
12156         case CSLS:  // fixed-point, leading sign
12157             switch(dstTN)
12158             {
12159             case CTN4:
12160               if (e->P) // If TN2 and S2 specify a 4-bit signed number and P
12161                           // = 1, then the 13(8) plus sign character is placed
12162                           // appropriately if the result of the operation is
12163                           // positive.
12164                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12165                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
12166                 else
12167                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12168                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
12169                 break;
12170             case CTN9:
12171                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12172                            (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
12173                 break;
12174             }
12175             break;
12176 
12177         case CSTS:  // nuttin' to do here .....
12178         case CSNS:
12179             break;  // no sign wysiwyg
12180     }
12181 
12182     // 2nd, write the digits .....
12183     for(int i = 0 ; i < n3 ; i++)
12184         switch(dstTN)
12185         {
12186             case CTN4:
12187                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
12188                 break;
12189             case CTN9:
12190                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
12191                 break;
12192         }
12193 
12194         // 3rd, take care of any trailing sign or exponent ...
12195     switch(e->S3)
12196     {
12197         case CSTS:  // write trailing sign ....
12198             switch(dstTN)
12199             {
12200                 case CTN4:
12201                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
12202                               //  then the 13(8) plus sign character is placed appropriately
12203                               //  if the result of the operation is positive.
12204                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12205                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
12206                     else
12207                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12208                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
12209                     break;
12210                 case CTN9:
12211                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
12212                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
12213                     break;
12214             }
12215             break;
12216 
12217         case CSFL:  // floating-point, leading sign.
12218             // write the exponent
12219             switch(dstTN)
12220             {
12221                 case CTN4:
12222                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
12223                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
12224                     break;
12225                 case CTN9:
12226                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
12227                     break;
12228             }
12229             break;
12230 
12231         case CSLS:  // fixed point, leading sign - already done
12232         case CSNS:  // fixed point, unsigned - nuttin' needed to do
12233             break;
12234     }
12235 
12236     // set flags, etc ...
12237     if (e->S3 == CSFL)
12238     {
12239         if (op3->exponent > 127)
12240         {
12241             SET_I_EOFL;
12242             EOvr = true;
12243         }
12244         if (op3->exponent < -128)
12245         {
12246             SET_I_EUFL;
12247             EOvr = true;
12248         }
12249     }
12250 
12251     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
12252     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
12253 
12254     SC_I_TRUNC (!R && Trunc); // If the truncation condition exists without rounding, then ON; otherwise OFF
12255 
12256     cleanupOperandDescriptor (cpup, 1);
12257     cleanupOperandDescriptor (cpup, 2);
12258     cleanupOperandDescriptor (cpup, 3);
12259 
12260     if (TST_I_TRUNC && T && tstOVFfault (cpup))
12261       doFault(FAULT_OFL, fst_zero, "mp3d truncation(overflow) fault");
12262     if (EOvr && tstOVFfault (cpup))
12263         doFault(FAULT_OFL, fst_zero, "mp3d over/underflow fault");
12264     if (Ovr)
12265     {
12266         SET_I_OFLOW;
12267         if (tstOVFfault (cpup))
12268           doFault(FAULT_OFL, fst_zero, "mp3d overflow fault");
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 
12884 
12885 
12886 
12887 
12888 
12889 
12890 
12891 
12892 
12893 
12894 
12895 
12896 
12897 
12898 
12899 
12900 
12901 
12902 
12903 
12904 
12905 
12906 
12907 
12908 
12909 
12910 
12911 
12912 
12913 
12914 
12915 
12916 
12917 
12918 
12919 
12920 
12921 
12922 
12923 
12924 
12925 
12926 
12927 
12928 
12929 
12930 
12931 
12932 
12933 
12934 
12935 
12936 
12937 
12938 
12939 
12940 
12941 
12942 
12943 
12944 
12945 
12946 
12947 
12948 
12949 
12950 
12951 
12952 
12953 
12954 
12955 
12956 
12957 
12958 
12959 
12960 
12961 
12962 
12963 
12964 
12965 
12966 
12967 
12968 
12969 
12970 
12971 
12972 
12973 
12974 
12975 
12976 
12977 
12978 
12979 
12980 
12981 
12982 
12983 
12984 
12985 
12986 
12987 
12988 
12989 
12990 
12991 
12992 
12993 
12994 
12995 
12996 
12997 
12998 
12999 
13000 
13001 
13002 
13003 
13004 
13005 
13006 
13007 
13008 
13009 
13010 
13011 
13012 
13013 
13014 
13015 
13016 
13017 
13018 
13019 
13020 
13021 /*
13022  * dv2d - Divide Using Two Decimal Operands
13023  */
13024 
13025 void dv2d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
13026 {
13027     EISstruct * e = & cpu.currentEISinstruction;
13028 
13029     fault_ipr_subtype_ mod_fault = 0;
13030 
13031 #if !defined(EIS_SETUP)
13032     setupOperandDescriptor(cpup, 1, &mod_fault);
13033     setupOperandDescriptor(cpup, 2, &mod_fault);
13034     setupOperandDescriptorCache(cpup, 3);
13035 #endif
13036 
13037     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
13038     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
13039 
13040     L68_ (
13041       // L68 raises it immediately
13042       if (mod_fault)
13043         {
13044           doFault (FAULT_IPR,
13045                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13046                    "Illegal modifier");
13047         }
13048     )
13049 
13050     // Bits 1-8 MBZ
13051     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ as well
13052     if (IWB_IRODD & 0377400000000)
13053       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv2d 1-9 MBZ");
13054 
13055     DPS8M_ (
13056       // DPS8M raises it delayed
13057       if (mod_fault)
13058         {
13059           doFault (FAULT_IPR,
13060                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13061                    "Illegal modifier");
13062         }
13063     )
13064 
13065     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
13066     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
13067     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
13068 
13069     PNL (L68_ (if (R)
13070       DU_CYCLE_FRND;))
13071 
13072     uint srcTN = e->TN1;    // type of chars in src
13073 
13074     uint dstTN = e->TN2;    // type of chars in dst
13075     uint dstCN = e->CN2;    // starting at char pos CN
13076 
13077     e->ADDR3 = e->ADDR2;
13078 
13079     int n1 = 0, n2 = 0, sc1 = 0, sc2 = 0;
13080 
13081     /*
13082      * Here we need to distinguish between 4 type of numbers.
13083      *
13084      * CSFL - Floating-point, leading sign
13085      * CSLS - Scaled fixed-point, leading sign
13086      * CSTS - Scaled fixed-point, trailing sign
13087      * CSNS - Scaled fixed-point, unsigned
13088      */
13089 
13090     // determine precision
13091     switch(e->S1)
13092     {
13093         case CSFL:
13094             n1 = (int) e->N1 - 1; // need to account for the - sign
13095             if (srcTN == CTN4)
13096                 n1 -= 2;    // 2 4-bit digits exponent
13097             else
13098                 n1 -= 1;    // 1 9-bit digit exponent
13099             sc1 = 0;        // no scaling factor
13100             break;
13101 
13102         case CSLS:
13103         case CSTS:
13104             n1 = (int) e->N1 - 1; // only 1 sign
13105             sc1 = -e->SF1;
13106             break;
13107 
13108         case CSNS:
13109             n1 = (int) e->N1;     // no sign
13110             sc1 = -e->SF1;
13111             break;  // no sign wysiwyg
13112     }
13113 
13114     if (n1 < 1)
13115         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n1<1");
13116 
13117     switch(e->S2)
13118     {
13119         case CSFL:
13120             n2 = (int) e->N2 - 1; // need to account for the sign
13121             if (e->TN2 == CTN4)
13122                 n2 -= 2;    // 2 4-bit digit exponent
13123             else
13124                 n2 -= 1;    // 1 9-bit digit exponent
13125             sc2 = 0;        // no scaling factor
13126             break;
13127 
13128         case CSLS:
13129         case CSTS:
13130             n2 = (int) e->N2 - 1; // 1 sign
13131             sc2 = -e->SF2;
13132             break;
13133 
13134         case CSNS:
13135             n2 = (int) e->N2;     // no sign
13136             sc2 = -e->SF2;
13137             break;  // no sign wysiwyg
13138     }
13139 
13140     if (n2 < 1)
13141         doFault (FAULT_IPR, fst_ill_proc, "dv2d adjusted n2<1");
13142 
13143     decContext set;
13144     decContextDefaultDPS8(&set);
13145 
13146     set.traps=0;
13147 
13148     decNumber _1, _2, _3;
13149 
13150     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
13151 
13152     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);    // divisor
13153     if (e->sign == -1)
13154         op1->bits |= DECNEG;
13155     if (e->S1 == CSFL)
13156         op1->exponent = e->exponent;
13157 
13158     // check for divide by 0!
13159     if (decNumberIsZero(op1))
13160     {
13161         doFault(FAULT_DIV, fst_zero, "dv2d division by 0");
13162     }
13163 
13164     word9   inBufferop1 [64];
13165     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13166 
13167     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
13168 
13169     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);    // dividend
13170     if (e->sign == -1)
13171         op2->bits |= DECNEG;
13172     if (e->S2 == CSFL)
13173         op2->exponent = e->exponent;
13174 
13175     int NQ;
13176     if (e->S2 == CSFL)
13177     {
13178         NQ = n2;
13179     }
13180     else
13181     {
13182         // count leading zeroes
13183         // TODO optimize - can these be somehow extracted from decNumbers?
13184         int clz1, clz2, i;
13185         for (i=0; i < op1->digits; i++)
13186             if (inBufferop1[i]!=0)
13187                 break;
13188         clz1 = i;
13189         for (i=0; i < op2->digits; i++)
13190             if (e->inBuffer[i]!=0) // this still holds op2 digits
13191                 break;
13192         clz2 = i;
13193         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: clz1 %d clz2 %d\r\n",clz1,clz2);
13194 
13195         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13196         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13197         NQ = (n2-clz2+1) - (n1-clz1) + (-(e->S1==CSFL?op1->exponent:(int)e->SF1));
13198 
13199 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\r\n",
13200            e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF2,NQ);
13201     }
13202     if (NQ > 63)
13203         doFault(FAULT_DIV, fst_zero, "dv2d NQ>63");
13204     // Note: NQ is currently unused apart from this FAULT_DIV check.
13205     // decNumber produces more digits than required, but they are then rounded/truncated
13206 
13207     // Yes, they're switched. op1=divisor
13208     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13209     // Note DPS88 and DPS9000 are different when NQ <= 0
13210     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13211     // ISOLTS-817 05b
13212 
13213     PRINTDEC("op2", op2);
13214     PRINTDEC("op1", op1);
13215     PRINTDEC("op3", op3);
13216 
13217     // let's check division results to see for anomalous conditions
13218     if (
13219         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13220         (set.status & DEC_Invalid_operation) ||
13221         (set.status & DEC_Division_by_zero)
13222         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv2d anomalous results"); } // divide by zero has already been checked before
13223 
13224     if (e->S2 == CSFL)
13225     {
13226         // justify CSFL left
13227         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13228         // Note DPS88 and DPS9000 are different
13229         // ISOLTS-817 06c,06e
13230 
13231         decNumber _sf;
13232 
13233         if (n2 - op3->digits > 0)
13234         {
13235             decNumberFromInt32(&_sf, op3->exponent - (n2 - op3->digits));
13236             PRINTDEC("Value 1", op3)
13237             PRINTDEC("Value sf", &_sf)
13238             op3 = decNumberRescale(op3, op3, &_sf, &set);
13239             PRINTDEC("Value 2", op3)
13240         }
13241     }
13242 
13243     bool Ovr = false, EOvr = false, Trunc = false;
13244     uint8_t out[256];
13245 
13246     // CSFL: If the divisor is greater than the dividend after operand
13247     // alignment, the leading zero digit produced is counted and the effective
13248     // precision of the result is reduced by one.
13249     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13250     // Note DPS88 and DPS9000 are different
13251     //
13252     // "greater after operand alignment" means scale until most-significant digits
13253     //   are nonzero, then compare magnitudes ignoring exponents
13254     // This passes ISOLTS-817 06e, ET 458,461,483,486
13255     char *res;
13256     if (e->S2 == CSFL) {
13257         decNumber _1a;
13258         decNumber _2a;
13259         decNumber _sf;
13260         if (op1->digits >= op2->digits) {
13261             // scale op2
13262             decNumberCopy(&_1a, op1);
13263             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13264             decNumberShift(&_2a, op2, &_sf, &set);
13265         } else if (op1->digits < op2->digits) {
13266             // scale op1
13267             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13268             decNumberShift(&_1a, op1, &_sf, &set);
13269             decNumberCopy(&_2a, op2);
13270         }
13271         _1a.exponent = 0;
13272         _2a.exponent = 0;
13273 
13274         PRINTDEC("dv2d: op1a", &_1a);
13275         PRINTDEC("dv2d: op2a", &_2a);
13276         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\r\n",
13277                    op1->exponent,op2->exponent,op1->digits,op2->digits,_1a.digits,_2a.digits);
13278 
13279         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13280             // shorten the result field to get proper rounding
13281             res = formatDecimal(out, &set, op3, n2 -1, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13282 
13283             // prepend zero digit
13284             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13285             for (int i = n2; i > 0; i--) // incl.zero terminator
13286                  res[i] = res[i-1];
13287             res[0] = '0';
13288             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv2d: addzero n2 %d %s exp %d\r\n",n2,res,op3->exponent);
13289         } else {
13290             // full n2 digits are returned
13291             res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13292         }
13293     } else {
13294         // same as all other decimal instructions
13295         res = formatDecimal(out, &set, op3, n2, (int) e->S2, e->SF2, R, &Ovr, &Trunc);
13296     }
13297 
13298     if (decNumberIsZero(op3))
13299         op3->exponent = 127;
13300 
13301     // now write to memory in proper format.....
13302 
13303     int pos = (int) dstCN;
13304 
13305     // 1st, take care of any leading sign .......
13306     switch(e->S2)
13307     {
13308         case CSFL:  // floating-point, leading sign.
13309         case CSLS:  // fixed-point, leading sign
13310             switch(dstTN)
13311             {
13312                 case CTN4:
13313                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13314                               //   then the 13(8) plus sign character is placed appropriately
13315                               //   if the result of the operation is positive.
13316                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13317                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13318                     else
13319                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13320                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13321                     break;
13322                 case CTN9:
13323                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13324                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13325                     break;
13326             }
13327             break;
13328 
13329         case CSTS:  // nuttin' to do here .....
13330         case CSNS:
13331             break;  // no sign wysiwyg
13332     }
13333 
13334     // 2nd, write the digits .....
13335     for(int i = 0 ; i < n2 ; i++)
13336         switch(dstTN)
13337         {
13338             case CTN4:
13339                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13340                 break;
13341             case CTN9:
13342                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13343                 break;
13344         }
13345 
13346     // 3rd, take care of any trailing sign or exponent ...
13347     switch(e->S2)
13348     {
13349         case CSTS:  // write trailing sign ....
13350             switch(dstTN)
13351             {
13352                 case CTN4:
13353                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13354                               //   then the 13(8) plus sign character is placed appropriately
13355                               //   if the result of the operation is positive.
13356                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13357                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13358                     else
13359                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13360                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13361                     break;
13362                 case CTN9:
13363                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13364                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13365                     break;
13366             }
13367             break;
13368 
13369         case CSFL:  // floating-point, leading sign.
13370             // write the exponent
13371             switch(dstTN)
13372             {
13373                 case CTN4:
13374                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13375                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13376                     break;
13377                 case CTN9:
13378                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13379                     break;
13380             }
13381             break;
13382 
13383         case CSLS:  // fixed point, leading sign - already done
13384         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13385             break;
13386     }
13387 
13388     // set flags, etc ...
13389     if (e->S2 == CSFL)
13390     {
13391         if (op3->exponent > 127)
13392         {
13393             SET_I_EOFL;
13394             EOvr = true;
13395         }
13396         if (op3->exponent < -128)
13397         {
13398             SET_I_EUFL;
13399             EOvr = true;
13400         }
13401     }
13402 
13403     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13404     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13405 
13406     //SC_I_TRUNC (!R && Trunc); // no truncation flag for divide
13407 
13408     cleanupOperandDescriptor (cpup, 1);
13409     cleanupOperandDescriptor (cpup, 2);
13410     cleanupOperandDescriptor (cpup, 3);
13411 
13412     //if (TST_I_TRUNC && T && tstOVFfault (cpup))
13413     //  doFault(FAULT_OFL, fst_zero, "dv2d truncation(overflow) fault");
13414     if (EOvr && tstOVFfault (cpup))
13415         doFault(FAULT_OFL, fst_zero, "dv2d over/underflow fault");
13416     if (Ovr)
13417     {
13418         SET_I_OFLOW;
13419         if (tstOVFfault (cpup))
13420           doFault(FAULT_OFL, fst_zero, "dv2d overflow fault");
13421     }
13422 }
13423 
13424 /*
13425  * dv3d - Divide Using Three Decimal Operands
13426  */
13427 
13428 void dv3d (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
13429 
13430 {
13431     EISstruct * e = & cpu.currentEISinstruction;
13432 
13433     fault_ipr_subtype_ mod_fault = 0;
13434 
13435 #if !defined(EIS_SETUP)
13436     setupOperandDescriptor(cpup, 1, &mod_fault);
13437     setupOperandDescriptor(cpup, 2, &mod_fault);
13438     setupOperandDescriptor(cpup, 3, &mod_fault);
13439 #endif
13440 
13441     parseNumericOperandDescriptor(cpup, 1, &mod_fault);
13442     parseNumericOperandDescriptor(cpup, 2, &mod_fault);
13443     parseNumericOperandDescriptor(cpup, 3, &mod_fault);
13444 
13445     L68_ (
13446       // L68 raises it immediately
13447       if (mod_fault)
13448         {
13449           doFault (FAULT_IPR,
13450                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13451                    "Illegal modifier");
13452         }
13453     )
13454 
13455     // Bit 1 MBZ
13456     // ISOLTS test 840 and RJ78 says bit 9 (T) MBZ
13457     if (IWB_IRODD & 0200400000000)
13458       doFault (FAULT_IPR, (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP|mod_fault}, "dv3d(): 1,9 MBZ");
13459 
13460     DPS8M_ (
13461       // DPS8M raises it delayed
13462       if (mod_fault)
13463         {
13464           doFault (FAULT_IPR,
13465                    (_fault_subtype) {.fault_ipr_subtype=mod_fault},
13466                    "Illegal modifier");
13467         }
13468     )
13469 
13470     e->P = getbits36_1 (cpu.cu.IWB, 0) != 0;  // 4-bit data sign character control
13471     //bool T = getbits36_1 (cpu.cu.IWB, 9) != 0;  // truncation bit
13472     bool R = getbits36_1 (cpu.cu.IWB, 10) != 0;  // rounding bit
13473 
13474     PNL (L68_ (if (R)
13475       DU_CYCLE_FRND;))
13476 
13477     uint srcTN = e->TN1;    // type of chars in src
13478 
13479     uint dstTN = e->TN3;    // type of chars in dst
13480     uint dstCN = e->CN3;    // starting at char pos CN
13481 
13482     int n1 = 0, n2 = 0, n3 = 0, sc1 = 0, sc2 = 0;
13483 
13484     /*
13485      * Here we need to distinguish between 4 type of numbers.
13486      *
13487      * CSFL - Floating-point, leading sign
13488      * CSLS - Scaled fixed-point, leading sign
13489      * CSTS - Scaled fixed-point, trailing sign
13490      * CSNS - Scaled fixed-point, unsigned
13491      */
13492 
13493     // determine precision
13494     switch(e->S1)
13495     {
13496         case CSFL:
13497             n1 = (int) e->N1 - 1; // need to account for the - sign
13498             if (srcTN == CTN4)
13499                 n1 -= 2;    // 2 4-bit digits exponent
13500             else
13501                 n1 -= 1;    // 1 9-bit digit exponent
13502             sc1 = 0;        // no scaling factor
13503             break;
13504 
13505         case CSLS:
13506         case CSTS:
13507             n1 = (int) e->N1 - 1; // only 1 sign
13508             sc1 = -e->SF1;
13509             break;
13510 
13511         case CSNS:
13512             n1 = (int) e->N1;     // no sign
13513             sc1 = -e->SF1;
13514             break;  // no sign wysiwyg
13515     }
13516 
13517     if (n1 < 1)
13518         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n1<1");
13519 
13520     switch(e->S2)
13521     {
13522         case CSFL:
13523             n2 = (int) e->N2 - 1; // need to account for the sign
13524             if (e->TN2 == CTN4)
13525                 n2 -= 2;    // 2 4-bit digit exponent
13526             else
13527                 n2 -= 1;    // 1 9-bit digit exponent
13528             sc2 = 0;        // no scaling factor
13529             break;
13530 
13531         case CSLS:
13532         case CSTS:
13533             n2 = (int) e->N2 - 1; // 1 sign
13534             sc2 = -e->SF2;
13535             break;
13536 
13537         case CSNS:
13538             n2 = (int) e->N2;     // no sign
13539             sc2 = -e->SF2;
13540             break;  // no sign wysiwyg
13541     }
13542 
13543     if (n2 < 1)
13544         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n2<1");
13545 
13546     switch(e->S3)
13547     {
13548         case CSFL:
13549             n3 = (int) e->N3 - 1; // need to account for the sign
13550             if (dstTN == CTN4)
13551                 n3 -= 2;    // 2 4-bit digit exponent
13552             else
13553                 n3 -= 1;    // 1 9-bit digit exponent
13554             break;
13555 
13556         case CSLS:
13557         case CSTS:
13558             n3 = (int) e->N3 - 1; // 1 sign
13559             break;
13560 
13561         case CSNS:
13562             n3 = (int) e->N3;     // no sign
13563             break;  // no sign wysiwyg
13564     }
13565     if (n3 < 1)
13566         doFault (FAULT_IPR, fst_ill_proc, "dv3d adjusted n3<1");
13567 
13568     decContext set;
13569     decContextDefaultDPS8(&set);
13570 
13571     set.traps=0;
13572 
13573     decNumber _1, _2, _3;
13574 
13575     EISloadInputBufferNumeric (cpup, 1);   // according to MF1
13576 
13577     decNumber *op1 = decBCD9ToNumber(e->inBuffer, n1, sc1, &_1);
13578     //PRINTDEC("op1", op1);
13579     if (e->sign == -1)
13580         op1->bits |= DECNEG;
13581     if (e->S1 == CSFL)
13582         op1->exponent = e->exponent;
13583 
13584     // check for divide by 0!
13585     if (decNumberIsZero(op1))
13586     {
13587         doFault(FAULT_DIV, fst_zero, "dv3d division by 0");
13588     }
13589 
13590     word9   inBufferop1 [64];
13591     memcpy (inBufferop1,e->inBuffer,sizeof(inBufferop1)); // save for clz1 calculation later
13592 
13593     EISloadInputBufferNumeric (cpup, 2);   // according to MF2
13594 
13595     decNumber *op2 = decBCD9ToNumber(e->inBuffer, n2, sc2, &_2);
13596     if (e->sign == -1)
13597         op2->bits |= DECNEG;
13598     if (e->S2 == CSFL)
13599         op2->exponent = e->exponent;
13600 
13601     // The number of required quotient digits, NQ, is determined before
13602     // division begins as follows:
13603     //  1) Floating-point quotient
13604     //      NQ = N3
13605     //  2) Fixed-point quotient
13606     //    NQ = (N2-LZ2+1) - (N1-LZ1) + (E2-E1-SF3)
13607     //     where: Nn = given operand field length
13608     //        LZn = leading zero count for operand n
13609     //        En = exponent of operand n
13610     //        SF3 = scaling factor of quotient
13611     // 3) Rounding
13612     //    If rounding is specified (R = 1), then one extra quotient digit is
13613     //    produced.
13614     // Note: rule 3 is already handled by formatDecimal rounding
13615     // Nn doesn't represent full field length, but length without sign and exponent (RJ78/DH03 seems like)
13616 
13617     int NQ;
13618     if (e->S3 == CSFL)
13619     {
13620         NQ = n3;
13621     }
13622     else
13623     {
13624         // count leading zeroes
13625         // TODO optimize - can these be somehow extracted from decNumbers?
13626         int clz1, clz2, i;
13627         for (i=0; i < op1->digits; i++)
13628             if (inBufferop1[i]!=0)
13629                 break;
13630         clz1 = i;
13631         for (i=0; i < op2->digits; i++)
13632             if (e->inBuffer[i]!=0) // this still holds op2 digits
13633                 break;
13634         clz2 = i;
13635         sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: clz1 %d clz2 %d\r\n",clz1,clz2);
13636 
13637         // XXX are clz also valid for CSFL dividend / divisor? probably yes
13638         // XXX seems that exponents and scale factors are used interchangeably here ? (RJ78)
13639         NQ = (n2-clz2+1) - (n1-clz1) + \
13640                 ((e->S2==CSFL?op2->exponent:(int)e->SF2)-(e->S1==CSFL?op1->exponent:(int)e->SF1)-(int)e->SF3);
13641 
13642 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\r\n",
13643            e->S1,e->S2,e->N1,e->N2,clz1,clz2,op1->exponent,op2->exponent,e->SF3,NQ);
13644     }
13645     if (NQ > 63)
13646         doFault(FAULT_DIV, fst_zero, "dv3d NQ>63");
13647     // Note: NQ is currently unused apart from this FAULT_DIV check.
13648     //   decNumber produces more digits than required, but they are then rounded/truncated
13649 
13650     // Yes, they're switched. op1=divisor
13651     decNumber *op3 = decNumberDivide(&_3, op2, op1, &set);
13652     // Note DPS88 and DPS9000 are different when NQ <= 0
13653     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13654     // ISOLTS-817 05b
13655 
13656     PRINTDEC("op2", op2);
13657     PRINTDEC("op1", op1);
13658     PRINTDEC("op3", op3);
13659 
13660     // let's check division results to see for anomalous conditions
13661     if (
13662         (set.status & DEC_Division_undefined) ||    // 0/0 will become NaN
13663         (set.status & DEC_Invalid_operation) ||
13664         (set.status & DEC_Division_by_zero)
13665         ) { sim_debug (DBG_TRACEEXT, & cpu_dev, "oops! dv3d anomalous results"); } // divide by zero has already been checked before
13666 
13667     if (e->S3 == CSFL)
13668     {
13669         // justify CSFL left
13670         // This is a flaw in the DPS8/70 hardware which was corrected in later models
13671         // Note DPS88 and DPS9000 are different
13672         // ISOLTS-817 06c,06e
13673 
13674         decNumber _sf;
13675 
13676         if (n3 - op3->digits > 0)
13677         {
13678             decNumberFromInt32(&_sf, op3->exponent - (n3 - op3->digits));
13679             PRINTDEC("Value 1", op3)
13680             PRINTDEC("Value sf", &_sf)
13681             op3 = decNumberRescale(op3, op3, &_sf, &set);
13682             PRINTDEC("Value 2", op3)
13683         }
13684     }
13685 
13686     bool Ovr = false, EOvr = false, Trunc = false;
13687     uint8_t out[256];
13688 
13689     // CSFL: If the divisor is greater than the dividend after operand
13690     // alignment, the leading zero digit produced is counted and the effective
13691     // precision of the result is reduced by one.
13692     // This is a flaw in the DPS8/70 hardware which was corrected in later models
13693     // Note DPS88 and DPS9000 are different
13694     //
13695     // "greater after operand alignment" means scale until most-significant digits
13696     //   are nonzero, then compare magnitudes ignoring exponents
13697     // This passes ISOLTS-817 06e, ET 458,461,483,486
13698     char *res;
13699     if (e->S3 == CSFL) {
13700         decNumber _1a;
13701         decNumber _2a;
13702         decNumber _sf;
13703         if (op1->digits >= op2->digits) {
13704             // scale op2
13705             decNumberCopy(&_1a, op1);
13706             decNumberFromInt32(&_sf, op1->digits - op2->digits);
13707             decNumberShift(&_2a, op2, &_sf, &set);
13708         } else if (op1->digits < op2->digits) {
13709             // scale op1
13710             decNumberFromInt32(&_sf, op2->digits - op1->digits);
13711             decNumberShift(&_1a, op1, &_sf, &set);
13712             decNumberCopy(&_2a, op2);
13713         }
13714         _1a.exponent = 0;
13715         _2a.exponent = 0;
13716 
13717         PRINTDEC("dv3d: op1a", &_1a);
13718         PRINTDEC("dv3d: op2a", &_2a);
13719         sim_debug (DBG_TRACEEXT, & cpu_dev,
13720                    "dv3d: exp1 %d exp2 %d digits op1 %d op2 %d op1a %d op2a %d\r\n",
13721                    op1->exponent ,op2->exponent, op1->digits,
13722                    op2->digits, _1a.digits, _2a.digits);
13723 
13724         if (decCompareMAG(&_1a, &_2a, &set) > 0) {
13725             // shorten the result field to get proper rounding
13726             res = formatDecimal(out, &set, op3, n3 -1, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13727 
13728             // prepend zero digit
13729             // ET 458,483 float=float/float, ET 461,486 float=fixed/fixed
13730             for (int i = n3; i > 0; i--) // incl.zero terminator
13731                  res[i] = res[i-1];
13732             res[0] = '0';
13733             sim_debug (DBG_TRACEEXT, & cpu_dev, "dv3d: addzero n3 %d %s exp %d\r\n",n3,res,op3->exponent);
13734         } else {
13735             // full n3 digits are returned
13736             res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13737         }
13738     } else {
13739         // same as all other decimal instructions
13740         res = formatDecimal(out, &set, op3, n3, (int) e->S3, e->SF3, R, &Ovr, &Trunc);
13741     }
13742 
13743     if (decNumberIsZero(op3))
13744         op3->exponent = 127;
13745 
13746     //(void)printf("%s\r\n", res);
13747 
13748     // now write to memory in proper format.....
13749 
13750     int pos = (int) dstCN;
13751 
13752     // 1st, take care of any leading sign .......
13753     switch(e->S3)
13754     {
13755         case CSFL:  // floating-point, leading sign.
13756         case CSLS:  // fixed-point, leading sign
13757             switch(dstTN)
13758             {
13759                 case CTN4:
13760                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13761                               //   then the 13(8) plus sign character is placed appropriately
13762                               //   if the result of the operation is positive.
13763                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13764                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13765                     else
13766                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13767                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13768                     break;
13769                 case CTN9:
13770                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13771                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13772                     break;
13773             }
13774             break;
13775 
13776         case CSTS:  // nuttin' to do here .....
13777         case CSNS:
13778             break;  // no sign wysiwyg
13779     }
13780 
13781     // 2nd, write the digits .....
13782     for(int i = 0 ; i < n3 ; i++)
13783         switch(dstTN)
13784         {
13785             case CTN4:
13786                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) (res[i] - '0'));
13787                 break;
13788             case CTN9:
13789                 EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (word9) res[i]);
13790                 break;
13791             }
13792 
13793     // 3rd, take care of any trailing sign or exponent ...
13794     switch(e->S3)
13795     {
13796         case CSTS:  // write trailing sign ....
13797             switch(dstTN)
13798             {
13799                 case CTN4:
13800                     if (e->P) //If TN2 and S2 specify a 4-bit signed number and P = 1,
13801                               //   then the 13(8) plus sign character is placed appropriately if
13802                               //   the result of the operation is positive.
13803                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13804                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  013);  // special +
13805                     else
13806                         EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13807                                    (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? 015 :  014);  // default +
13808                     break;
13809                 case CTN9:
13810                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,
13811                                (decNumberIsNegative(op3) && !decNumberIsZero(op3)) ? '-' : '+');
13812                 break;
13813             }
13814             break;
13815 
13816         case CSFL:  // floating-point, leading sign.
13817             // write the exponent
13818             switch(dstTN)
13819             {
13820                 case CTN4:
13821                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, (op3->exponent >> 4) & 0xf); // upper 4-bits
13822                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN,  op3->exponent       & 0xf); // lower 4-bits
13823                     break;
13824                 case CTN9:
13825                     EISwrite49(cpup, &e->ADDR3, &pos, (int) dstTN, op3->exponent & 0xff);    // write 8-bit exponent
13826                     break;
13827             }
13828             break;
13829 
13830         case CSLS:  // fixed point, leading sign - already done
13831         case CSNS:  // fixed point, unsigned - nuttin' needed to do
13832             break;
13833     }
13834 
13835     // set flags, etc ...
13836     if (e->S3 == CSFL)
13837     {
13838         if (op3->exponent > 127)
13839         {
13840             SET_I_EOFL;
13841             EOvr = true;
13842         }
13843         if (op3->exponent < -128)
13844         {
13845             SET_I_EUFL;
13846             EOvr = true;
13847         }
13848     }
13849 
13850     SC_I_NEG (decNumberIsNegative(op3) && !decNumberIsZero(op3));  // set negative indicator if op3 < 0
13851     SC_I_ZERO (decNumberIsZero(op3));     // set zero indicator if op3 == 0
13852 
13853     // SC_I_TRUNC(!R && Trunc); // no truncation flag for divide
13854 
13855     cleanupOperandDescriptor (cpup, 1);
13856     cleanupOperandDescriptor (cpup, 2);
13857     cleanupOperandDescriptor (cpup, 3);
13858 
13859     //if (TST_I_TRUNC && T && tstOVFfault (cpup))
13860     //  doFault(FAULT_OFL, fst_zero, "dv3d truncation(overflow) fault");
13861     if (EOvr && tstOVFfault (cpup))
13862         doFault(FAULT_OFL, fst_zero, "dv3d over/underflow fault");
13863     if (Ovr)
13864     {
13865         SET_I_OFLOW;
13866         if (tstOVFfault (cpup))
13867           doFault(FAULT_OFL, fst_zero, "dv3d overflow fault");
13868     }
13869 }

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