1 /* vax_cis.c: VAX CIS instructions
2 
3    Copyright (c) 2004-2008, Robert M Supnik
4 
5    Permission is hereby granted, free of charge, to any person obtaining a
6    copy of this software and associated documentation files (the "Software"),
7    to deal in the Software without restriction, including without limitation
8    the rights to use, copy, modify, merge, publish, distribute, sublicense,
9    and/or sell copies of the Software, and to permit persons to whom the
10    Software is furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be included in
13    all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18    ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22    Except as contained in this notice, the name of Robert M Supnik shall not be
23    used in advertising or otherwise to promote the sale, use or other dealings
24    in this Software without prior written authorization from Robert M Supnik.
25 
26    On a full VAX, this module simulates the VAX commercial instruction set (CIS).
27    On a subset VAX, this module implements the emulated instruction fault.
28 
29    16-Oct-08    RMS     Fixed bug in ASHP left overflow calc (Word/NibbleLShift)
30                         Fixed bug in DIVx (LntDstr calculation)
31    28-May-08    RMS     Inlined physical memory routines
32    16-May-06    RMS     Fixed bug in length calculation (Tim Stark)
33    03-May-06    RMS     Fixed MOVTC, MOVTUC to preserve cc's through page faults
34                         Fixed MOVTUC to stop on translated == escape
35                         Fixed CVTPL to set registers before destination reg write
36                         Fixed CVTPL to set correct cc bit on overflow
37                         Fixed EDITPC to preserve cc's through page faults
38                         Fixed EDITPC EO$BLANK_ZERO count, cc test
39                         Fixed EDITPC EO$INSERT to insert fill instead of blank
40                         Fixed EDITPC EO$LOAD_PLUS/MINUS to skip character
41                         (Tim Stark)
42    12-Apr-04    RMS     Cloned from pdp11_cis.c and vax_cpu1.c
43 
44    Zero length decimal strings require either zero bytes (trailing) or one byte
45    (separate, packed).
46 
47    CIS instructions can run for a very long time, so they are interruptible
48    and restartable.  In the simulator, string instructions (and EDITPC) are
49    interruptible by faults, but decimal instructions run to completion.
50    The code is unoptimized.
51 */
52 
53 #include "vax_defs.h"
54 
55 #if defined (FULL_VAX)
56 
57 /* Decimal string structure */
58 
59 #define DSTRLNT         4
60 #define DSTRMAX         (DSTRLNT - 1)
61 #define MAXDVAL         429496730                       /* 2^32 / 10 */
62 
63 #define C_SPACE         0x20                            /* ASCII chars */
64 #define C_PLUS          0x2B
65 #define C_MINUS         0x2D
66 #define C_ZERO          0x30
67 #define C_NINE          0x39
68 
69 typedef struct {
70     uint32              sign;
71     uint32              val[DSTRLNT];
72     } DSTR;
73 
74 static DSTR Dstr_zero = { 0, 0, 0, 0, 0 };
75 static DSTR Dstr_one = { 0, 0x10, 0, 0, 0 };
76 
77 extern int32 R[16];
78 extern int32 PSL;
79 extern int32 trpirq;
80 extern int32 p1;
81 extern int32 fault_PC;
82 extern int32 ibcnt, ppc;
83 extern int32 sim_interval;
84 extern jmp_buf save_env;
85 
86 int32 ReadDstr (int32 lnt, int32 addr, DSTR *dec, int32 acc);
87 int32 WriteDstr (int32 lnt, int32 addr, DSTR *dec, int32 v, int32 acc);
88 int32 SetCCDstr (int32 lnt, DSTR *src, int32 pslv);
89 int32 AddDstr (DSTR *src1, DSTR *src2, DSTR *dst, int32 cin);
90 void SubDstr (DSTR *src1, DSTR *src2, DSTR *dst);
91 int32 CmpDstr (DSTR *src1, DSTR *src2);
92 int32 TestDstr (DSTR *dsrc);
93 void ProbeDstr (int32 lnt, int32 addr, int32 acc);
94 int32 LntDstr (DSTR *dsrc, int32 nz);
95 uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin);
96 uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin);
97 int32 WordLshift (DSTR *dsrc, int32 sc);
98 void WordRshift (DSTR *dsrc, int32 sc);
99 void CreateTable (DSTR *dsrc, DSTR mtable[10]);
100 int32 do_crc_4b (int32 crc, int32 tbl, int32 acc);
101 int32 edit_read_src (int32 inc, int32 acc);
102 void edit_adv_src (int32 inc);
103 int32 edit_read_sign (int32 acc);
104 
105 extern int32 eval_int (void);
106 
107 /* CIS emulator */
108 
op_cis(int32 * op,int32 cc,int32 opc,int32 acc)109 int32 op_cis (int32 *op, int32 cc, int32 opc, int32 acc)
110 {
111 int32 i, j, c, t, pop, rpt, V;
112 int32 match, fill, sign, shift;
113 int32 ldivd, ldivr;
114 int32 lenl, lenp;
115 uint32 nc, d, result;
116 t_stat r;
117 DSTR accum, src1, src2, dst;
118 DSTR mptable[10];
119 
120 switch (opc) {                                          /* case on opcode */
121 
122 /* MOVTC
123 
124    Operands if PSL<fpd> = 0:
125         op[0:1]         =       source string descriptor
126         op[2]           =       fill character
127         op[3]           =       table address
128         op[4:5]         =       destination string descriptor
129 
130    Registers if PSL<fpd> = 1:
131         R[0]            =       delta-PC/fill/source string length
132         R[1]            =       source string address
133         R[2]            =       number of bytes remaining to move
134         R[3]            =       table address
135         R[4]            =       saved cc's/destination string length
136         R[5]            =       destination string address
137 
138    Condition codes:
139         NZC             =       set from op[0]:op[4]
140         V               =       0
141 
142    Registers:
143         R0              =       src length remaining, or 0
144         R1              =       addr of end of source string + 1
145         R2              =       0
146         R3              =       table address
147         R4              =       0
148         R5              =       addr of end of dest string + 1
149 */
150 
151     case MOVTC:
152         if (PSL & PSL_FPD) {                            /* FPD set? */
153             SETPC (fault_PC + STR_GETDPC (R[0]));       /* reset PC */
154             fill = STR_GETCHR (R[0]);                   /* get fill */
155             R[2] = R[2] & STR_LNMASK;                   /* remaining move */
156             cc = (R[4] >> 16) & CC_MASK;                /* restore cc's */
157             }
158         else {
159             CC_CMP_W (op[0], op[4]);                    /* set cc's */
160             R[0] = STR_PACK (op[2], op[0]);             /* src len, fill */
161             R[1] = op[1];                               /* src addr */
162             fill = op[2];                               /* set fill */
163             R[3] = op[3];                               /* table addr */
164             R[4] = op[4] | ((cc & CC_MASK) << 16);      /* dst len + cc's */
165             R[5] = op[5];                               /* dst addr */
166             R[2] = (op[0] < op[4])? op[0]: op[4];       /* remaining move */
167             PSL = PSL | PSL_FPD;                        /* set FPD */
168             }
169         if (R[2]) {                                     /* move to do? */
170             int32 mvl;
171             mvl = R[0] & STR_LNMASK;                    /* orig move len */
172             if (mvl >= (R[4] & STR_LNMASK))
173                 mvl = R[4] & STR_LNMASK;
174             if (((uint32) R[1]) < ((uint32) R[5])) {    /* backward? */
175                 while (R[2]) {                          /* loop thru char */
176                     t = Read ((R[1] + R[2] - 1) & LMASK, L_BYTE, RA);
177                     c = Read ((R[3] + t) & LMASK, L_BYTE, RA);
178                     Write ((R[5] + R[2] - 1) & LMASK, c, L_BYTE, WA);
179                     R[2] = (R[2] - 1) & STR_LNMASK;
180                     }
181                 R[1] = (R[1] + mvl) & LMASK;            /* adv src, dst */
182                 R[5] = (R[5] + mvl) & LMASK;
183                 }
184             else {                                      /* forward */
185                 while (R[2]) {                          /* loop thru char */
186                     t = Read (R[1], L_BYTE, RA);        /* read src */
187                     c = Read ((R[3] + t) & LMASK, L_BYTE, RA);
188                     Write (R[5], c, L_BYTE, WA);        /* write dst */
189                     R[1] = (R[1] + 1) & LMASK;          /* adv src, dst */
190                     R[2] = (R[2] - 1) & STR_LNMASK;
191                     R[5] = (R[5] + 1) & LMASK;
192                     }
193                 }                                       /* update lengths */
194             R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - mvl) & STR_LNMASK);
195             R[4] = (R[4] & ~STR_LNMASK) | ((R[4] - mvl) & STR_LNMASK);
196             }
197         while (R[4] & STR_LNMASK) {                     /* fill if needed */
198             Write (R[5], fill, L_BYTE, WA);
199             R[4] = (R[4] & ~STR_LNMASK) | ((R[4] - 1) & STR_LNMASK);
200             R[5] = (R[5] + 1) & LMASK;                  /* adv dst */
201             }
202         R[0] = R[0] & STR_LNMASK;                       /* mask off state */
203         R[4] = 0;
204         PSL = PSL & ~PSL_FPD;
205         return cc;
206 
207 /* MOVTUC
208 
209    Operands:
210         op[0:1]         =       source string descriptor
211         op[2]           =       escape character
212         op[3]           =       table address
213         op[4:5]         =       destination string descriptor
214 
215    Registers if PSL<fpd> = 1:
216         R[0]            =       delta-PC/match/source string length
217         R[1]            =       source string address
218         R[2]            =       saved condition codes
219         R[3]            =       table address
220         R[4]            =       destination string length
221         R[5]            =       destination string address
222 
223    Condition codes:
224         NZC             =       set from op[0]:op[4]
225         V               =       1 if match to escape character
226 
227    Registers:
228         R0              =       src length remaining, or 0
229         R1              =       addr of end of source string + 1
230         R2              =       0
231         R3              =       table address
232         R4              =       dst length remaining, or 0
233         R5              =       addr of end of dest string + 1
234 */
235 
236     case MOVTUC:
237         if (PSL & PSL_FPD) {                            /* FPD set? */
238             SETPC (fault_PC + STR_GETDPC (R[0]));       /* reset PC */
239             fill = STR_GETCHR (R[0]);                   /* get match */
240             R[4] = R[4] & STR_LNMASK;
241             cc = R[2] & CC_MASK;                        /* restore cc's */
242             }
243         else {
244             CC_CMP_W (op[0], op[4]);                    /* set cc's */
245             R[0] = STR_PACK (op[2], op[0]);             /* src len, fill */
246             R[1] = op[1];                               /* src addr */
247             fill = op[2];                               /* set match */
248             R[3] = op[3];                               /* table addr */
249             R[4] = op[4];                               /* dst len */
250             R[5] = op[5];                               /* dst addr */
251             R[2] = cc;                                  /* save cc's */
252             PSL = PSL | PSL_FPD;                        /* set FPD */
253             }
254         while ((R[0] & STR_LNMASK) && R[4]) {           /* while src & dst */
255             t = Read (R[1], L_BYTE, RA);                /* read src */
256             c = Read ((R[3] + t) & LMASK, L_BYTE, RA);  /* translate */
257             if (c == fill) {                            /* stop char? */
258                 cc = cc | CC_V;                         /* set V, done */
259                 break;
260                 }
261             Write (R[5], c, L_BYTE, WA);                /* write dst */
262             R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - 1) & STR_LNMASK);
263             R[1] = (R[1] + 1) & LMASK;
264             R[4] = (R[4] - 1) & STR_LNMASK;             /* adv src, dst */
265             R[5] = (R[5] + 1) & LMASK;
266             }
267         R[0] = R[0] & STR_LNMASK;                       /* mask off state */
268         R[2] = 0;
269         PSL = PSL & ~PSL_FPD;
270         return cc;
271 
272 /* MATCHC
273 
274    Operands:
275         op[0:1]         =       substring descriptor
276         op[2:3]         =       string descriptor
277 
278    Registers if PSL<fpd> = 1:
279         R[0]            =       delta-PC/match/substring length
280         R[1]            =       substring address
281         R[2]            =       source string length
282         R[3]            =       source string address
283 
284    Condition codes:
285         NZ              =       set from R0
286         VC              =       0
287 
288    Registers:
289         R0              =       if match, 0, else, op[0]
290         R1              =       if match, op[0] + op[1], else, op[1]
291         R2              =       if match, src bytes remaining, else, 0
292         R3              =       if match, end of substr, else, op[2] + op[3]
293 
294    Notes:
295         - If the string is zero length, and the substring is not,
296           the outer loop exits immediately, and the result is
297           "no match"
298         - If the substring is zero length, the inner loop always
299           exits immediately, and the result is a "match"
300         - If the string is zero length, and the substring is as
301           well, the outer loop executes, the inner loop exits
302           immediately, and the result is a match, but the result
303           is the length of the string (zero)
304         - This instruction can potentially run a very long time - worst
305           case execution on a real VAX-11/780 was more than 30 minutes.
306           Accordingly, the instruction tests for interrupts and stops
307           if one is found.
308 */
309 
310     case MATCHC:
311         if (PSL & PSL_FPD) {                            /* FPD? */
312             SETPC (fault_PC + STR_GETDPC (R[0]));       /* reset PC */
313             R[2] = R[2] & STR_LNMASK;
314             }
315         else {
316             R[0] = STR_PACK (0, op[0]);                 /* srclen + FPD data */
317             R[1] = op[1];                               /* save operands */
318             R[2] = op[2];
319             R[3] = op[3];
320             PSL = PSL | PSL_FPD;                        /* set FPD */
321             }
322         for (match = 0; R[2] >= (R[0] & STR_LNMASK); ) {
323             for (i = 0, match = 1; match && (i < (R[0] & STR_LNMASK)); i++) {
324                 c = Read ((R[1] + i) & LMASK, L_BYTE, RA);
325                 t = Read ((R[3] + i) & LMASK, L_BYTE, RA);
326                 match = (c == t);                       /* continue if match */
327                 }                                       /* end for substring */
328             if (match)                                  /* exit if match */
329                 break;
330             R[2] = (R[2] - 1) & STR_LNMASK;             /* decr src length */
331             R[3] = (R[3] + 1) & LMASK;                  /* next string char */
332             if (i >= sim_interval) {                    /* done with interval? */
333                 sim_interval = 0;
334                 if ((r = sim_process_event ())) {       /* presumably WRU */
335                     PC = fault_PC;                      /* backup up PC */
336                     ABORT (r);                          /* abort flushes IB */
337                     }
338                 SET_IRQL;                               /* update interrupts */
339                 if (trpirq)                             /* pending? stop */
340                     ABORT (ABORT_INTR);
341                 }
342             else sim_interval = sim_interval - i;
343             }                                           /* end for string */
344         R[0] = R[0] & STR_LNMASK;
345         if (match) {                                    /* if match */
346             R[1] = (R[1] + R[0]) & LMASK;
347             R[2] = (R[2] - R[0]) & STR_LNMASK;
348             R[3] = (R[3] + R[0]) & LMASK;
349             R[0] = 0;
350             }
351         else {                                          /* if no match */
352             R[3] = (R[3] + R[2]) & LMASK;
353             R[2] = 0;
354             }
355         PSL = PSL & ~PSL_FPD;
356         CC_IIZZ_L (R[0]);                               /* set cc's */
357         return cc;
358 
359 /* CRC
360 
361    Operands:
362         op[0]           =       table address
363         op[1]           =       initial CRC
364         op[2:3]         =       source string descriptor
365 
366    Registers if PSL<fpd> = 1:
367         R[0]            =       result
368         R[1]            =       table address
369         R[2]            =       delta-PC/0/source string length
370         R[3]            =       source string address
371 
372    Condition codes:
373         NZ              =       set from result
374         VC              =       0
375 
376    Registers:
377         R0              =       result
378         R1              =       0
379         R2              =       0
380         R3              =       addr + 1 of last byte in source string
381 */
382 
383     case CRC:
384         if (PSL & PSL_FPD) {                            /* FPD? */
385             SETPC (fault_PC + STR_GETDPC (R[2]));       /* reset PC */
386             }
387         else {
388             R[2] = STR_PACK (0, op[2]);                 /* srclen + FPD data */
389             R[0] = op[1];                               /* save operands */
390             R[1] = op[0];
391             R[3] = op[3];
392             PSL = PSL | PSL_FPD;                        /* set FPD */
393             }
394         while ((R[2] & STR_LNMASK) != 0) {              /* loop thru chars */
395             c = Read (R[3], L_BYTE, RA);                /* get char */
396             t = R[0] ^ c;                               /* XOR to CRC */
397             t = do_crc_4b (t, R[1], acc);               /* do 4b shift */
398             R[0] = do_crc_4b (t, R[1], acc);            /* do 4b shift */
399             R[3] = (R[3] + 1) & LMASK;
400             R[2] = R[2] - 1;
401             }
402         R[1] = 0;
403         R[2] = 0;
404         PSL = PSL & ~PSL_FPD;
405         CC_IIZZ_L (R[0]);                               /* set cc's */
406         return cc;
407 
408 /* MOVP
409 
410    Operands:
411         op[0]           =       length
412         op[1]           =       source string address
413         op[2]           =       dest string address
414 
415    Condition codes:
416         NZ              =       set from result
417         V               =       0
418         C               =       unchanged
419 
420    Registers:
421         R0              =       0
422         R1              =       addr of source string
423         R2              =       0
424         R3              =       addr of dest string
425 */
426 
427     case MOVP:
428         if ((PSL & PSL_FPD) || (op[0] > 31))
429             RSVD_OPND_FAULT;
430         ReadDstr (op[0], op[1], &dst, acc);             /* read source */
431         cc = WriteDstr (op[0], op[2], &dst, 0, acc) |   /* write dest */
432             (cc & CC_C);                                /* preserve C */
433         R[0] = 0;
434         R[1] = op[1];
435         R[2] = 0;
436         R[3] = op[2];
437         return cc;
438 
439 /* ADDP4, ADDP6, SUBP4, SUBP6
440 
441    Operands:
442         op[0:1]         =       src1 string descriptor
443         op[2:3]         =       src2 string descriptor
444         (ADDP6, SUBP6 only)
445         op[4:5]         =       dest string descriptor
446 
447    Condition codes:
448         NZV             =       set from result
449         C               =       0
450 
451    Registers:
452         R0              =       0
453         R1              =       addr of src1 string
454         R2              =       0
455         R3              =       addr of src2 string
456         (ADDP6, SUBP6 only)
457         R4              =       0
458         R5              =       addr of dest string
459 */
460 
461     case ADDP4: case SUBP4:
462         op[4] = op[2];                                  /* copy dst */
463         op[5] = op[3];
464     case ADDP6: case SUBP6:
465         if ((PSL & PSL_FPD) || (op[0] > 31) ||
466             (op[2] > 31) || (op[4] > 31))
467             RSVD_OPND_FAULT;
468         ReadDstr (op[0], op[1], &src1, acc);            /* get src1 */
469         ReadDstr (op[2], op[3], &src2, acc);            /* get src2 */
470         if (opc & 2)                                    /* sub? invert sign */
471             src1.sign = src1.sign ^ 1;
472         if (src1.sign ^ src2.sign) {                    /* opp signs?  sub */
473             if (CmpDstr (&src1, &src2) < 0) {           /* src1 < src2? */
474                 SubDstr (&src1, &src2, &dst);           /* src2 - src1 */
475                 dst.sign = src2.sign;                   /* sign = src2 */
476                 }
477             else {
478                 SubDstr (&src2, &src1, &dst);           /* src1 - src2 */
479                 dst.sign = src1.sign;                   /* sign = src1 */
480                 }
481             V = 0;                                      /* can't carry */
482             }
483         else {                                          /* addition */
484             V = AddDstr (&src1, &src2, &dst, 0);        /* add magnitudes */
485             dst.sign = src1.sign;                       /* set result sign */
486             }
487         cc = WriteDstr (op[4], op[5], &dst, V, acc);    /* store result */
488         R[0] = 0;
489         R[1] = op[1];
490         R[2] = 0;
491         R[3] = op[3];
492         if (opc & 1) {                                  /* ADDP6, SUBP6? */
493             R[4] = 0;
494             R[5] = op[5];
495             }
496         return cc;
497 
498 /* MULP
499 
500    Operands:
501         op[0:1]         =       src1 string descriptor
502         op[2:3]         =       src2 string descriptor
503         op[4:5]         =       dest string descriptor
504 
505    Condition codes:
506         NZV             =       set from result
507         C               =       0
508 
509    Registers:
510         R0              =       0
511         R1              =       addr of src1 string
512         R2              =       0
513         R3              =       addr of src2 string
514         R4              =       0
515         R5              =       addr of dest string
516 */
517 
518     case MULP:
519         if ((PSL & PSL_FPD) || (op[0] > 31) ||
520             (op[2] > 31) || (op[4] > 31))
521             RSVD_OPND_FAULT;
522         dst = Dstr_zero;                                /* clear result */
523         if (ReadDstr (op[0], op[1], &src1, acc) &&      /* read src1, src2 */
524             ReadDstr (op[2], op[3], &src2, acc)) {      /* if both > 0 */
525             dst.sign = src1.sign ^ src2.sign;           /* sign of result */
526             accum = Dstr_zero;                          /* clear accum */
527             NibbleRshift (&src1, 1, 0);                 /* shift out sign */
528             CreateTable (&src1, mptable);               /* create *1, *2, ... */
529             for (i = 1; i < (DSTRLNT * 8); i++) {       /* 31 iterations */
530                 d = (src2.val[i / 8] >> ((i % 8) * 4)) & 0xF;
531                 if (d > 0)                              /* add in digit*mpcnd */
532                     AddDstr (&mptable[d], &accum, &accum, 0);
533                 nc = NibbleRshift (&accum, 1, 0);       /* ac right 4 */
534                 NibbleRshift (&dst, 1, nc);             /* result right 4 */
535                 }
536             V = TestDstr (&accum) != 0;                 /* if ovflo, set V */
537             }
538         else V = 0;                                     /* result = 0 */
539         cc = WriteDstr (op[4], op[5], &dst, V, acc);    /* store result */
540         R[0] = 0;
541         R[1] = op[1];
542         R[2] = 0;
543         R[3] = op[3];
544         R[4] = 0;
545         R[5] = op[5];
546         return cc;
547 
548 /* DIVP
549 
550    Operands:
551         op[0:1]         =       src1 string descriptor
552         op[2:3]         =       src2 string descriptor
553         op[4:5]         =       dest string descriptor
554 
555    Condition codes:
556         NZV             =       set from result
557         C               =       0
558 
559    Registers:
560         R0              =       0
561         R1              =       addr of src1 string
562         R2              =       0
563         R3              =       addr of src2 string
564         R4              =       0
565         R5              =       addr of dest string
566 */
567 
568     case DIVP:
569         if ((PSL & PSL_FPD) || (op[0] > 31) ||
570             (op[2] > 31) || (op[4] > 31))
571             RSVD_OPND_FAULT;
572         ldivr = ReadDstr (op[0], op[1], &src1, acc);    /* get divisor */
573         if (ldivr == 0) {                               /* divisor = 0? */
574             SET_TRAP (TRAP_FLTDIV);                     /* dec div trap */
575             return cc;
576             }
577         ldivr = LntDstr (&src1, ldivr);                 /* get exact length */
578         ldivd = ReadDstr (op[2], op[3], &src2, acc);    /* get dividend */
579         ldivd = LntDstr (&src2, ldivd);                 /* get exact length */
580         dst = Dstr_zero;                                /* clear dest */
581         NibbleRshift (&src1, 1, 0);                     /* right justify ops */
582         NibbleRshift (&src2, 1, 0);
583         if ((t = ldivd - ldivr) >= 0) {                 /* any divide to do? */
584             dst.sign = src1.sign ^ src2.sign;           /* calculate sign */
585             WordLshift (&src1, t / 8);                  /* align divr to divd */
586             NibbleLshift (&src1, t % 8, 0);
587             CreateTable (&src1, mptable);               /* create *1, *2, ... */
588             for (i = 0; i <= t; i++) {                  /* divide loop */
589                 for (d = 9; d > 0; d--) {               /* find digit */
590                     if (CmpDstr (&src2, &mptable[d]) >= 0) {
591                         SubDstr (&mptable[d], &src2, &src2);
592                         dst.val[0] = dst.val[0] | d;
593                         break;
594                         }                               /* end if */
595                     }                                   /* end for */
596                 NibbleLshift (&src2, 1, 0);             /* shift dividend */
597                 NibbleLshift (&dst, 1, 0);              /* shift quotient */
598                 }                                       /* end divide loop */
599             }                                           /* end if */
600         cc = WriteDstr (op[4], op[5], &dst, 0, acc);    /* store result */
601         R[0] = 0;
602         R[1] = op[1];
603         R[2] = 0;
604         R[3] = op[3];
605         R[4] = 0;
606         R[5] = op[5];
607         return cc;
608 
609 /* CMPP3, CMPP4
610 
611    Operands (CMPP3):
612         op[0]           =       string length
613         op[1], op[2]    =       string lengths
614 
615    Operands (CMPP4):
616         op[0:1]         =       string1 descriptor
617         op[2:3]         =       string2 descriptor
618 
619    Condition codes:
620         NZ              =       set from comparison
621         VC              =       0
622 
623    Registers:
624         R0              =       0
625         R1              =       addr of src1 string
626         R2              =       0
627         R3              =       addr of src2 string
628 */
629 
630     case CMPP3:
631         op[3] = op[2];                                  /* reposition ops */
632         op[2] = op[0];
633     case CMPP4:
634         if ((PSL & PSL_FPD) || (op[0] > 31) || (op[2] > 31))
635             RSVD_OPND_FAULT;
636         ReadDstr (op[0], op[1], &src1, acc);            /* get src1 */
637         ReadDstr (op[2], op[3], &src2, acc);            /* get src2 */
638         cc = 0;
639         if (src1.sign != src2.sign) cc = (src1.sign)? CC_N: 0;
640         else {
641             t = CmpDstr (&src1, &src2);                 /* compare strings */
642             if (t < 0)
643                 cc = (src1.sign? 0: CC_N);
644             else if (t > 0)
645                 cc = (src1.sign? CC_N: 0);
646             else cc = CC_Z;
647             }
648         R[0] = 0;
649         R[1] = op[1];
650         R[2] = 0;
651         R[3] = op[3];
652         return cc ;
653 
654 /* ASHP
655 
656    Operands:
657         op[0]           =       shift count
658         op[1:2]         =       source string descriptor
659         op[3]           =       round digit
660         op[4:5]         =       dest string descriptor
661 
662    Condition codes:
663         NZV             =       set from result
664         C               =       0
665 
666    Registers:
667         R0              =       0
668         R1              =       addr of src1 string
669         R2              =       0
670         R3              =       addr of src2 string
671 */
672 
673     case ASHP:
674         if ((PSL & PSL_FPD) || (op[1] > 31) || (op[4] > 31))
675             RSVD_OPND_FAULT;
676         ReadDstr (op[1], op[2], &src1, acc);            /* get source */
677         V = 0;                                          /* init V */
678         shift = op[0];                                  /* get shift count */
679         if (shift & BSIGN) {                            /* right shift? */
680             shift = BMASK + 1 - shift;                  /* !shift! */
681             WordRshift (&src1, shift / 8);              /* do word shifts */
682             NibbleRshift (&src1, shift % 8, 0);         /* do nibble shifts */
683             t = op[3] & 0xF;                            /* get round nibble */
684             if ((t + (src1.val[0] & 0xF)) > 9)          /* rounding needed? */
685                 AddDstr (&src1, &Dstr_one, &src1, 0);   /* round */
686             src1.val[0] = src1.val[0] & ~0xF;           /* clear sign */
687             }                                           /* end right shift */
688         else if (shift) {                               /* left shift? */
689             if (WordLshift (&src1, shift / 8))          /* do word shifts */
690                 V = 1;
691             if (NibbleLshift (&src1, shift % 8, 0))
692                 V = 1;
693             }                                           /* end left shift */
694         cc = WriteDstr (op[4], op[5], &src1, V, acc);   /* store result */
695         R[0] = 0;
696         R[1] = op[2];
697         R[2] = 0;
698         R[3] = op[5];
699         return cc ;
700 
701 /* CVTPL
702 
703    Operands:
704         op[0:1]         =       source string descriptor
705         op[2]           =       memory flag/register number
706         op[3]           =       memory address
707 
708    Condition codes:
709         NZV             =       set from result
710         C               =       0
711 
712    Registers:
713         R0              =       0
714         R1              =       addr of source string
715         R2              =       0
716         R3              =       0
717 */
718 
719     case CVTPL:
720         if ((PSL & PSL_FPD) || (op[0] > 31))
721             RSVD_OPND_FAULT;
722         ReadDstr (op[0], op[1], &src1, acc);            /* get source */
723         V = result = 0;                                 /* clear V, result */
724         for (i = (DSTRLNT * 8) - 1; i > 0; i--) {       /* loop thru digits */
725             d = (src1.val[i / 8] >> ((i % 8) * 4)) & 0xF;
726             if (d || result || V) {                     /* skip initial 0's */
727                 if (result >= MAXDVAL)
728                     V = 1;
729                 result = ((result * 10) + d) & LMASK;
730                 if (result < d)
731                     V = 1;
732                 }                                       /* end if */
733             }                                           /* end for */
734         if (src1.sign)                                  /* negative? */
735             result = (~result + 1) & LMASK;
736         if (src1.sign ^ ((result & LSIGN) != 0))        /* test for overflow */
737             V = 1;
738         if (op[2] < 0)                                  /* if mem, store result */
739             Write (op[3], result, L_LONG, WA);          /* before reg update */
740         R[0] = 0;                                       /* update registers */
741         R[1] = op[1];
742         R[2] = 0;
743         R[3] = 0;
744         if (op[2] >= 0)                                 /* if reg, store result */
745             R[op[2]] = result;                          /* after reg update */
746         if (V && (PSL & PSW_IV))                        /* ovflo and IV? trap */
747             SET_TRAP (TRAP_INTOV);
748         CC_IIZZ_L (result);
749         return cc | (V? CC_V: 0);
750 
751 /* CVTLP
752 
753    Operands:
754         op[0]           =       source long
755         op[1:2]         =       dest string descriptor
756 
757    Condition codes:
758         NZV             =       set from result
759         C               =       0
760 
761    Registers:
762         R0              =       0
763         R1              =       0
764         R2              =       0
765         R3              =       addr of dest string
766 */
767 
768     case CVTLP:
769         if ((PSL & PSL_FPD) || (op[1] > 31))
770             RSVD_OPND_FAULT;
771         dst = Dstr_zero;                                /* clear result */
772         result = op[0];
773         if ((result & LSIGN) != 0) {
774             dst.sign = 1;
775             result = (~result + 1) & LMASK;
776             }
777         for (i = 1; (i < (DSTRLNT * 8)) && result; i++) {
778             d = result % 10;
779             result = result / 10;
780             dst.val[i / 8] = dst.val[i / 8] | (d << ((i % 8) * 4));
781             }
782         cc = WriteDstr (op[1], op[2], &dst, 0, acc);    /* write result */
783         R[0] = 0;
784         R[1] = 0;
785         R[2] = 0;
786         R[3] = op[2];
787         return cc;
788 
789 /* CVTSP
790 
791    Operands:
792         op[0:1]         =       source string descriptor
793         op[2:3]         =       dest string descriptor
794 
795    Condition codes:
796         NZV             =       set from result
797         C               =       0
798 
799    Registers:
800         R0              =       0
801         R1              =       address of sign byte of source string
802         R2              =       0
803         R3              =       addr of dest string
804 */
805 
806     case CVTSP:
807         if ((PSL & PSL_FPD) || (op[0] > 31) || (op[2] > 31))
808             RSVD_OPND_FAULT;
809         dst = Dstr_zero;                                /* clear result */
810         t = Read (op[1], L_BYTE, RA);                   /* read source sign */
811         if (t == C_MINUS)                               /* sign -, */
812             dst.sign = 1;
813         else if ((t != C_PLUS) && (t != C_SPACE))       /* + or blank? */
814             RSVD_OPND_FAULT;
815         for (i = 1; i <= op[0]; i++) {                  /* loop thru chars */
816             c = Read ((op[1] + op[0] + 1 - i) & LMASK, L_BYTE, RA);
817             if ((c < C_ZERO) || (c > C_NINE))           /* [0:9]? */
818                 RSVD_OPND_FAULT;
819             d = c & 0xF;
820             dst.val[i / 8] = dst.val[i / 8] | (d << ((i % 8) * 4));
821             }
822         TestDstr (&dst);                                /* correct -0 */
823         cc = WriteDstr (op[2], op[3], &dst, 0, acc);    /* write result */
824         R[0] = 0;
825         R[1] = op[1];
826         R[2] = 0;
827         R[3] = op[3];
828         return cc;
829 
830 /* CVTPS
831 
832    Operands:
833         op[0:1]         =       source string descriptor
834         op[2:3]         =       dest string descriptor
835 
836    Condition codes:
837         NZV             =       set from result
838         C               =       0
839 
840    Registers:
841         R0              =       0
842         R1              =       addr of source string
843         R2              =       0
844         R3              =       addr of dest string
845 */
846 
847     case CVTPS:
848         if ((PSL & PSL_FPD) || (op[0] > 31) || (op[2] > 31))
849             RSVD_OPND_FAULT;
850         lenl = ReadDstr (op[0], op[1], &dst, acc);      /* get source, lw len */
851         lenp = LntDstr (&dst, lenl);                    /* get exact nz src len */
852         ProbeDstr (op[2], op[3], WA);                   /* test dst write */
853         Write (op[3], dst.sign? C_MINUS: C_PLUS, L_BYTE, WA);
854         for (i = 1; i <= op[2]; i++) {                  /* loop thru chars */
855             d = (dst.val[i / 8] >> ((i % 8) * 4)) & 0xF;/* get digit */
856             c = d | C_ZERO;                             /* cvt to ASCII */
857             Write ((op[3] + op[2] + 1 - i) & LMASK, c, L_BYTE, WA);
858             }
859         cc = SetCCDstr (op[0], &dst, 0);                /* set cc's */
860         if (lenp > op[2]) {                             /* src fit in dst? */
861             cc = cc | CC_V;                             /* set ovflo */
862             if (PSL & PSW_DV) SET_TRAP (TRAP_DECOVF);   /* if enabled, trap */
863             }
864         R[0] = 0;
865         R[1] = op[1];
866         R[2] = 0;
867         R[3] = op[3];
868         return cc;
869 
870 /* CVTTP
871 
872    Operands:
873         op[0:1]         =       source string descriptor
874         op[2]           =       table address
875         op[3:4]         =       dest string descriptor
876 
877    Condition codes:
878         NZV             =       set from result
879         C               =       0
880 
881    Registers:
882         R0              =       0
883         R1              =       addr of source string
884         R2              =       0
885         R3              =       addr of dest string
886 */
887 
888     case CVTTP:
889         if ((PSL & PSL_FPD) || (op[0] > 31) || (op[3] > 31))
890             RSVD_OPND_FAULT;
891         dst = Dstr_zero;                                /* clear result */
892         for (i = 1; i <= op[0]; i++) {                  /* loop thru char */
893             c = Read ((op[1] + op[0] - i) & LMASK, L_BYTE, RA); /* read char */
894             if (i != 1) {                               /* normal byte? */
895                 if ((c < C_ZERO) || (c > C_NINE))       /* valid digit? */
896                     RSVD_OPND_FAULT;
897                 d = c & 0xF;
898                 }
899             else {                                      /* highest byte */
900                 t = Read ((op[2] + c) & LMASK, L_BYTE, RA); /* xlate */
901                 d = (t >> 4) & 0xF;                     /* digit */
902                 t = t & 0xF;                            /* sign */
903                 if ((d > 0x9) || (t < 0xA))
904                     RSVD_OPND_FAULT;
905                 if ((t == 0xB) || (t == 0xD))
906                     dst.sign = 1;
907                 }
908             dst.val[i / 8] = dst.val[i / 8] | (d << ((i % 8) * 4));
909             }
910         TestDstr (&dst);                                /* correct -0 */
911         cc = WriteDstr (op[3], op[4], &dst, 0, acc);    /* write result */
912         R[0] = 0;
913         R[1] = op[1];
914         R[2] = 0;
915         R[3] = op[4];
916         return cc;
917 
918 /* CVTPT
919 
920    Operands:
921         op[0:1]         =       source string descriptor
922         op[2]           =       table address
923         op[3:4]         =       dest string descriptor
924 
925    Condition codes:
926         NZV             =       set from result
927         C               =       0
928 
929    Registers:
930         R0              =       0
931         R1              =       addr of source string
932         R2              =       0
933         R3              =       addr of dest string
934 */
935 
936     case CVTPT:
937         if ((PSL & PSL_FPD) || (op[0] > 31) || (op[3] > 31))
938             RSVD_OPND_FAULT;
939         lenl = ReadDstr (op[0], op[1], &dst, acc);      /* get source, lw len */
940         lenp = LntDstr (&dst, lenl);                    /* get exact src len */
941         ProbeDstr (op[3], op[4], WA);                   /* test writeability */
942         for (i = 1; i <= op[3]; i++) {                  /* loop thru chars */
943             if (i != 1) {                               /* not last? */
944                 d = (dst.val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */
945                 c = d + C_ZERO;                         /* convert */
946                 }
947             else {                                      /* translate last */
948                 t = Read ((op[1] + (op[0] / 2)) & LMASK, L_BYTE, RA);
949                 c = Read ((op[2] + t) & LMASK, L_BYTE, RA);
950                 }
951             Write ((op[4] + op[3] - i) & LMASK, c, L_BYTE, WA);
952             }
953         cc = SetCCDstr (op[0], &dst, 0);                /* set cc's from src */
954         if (lenp > op[3]) {                             /* src fit in dst? */
955             cc = cc | CC_V;                             /* set ovflo */
956             if (PSL & PSW_DV) SET_TRAP (TRAP_DECOVF);   /* if enabled, trap */
957             }
958         R[0] = 0;
959         R[1] = op[1];
960         R[2] = 0;
961         R[3] = op[4];
962         return cc;
963 
964 /* EDITPC
965 
966    Operands:
967         op[0:1]         =       source string descriptor
968         op[2]           =       pattern string address
969         op[3]           =       dest string address
970 
971    Condition codes:
972         N               =       source is negative
973         Z               =       source is zero
974         V               =       significant digits lost
975         C               =       significant digits seen
976 
977    Registers at packup:
978         R0<31:16>       =       -count of source zeroes to supply
979         R0<15:0>        =       remaining source length
980         R1              =       source address
981         R2<31:24>       =       delta PC
982         R2<19:16>       =       condition codes
983         R2<15:8>        =       sign char
984         R2<7:0>         =       fill char
985         R3              =       pattern string address
986         R4              =       original source length
987         R5              =       dest string addr
988 
989    Registers at end:
990         R0              =       source length
991         R1              =       source addr
992         R2              =       0
993         R3              =       addr of byte containing EO$END
994         R4              =       0
995         R5              =       addr of end of dst string + 1
996 
997    Fault and abort conditions for EDITPC are complicated.  In general:
998    - It is safe to take a memory management fault on the read of
999      any pattern byte.  After correction of the fault, the pattern
1000      operator is fetched and executed again.
1001    - It is safe to take a memory management fault on a write-only
1002      operation, like fill.  After correction of the fault, the
1003      pattern operator is fetched and executed again.
1004    - The move operators do not alter visible state (registers or saved cc)
1005      until all memory operations are complete.
1006 */
1007 
1008     case EDITPC:
1009         if (PSL & PSL_FPD) {                            /* FPD set? */
1010             SETPC (fault_PC + STR_GETDPC (R[2]));       /* reset PC */
1011             fill = ED_GETFILL (R[2]);                   /* get fill */
1012             sign = ED_GETSIGN (R[2]);                   /* get sign */
1013             cc = ED_GETCC (R[2]);                       /* get cc's */
1014             R[0] = R[0] & ~0xFFE0;                      /* src len <= 31 */
1015             }
1016         else {                                          /* new instr */
1017             if (op[0] > 31)                             /* lnt > 31? */
1018                 RSVD_OPND_FAULT;
1019             t = Read ((op[1] + (op[0] / 2)) & LMASK, L_BYTE, RA) & 0xF;
1020             if ((t == 0xB) || (t == 0xD)) {
1021                 cc = CC_N | CC_Z;
1022                 sign = C_MINUS;
1023                 }
1024             else {
1025                 cc = CC_Z;
1026                 sign = C_SPACE;
1027                 }
1028             fill = C_SPACE;
1029             R[0] = R[4] = op[0];                        /* src len */
1030             R[1] = op[1];                               /* src addr */
1031             R[2] = STR_PACK (cc, (sign << ED_V_SIGN) | (fill << ED_V_FILL));
1032                                                         /* delta PC, cc, sign, fill */
1033             R[3] = op[2];                               /* pattern */
1034             R[5] = op[3];                               /* dst addr */
1035             PSL = PSL | PSL_FPD;                        /* set FPD */
1036             }
1037 
1038         for ( ;; ) {                                    /* loop thru pattern */
1039             pop = Read (R[3], L_BYTE, RA);              /* rd pattern op */
1040             if (pop == EO_END)                          /* end? */
1041                 break;
1042             if (pop & EO_RPT_FLAG) {                    /* repeat class? */
1043                 rpt = pop & EO_RPT_MASK;                /* isolate count */
1044                 if (rpt == 0)                           /* can't be zero */
1045                     RSVD_OPND_FAULT;
1046                 pop = pop & ~EO_RPT_MASK;               /* isolate op */
1047                 }
1048             switch (pop) {                              /* case on op */
1049 
1050             case EO_END_FLOAT:                          /* end float */
1051                 if (!(cc & CC_C)) {                     /* not signif? */
1052                     Write (R[5], sign, L_BYTE, WA);     /* write sign */
1053                     R[5] = (R[5] + 1) & LMASK;          /* now fault safe */
1054                     cc = cc | CC_C;                     /* set signif */
1055                     }
1056                 break;
1057 
1058             case EO_CLR_SIGNIF:                         /* clear signif */
1059                 cc = cc & ~CC_C;                        /* clr C */
1060                 break;
1061 
1062             case EO_SET_SIGNIF:                         /* set signif */
1063                 cc = cc | CC_C;                         /* set C */
1064                 break;
1065 
1066             case EO_STORE_SIGN:                         /* store sign */
1067                 Write (R[5], sign, L_BYTE, WA);         /* write sign */
1068                 R[5] = (R[5] + 1) & LMASK;              /* now fault safe */
1069                 break;
1070 
1071             case EO_LOAD_FILL:                          /* load fill */
1072                 fill = Read ((R[3] + 1) & LMASK, L_BYTE, RA);
1073                 R[2] = ED_PUTFILL (R[2], fill);         /* now fault safe */
1074                 R[3]++;
1075                 break;
1076 
1077             case EO_LOAD_SIGN:                          /* load sign */
1078                 sign = edit_read_sign (acc);
1079                 R[3]++;
1080                 break;
1081 
1082             case EO_LOAD_PLUS:                          /* load sign if + */
1083                 if (!(cc & CC_N))
1084                     sign = edit_read_sign (acc);
1085                 R[3]++;
1086                 break;
1087 
1088             case EO_LOAD_MINUS:                         /* load sign if - */
1089                 if (cc & CC_N)
1090                     sign = edit_read_sign (acc);
1091                 R[3]++;
1092                 break;
1093 
1094             case EO_INSERT:                             /* insert char */
1095                 c = Read ((R[3] + 1) & LMASK, L_BYTE, RA);
1096                 Write (R[5], ((cc & CC_C)? c: fill), L_BYTE, WA);
1097                 R[5] = (R[5] + 1) & LMASK;              /* now fault safe */
1098                 R[3]++;
1099                 break;
1100 
1101             case EO_BLANK_ZERO:                         /* blank zero */
1102                 t = Read ((R[3] + 1) & LMASK, L_BYTE, RA);
1103                 if (t == 0)
1104                     RSVD_OPND_FAULT;
1105                 if (cc & CC_Z) {                        /* zero? */
1106                     do {                                /* repeat and blank */
1107                         Write ((R[5] - t) & LMASK, fill, L_BYTE, WA);
1108                         } while (--t);
1109                     }
1110                 R[3]++;                                 /* now fault safe */
1111                 break;
1112 
1113             case EO_REPL_SIGN:                          /* replace sign */
1114                 t = Read ((R[3] + 1) & LMASK, L_BYTE, RA);
1115                 if (t == 0)
1116                     RSVD_OPND_FAULT;
1117                 if (cc & CC_Z)
1118                     Write ((R[5] - t) & LMASK, fill, L_BYTE, WA);
1119                 R[3]++;                                 /* now fault safe */
1120                 break;
1121 
1122             case EO_ADJUST_LNT:                         /* adjust length */
1123                 t = Read ((R[3] + 1) & LMASK, L_BYTE, RA);
1124                 if ((t == 0) || (t > 31))
1125                     RSVD_OPND_FAULT;
1126                 R[0] = R[0] & WMASK;                    /* clr old ld zero */
1127                 if (R[0] > t) {                         /* decrease */
1128                     for (i = 0; i < (R[0] - t); i++) {  /* loop thru src */
1129                         d = edit_read_src (i, acc);     /* get nibble */
1130                         if (d)
1131                             cc = (cc | CC_V | CC_C) & ~CC_Z;
1132                         }                               /* end for */
1133                     edit_adv_src (R[0] - t);            /* adv src ptr */
1134                     }                                   /* end else */
1135                 else R[0] = R[0] | (((R[0] - t) & WMASK) << 16);
1136                 R[3]++;
1137                 break;
1138 
1139             case EO_FILL:                               /* fill */
1140                 for (i = 0; i < rpt; i++)               /* fill string */
1141                     Write ((R[5] + i) & LMASK, fill, L_BYTE, WA);
1142                 R[5] = (R[5] + rpt) & LMASK;            /* now fault safe */
1143                 break;
1144 
1145             case EO_MOVE:
1146                 for (i = 0; i < rpt; i++) {             /* for repeat */
1147                     d = edit_read_src (i, acc);         /* get nibble */
1148                     if (d)                              /* test for non-zero */
1149                         cc = (cc | CC_C) & ~CC_Z;
1150                     c = (cc & CC_C)? (d | 0x30): fill;  /* test for signif */
1151                     Write ((R[5] + i) & LMASK, c, L_BYTE, WA);
1152                     }                                   /* end for */
1153                 edit_adv_src (rpt);                     /* advance src */
1154                 R[5] = (R[5] + rpt) & LMASK;            /* advance dst */
1155                 break;
1156 
1157             case EO_FLOAT:
1158                 for (i = j = 0; i < rpt; i++, j++) {    /* for repeat */
1159                     d = edit_read_src (i, acc);         /* get nibble */
1160                     if (d && !(cc & CC_C)) {            /* nz, signif clear? */
1161                         Write ((R[5] + j) & LMASK, sign, L_BYTE, WA);
1162                         cc = (cc | CC_C) & ~CC_Z;       /* set signif */
1163                         j++;                            /* extra dst char */
1164                         }                               /* end if */
1165                     c = (cc & CC_C)? (d | 0x30): fill;  /* test for signif */
1166                     Write ((R[5] + j) & LMASK, c, L_BYTE, WA);
1167                     }                                   /* end for */
1168                 edit_adv_src (rpt);                     /* advance src */
1169                 R[5] = (R[5] + j) & LMASK;              /* advance dst */
1170                 break;
1171 
1172             default:                                    /* undefined */
1173                 RSVD_OPND_FAULT;
1174                 }                                       /* end case pattern */
1175 
1176             R[3] = (R[3] + 1) & LMASK;                  /* next pattern byte */
1177             R[2] = ED_PUTCC (R[2], cc);                 /* update cc's */
1178             }                                           /* end for pattern */
1179 
1180         if (R[0])                                       /* pattern too short */
1181             RSVD_OPND_FAULT;
1182         PSL = PSL & ~PSL_FPD;                           /* clear FPD */
1183         if (cc & CC_Z)                                  /* zero? clear n */
1184             cc = cc & ~CC_N;
1185         if ((cc & CC_V) && (PSL & PSW_DV))              /* overflow & trap enabled? */
1186             SET_TRAP (TRAP_DECOVF);
1187         R[0] = R[4];                                    /* restore src len */
1188         R[1] = R[1] - (R[0] >> 1);                      /* restore src addr */
1189         R[2] = R[4] = 0;
1190         return cc;
1191 
1192     default:
1193         RSVD_INST_FAULT;
1194         }
1195                                                         /* end case op */
1196 return cc;
1197 }
1198 
1199 /* Get packed decimal string
1200 
1201    Arguments:
1202         lnt     =       decimal string length
1203         adr     =       decimal string address
1204         src     =       decimal string structure
1205         acc     =       access mode
1206 
1207    The routine returns the length in int32's of the non-zero part of
1208    the string.
1209 
1210    To simplify the code elsewhere, digits are range checked,
1211    and bad digits cause a fault.
1212 */
1213 
ReadDstr(int32 lnt,int32 adr,DSTR * src,int32 acc)1214 int32 ReadDstr (int32 lnt, int32 adr, DSTR *src, int32 acc)
1215 {
1216 int32 c, i, end, t;
1217 
1218 *src = Dstr_zero;                                       /* clear result */
1219 end = lnt / 2;                                          /* last byte */
1220 for (i = 0; i <= end; i++) {                            /* loop thru string */
1221     c = Read ((adr + end - i) & LMASK, L_BYTE, RA);     /* get byte */
1222     if (i == 0) {                                       /* sign char? */
1223         t = c & 0xF;                                    /* save sign */
1224         c = c & 0xF0;                                   /* erase sign */
1225         }
1226     if ((i == end) && ((lnt & 1) == 0))
1227         c = c & 0xF;
1228 /*    if (((c & 0xF0) > 0x90) ||                          /* check hi digit */
1229 /*        ((c & 0x0F) > 0x09))                            /* check lo digit */
1230 /*        RSVD_OPND_FAULT; */
1231     src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8));
1232     }                                                   /* end for */
1233 if ((t == 0xB) || (t == 0xD))                           /* if -, set sign */
1234     src->sign = 1;
1235 return TestDstr (src);                                  /* clean -0 */
1236 }
1237 
1238 /* Store decimal string
1239 
1240    Arguments:
1241         lnt     =       decimal string length
1242         adr     =       decimal string address
1243         dst     =       decimal string structure
1244         V       =       initial overflow flag
1245         acc     =       access mode
1246 
1247    Returns condition codes.
1248 
1249    PSL.NZ are also set to their proper values
1250    PSL.V will be set on overflow; it must be initialized elsewhere
1251         (to allow for external overflow calculations)
1252 
1253    The rules for the stored sign and the PSW sign are:
1254 
1255    - Stored sign is negative if input is negative, and the result
1256      is non-zero or there was overflow
1257    - PSL sign is negative if input is negative, and the result is
1258      non-zero
1259 
1260    Thus, the stored sign and the PSL sign will differ in one case:
1261    a negative zero generated by overflow is stored with a negative
1262    sign, but PSL.N is clear
1263 */
1264 
WriteDstr(int32 lnt,int32 adr,DSTR * dst,int32 pslv,int32 acc)1265 int32 WriteDstr (int32 lnt, int32 adr, DSTR *dst, int32 pslv, int32 acc)
1266 {
1267 int32 c, i, cc, end;
1268 
1269 end = lnt / 2;                                          /* end of string */
1270 ProbeDstr (end, adr, WA);                               /* test writeability */
1271 cc = SetCCDstr (lnt, dst, pslv);                        /* set cond codes */
1272 dst->val[0] = dst->val[0] | 0xC | dst->sign;            /* set sign */
1273 for (i = 0; i <= end; i++) {                            /* store string */
1274     c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF;
1275     Write ((adr + end - i) & LMASK, c, L_BYTE, WA);
1276     }                                                   /* end for */
1277 return cc;
1278 }
1279 
1280 /* Set CC for decimal string
1281 
1282    Arguments:
1283         lnt     =       string length
1284         dst     =       decimal string structure
1285         pslv    =       initial V
1286 
1287    Output:
1288         cc      =       condition codes
1289 */
1290 
SetCCDstr(int32 lnt,DSTR * dst,int32 pslv)1291 int32 SetCCDstr (int32 lnt, DSTR *dst, int32 pslv)
1292 {
1293 int32 psln, pslz, i, limit;
1294 uint32 mask;
1295 static uint32 masktab[8] = {
1296     0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,
1297     0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000
1298     };
1299 
1300 mask = 0;                                               /* can't ovflo */
1301 pslz = 1;                                               /* assume all 0's */
1302 limit = lnt / 8;                                        /* limit for test */
1303 for (i = 0; i < DSTRLNT; i++) {                         /* loop thru value */
1304     if (i == limit)                                     /* at limit, get mask */
1305         mask = masktab[lnt % 8];
1306     else if (i > limit)                                 /* beyond, all ovflo */
1307         mask = 0xFFFFFFFF;
1308     if (dst->val[i] & mask)                             /* test for ovflo */
1309         pslv = 1;
1310     dst->val[i] = dst->val[i] & ~mask;                  /* clr digits past end */
1311     if (dst->val[i])                                    /* test nz */
1312         pslz = 0;
1313     }
1314 dst->sign = dst->sign & ~(pslz & ~pslv);
1315 psln = dst->sign & ~pslz;                               /* N = sign, if ~zero */
1316 if (pslv && (PSL & PSW_DV))
1317     SET_TRAP (TRAP_DECOVF);
1318 return (psln? CC_N: 0) | (pslz? CC_Z: 0) | (pslv? CC_V: 0);
1319 }
1320 
1321 /* Probe decimal string for accessibility */
1322 
ProbeDstr(int32 lnt,int32 addr,int32 acc)1323 void ProbeDstr (int32 lnt, int32 addr, int32 acc)
1324 {
1325 Read (addr, L_BYTE, acc);
1326 Read ((addr + lnt) & LMASK, L_BYTE, acc);
1327 return;
1328 }
1329 
1330 /* Add decimal string magnitudes
1331 
1332    Arguments:
1333         s1      =       src1 decimal string
1334         s2      =       src2 decimal string
1335         ds      =       dest decimal string
1336         cy      =       carry in
1337    Output       =       1 if carry, 0 if no carry
1338 
1339    This algorithm courtesy Anton Chernoff, circa 1992 or even earlier.
1340 
1341    We trace the history of a pair of adjacent digits to see how the
1342    carry is fixed; each parenthesized item is a 4b digit.
1343 
1344    Assume we are adding:
1345 
1346         (a)(b)  I
1347    +    (x)(y)  J
1348 
1349    First compute I^J:
1350 
1351         (a^x)(b^y)      TMP
1352 
1353    Note that the low bit of each digit is the same as the low bit of
1354    the sum of the digits, ignoring the carry, since the low bit of the
1355    sum is the xor of the bits.
1356 
1357    Now compute I+J+66 to get decimal addition with carry forced left
1358    one digit:
1359 
1360         (a+x+6+carry mod 16)(b+y+6 mod 16)      SUM
1361 
1362    Note that if there was a carry from b+y+6, then the low bit of the
1363    left digit is different from the expected low bit from the xor.
1364    If we xor this SUM into TMP, then the low bit of each digit is 1
1365    if there was a carry, and 0 if not.  We need to subtract 6 from each
1366    digit that did not have a carry, so take ~(SUM ^ TMP) & 0x11, shift
1367    it right 4 to the digits that are affected, and subtract 6*adjustment
1368    (actually, shift it right 3 and subtract 3*adjustment).
1369 */
1370 
AddDstr(DSTR * s1,DSTR * s2,DSTR * ds,int32 cy)1371 int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy)
1372 {
1373 int32 i;
1374 uint32 sm1, sm2, tm1, tm2, tm3, tm4;
1375 
1376 for (i = 0; i < DSTRLNT; i++) {                         /* loop low to high */
1377     tm1 = s1->val[i] ^ (s2->val[i] + cy);               /* xor operands */
1378     sm1 = s1->val[i] + (s2->val[i] + cy);               /* sum operands */
1379     sm2 = sm1 + 0x66666666;                             /* force carry out */
1380     cy = ((sm1 < s1->val[i]) || (sm2 < sm1));           /* check for overflow */
1381     tm2 = tm1 ^ sm2;                                    /* get carry flags */
1382     tm3 = (tm2 >> 3) | (cy << 29);                      /* compute adjustment */
1383     tm4 = 0x22222222 & ~tm3;                            /* clear where carry */
1384     ds->val[i] = (sm2 - (3 * tm4)) & LMASK;             /* final result */
1385     }
1386 return cy;
1387 }
1388 
1389 /* Subtract decimal string magnitudes
1390 
1391    Arguments:
1392         s1      =       src1 decimal string
1393         s2      =       src2 decimal string
1394         ds      =       dest decimal string
1395    Outputs:             s2 - s1 in ds
1396 
1397    Note: the routine assumes that s1 <= s2
1398 
1399 */
1400 
SubDstr(DSTR * s1,DSTR * s2,DSTR * ds)1401 void SubDstr (DSTR *s1, DSTR *s2, DSTR *ds)
1402 {
1403 int32 i;
1404 DSTR compl;
1405 
1406 for (i = 0; i < DSTRLNT; i++)                           /* 10's comp s2 */
1407     compl.val[i] = 0x99999999 - s1->val[i];
1408 AddDstr (&compl, s2, ds, 1);                            /* s1 + ~s2 + 1 */
1409 return;
1410 }
1411 
1412 /* Compare decimal string magnitudes
1413 
1414    Arguments:
1415         s1      =       src1 decimal string
1416         s2      =       src2 decimal string
1417    Output       =       1 if >, 0 if =, -1 if <
1418 */
1419 
CmpDstr(DSTR * s1,DSTR * s2)1420 int32 CmpDstr (DSTR *s1, DSTR *s2)
1421 {
1422 int32 i;
1423 
1424 for (i = DSTRMAX; i >=0; i--) {
1425     if (s1->val[i] > s2->val[i])
1426         return 1;
1427     if (s1->val[i] < s2->val[i])
1428         return -1;
1429     }
1430 return 0;
1431 }
1432 
1433 /* Test decimal string for zero
1434 
1435    Arguments:
1436         dsrc    =       decimal string structure
1437 
1438    Returns the non-zero length of the string, in int32 units
1439    If the string is zero, the sign is cleared
1440 */
1441 
TestDstr(DSTR * dsrc)1442 int32 TestDstr (DSTR *dsrc)
1443 {
1444 int32 i;
1445 
1446 for (i = DSTRMAX; i >= 0; i--) {
1447     if (dsrc->val[i])
1448         return (i + 1);
1449     }
1450 dsrc->sign = 0;
1451 return 0;
1452 }
1453 
1454 /* Get exact length of decimal string
1455 
1456    Arguments:
1457         dsrc    =       decimal string structure
1458         nz      =       result from TestDstr
1459 */
1460 
LntDstr(DSTR * dsrc,int32 nz)1461 int32 LntDstr (DSTR *dsrc, int32 nz)
1462 {
1463 int32 i;
1464 
1465 if (nz == 0)
1466     return 0;
1467 for (i = 7; i >= 0; i--) {
1468     if ((dsrc->val[nz - 1] >> (i * 4)) & 0xF)
1469         break;
1470     }
1471 return ((nz - 1) * 8) + i;
1472 }
1473 
1474 /* Create table of multiples
1475 
1476    Arguments:
1477         dsrc    =       base decimal string structure
1478         mtable[10] =    array of decimal string structures
1479 
1480    Note that dsrc has a high order zero nibble; this
1481    guarantees that the largest multiple won't overflow
1482    Also note that mtable[0] is not filled in
1483 */
1484 
CreateTable(DSTR * dsrc,DSTR mtable[10])1485 void CreateTable (DSTR *dsrc, DSTR mtable[10])
1486 {
1487 int32 (i);
1488 
1489 mtable[1] = *dsrc;
1490 for (i = 2; i < 10; i++)
1491     AddDstr (&mtable[1], &mtable[i-1], &mtable[i], 0);
1492 return;
1493 }
1494 
1495 /* Word shift right
1496 
1497    Arguments:
1498         dsrc    =       decimal string structure
1499         sc      =       shift count
1500 */
1501 
WordRshift(DSTR * dsrc,int32 sc)1502 void WordRshift (DSTR *dsrc, int32 sc)
1503 {
1504 int32 i;
1505 
1506 if (sc) {
1507     for (i = 0; i < DSTRLNT; i++) {
1508         if ((i + sc) < DSTRLNT)
1509             dsrc->val[i] = dsrc->val[i + sc];
1510         else dsrc->val[i] = 0;
1511         }
1512     }
1513 return;
1514 }
1515 
1516 /* Word shift left
1517 
1518    Arguments:
1519         dsrc    =       decimal string structure
1520         sc      =       shift count
1521 */
1522 
WordLshift(DSTR * dsrc,int32 sc)1523 int32 WordLshift (DSTR *dsrc, int32 sc)
1524 {
1525 int32 i, c;
1526 
1527 c = 0;
1528 if (sc) {
1529     for (i = DSTRMAX; i >= 0; i--) {
1530         if (i >= sc)
1531             dsrc->val[i] = dsrc->val[i - sc];
1532         else {
1533             c |= dsrc->val[i];
1534             dsrc->val[i] = 0;
1535             }
1536         }
1537     }
1538 return c;
1539 }
1540 
1541 /* Nibble shift decimal string right
1542 
1543    Arguments:
1544         dsrc    =       decimal string structure
1545         sc      =       shift count
1546         cin     =       carry in
1547 */
1548 
NibbleRshift(DSTR * dsrc,int32 sc,uint32 cin)1549 uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin)
1550 {
1551 int32 i, s, nc;
1552 
1553 if ((s = sc * 4)) {
1554     for (i = DSTRMAX; i >= 0; i--) {
1555         nc = (dsrc->val[i] << (32 - s)) & LMASK;
1556         dsrc->val[i] = ((dsrc->val[i] >> s) |
1557             cin) & LMASK;
1558         cin = nc;
1559         }
1560     return cin;
1561     }
1562 return 0;
1563 }
1564 
1565 /* Nibble shift decimal string left
1566 
1567    Arguments:
1568         dsrc    =       decimal string structure
1569         sc      =       shift count
1570         cin     =       carry in
1571 */
1572 
NibbleLshift(DSTR * dsrc,int32 sc,uint32 cin)1573 uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin)
1574 {
1575 int32 i, s, nc;
1576 
1577 if ((s = sc * 4)) {
1578     for (i = 0; i < DSTRLNT; i++) {
1579         nc = dsrc->val[i] >> (32 - s);
1580         dsrc->val[i] = ((dsrc->val[i] << s) |
1581             cin) & LMASK;
1582         cin = nc;
1583         }
1584     return cin;
1585     }
1586 return 0;
1587 }
1588 
1589 /* Do 4b of CRC calculation
1590 
1591    Arguments:
1592         crc     =       current CRC ^ char
1593         tbl     =       16 lw table base
1594 
1595    Output:
1596         new CRC
1597 */
1598 
do_crc_4b(int32 crc,int32 tbl,int32 acc)1599 int32 do_crc_4b (int32 crc, int32 tbl, int32 acc)
1600 {
1601 int32 idx = (crc & 0xF) << 2;
1602 int32 t;
1603 
1604 crc = (crc >> 4) & 0x0FFFFFFF;
1605 t = Read ((tbl + idx) & LMASK, L_LONG, RA);
1606 return crc ^ t;
1607 }
1608 
1609 /* Edit routines */
1610 
edit_read_src(int32 inc,int32 acc)1611 int32 edit_read_src (int32 inc, int32 acc)
1612 {
1613 int32 c, r0, r1;
1614 
1615 if (R[0] & LSIGN) {                                     /* ld zeroes? */
1616     r0 = (R[0] + (inc << 16)) & LMASK;                  /* retire increment */
1617     if (r0 & LSIGN)                                     /* more? return 0 */
1618         return 0;
1619     inc = (r0 >> 16) & 0x1F;                            /* effective inc */
1620     }
1621 r1 = (R[1] + (inc / 2) + ((~R[0] & inc) & 1)) & LMASK;  /* eff addr */
1622 r0 = (R[0] - inc) & 0x1F;                               /* eff lnt left */
1623 if (r0 == 0) {                                          /* nothing left? */
1624     R[0] = -1;                                          /* out of input */
1625     RSVD_OPND_FAULT;
1626     }
1627 c = Read (r1, L_BYTE, RA);
1628 return (((r0 & 1)? (c >> 4): c) & 0xF);
1629 }
1630 
edit_adv_src(int32 inc)1631 void edit_adv_src (int32 inc)
1632 {
1633 if (R[0] & LSIGN) {                                     /* ld zeroes? */
1634     R[0] = (R[0] + (inc << 16)) & LMASK;                /* retire 0's */
1635     if (R[0] & LSIGN)                                   /* more to do? */
1636         return;
1637     inc = (R[0] >> 16) & 0x1F;                          /* get excess */
1638     if (inc == 0)                                       /* more to do? */
1639         return;
1640     }
1641 R[1] = (R[1] + (inc / 2) + ((~R[0] & inc) & 1)) & LMASK;/* retire src */
1642 R[0] = (R[0] - inc) & 0x1F;
1643 return;
1644 }
1645 
edit_read_sign(int32 acc)1646 int32 edit_read_sign (int32 acc)
1647 {
1648 int32 sign;
1649 
1650 sign = Read ((R[3] + 1) & LMASK, L_BYTE, RA);           /* read */
1651 R[2] = ED_PUTSIGN (R[2], sign);                         /* now fault safe */
1652 return sign;
1653 }
1654 
1655 #else
1656 
1657 extern int32 R[16];
1658 extern int32 PSL;
1659 extern int32 SCBB;
1660 extern int32 fault_PC;
1661 extern int32 ibcnt, ppc;
1662 extern int32 pcq[PCQ_SIZE];
1663 extern int32 pcq_p;
1664 extern jmp_buf save_env;
1665 
1666 /* CIS instructions - invoke emulator interface
1667 
1668         opnd[0:5] =     six operands to be pushed (if PSL<fpd> = 0)
1669         cc      =       condition codes
1670         opc     =       opcode
1671 
1672    If FPD is set, push old PC and PSL on stack, vector thru SCB.
1673    If FPD is clear, push opcode, old PC, operands, new PC, and PSL
1674         on stack, vector thru SCB.
1675    In both cases, the exception occurs in the current mode.
1676 */
1677 
op_cis(int32 * opnd,int32 cc,int32 opc,int32 acc)1678 int32 op_cis (int32 *opnd, int32 cc, int32 opc, int32 acc)
1679 {
1680 int32 vec;
1681 
1682 if (PSL & PSL_FPD) {                                    /* FPD set? */
1683     Read (SP - 1, L_BYTE, WA);                          /* wchk stack */
1684     Write (SP - 8, fault_PC, L_LONG, WA);               /* push old PC */
1685     Write (SP - 4, PSL | cc, L_LONG, WA);               /* push PSL */
1686     SP = SP - 8;                                        /* decr stk ptr */
1687     vec = ReadLP ((SCBB + SCB_EMULFPD) & PAMASK);
1688     }
1689 else {
1690     if (opc == CVTPL)                                   /* CVTPL? .wl */
1691         opnd[2] = (opnd[2] >= 0)? ~opnd[2]: opnd[3];
1692     Read (SP - 1, L_BYTE, WA);                          /* wchk stack */
1693     Write (SP - 48, opc, L_LONG, WA);                   /* push opcode */
1694     Write (SP - 44, fault_PC, L_LONG, WA);              /* push old PC */
1695     Write (SP - 40, opnd[0], L_LONG, WA);               /* push operands */
1696     Write (SP - 36, opnd[1], L_LONG, WA);
1697     Write (SP - 32, opnd[2], L_LONG, WA);
1698     Write (SP - 28, opnd[3], L_LONG, WA);
1699     Write (SP - 24, opnd[4], L_LONG, WA);
1700     Write (SP - 20, opnd[5], L_LONG, WA);
1701     Write (SP - 8, PC, L_LONG, WA);                     /* push cur PC */
1702     Write (SP - 4, PSL | cc, L_LONG, WA);               /* push PSL */
1703     SP = SP - 48;                                       /* decr stk ptr */
1704     vec = ReadLP ((SCBB + SCB_EMULATE) & PAMASK);
1705     }
1706 PSL = PSL & ~(PSL_TP | PSL_FPD | PSW_DV | PSW_FU | PSW_IV | PSW_T);
1707 JUMP (vec & ~03);                                       /* set new PC */
1708 return 0;                                               /* set new cc's */
1709 }
1710 
1711 #endif
1712