~ubuntu-branches/ubuntu/utopic/simh/utopic

« back to all changes in this revision

Viewing changes to PDP11/pdp11_cis.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2004-04-20 20:01:26 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040420200126-ehsuleda8xcgi51h
Tags: 3.2.0-1
New upstream 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* pdp11_cis.c: PDP-11 CIS optional instruction set simulator
 
2
 
 
3
   Copyright (c) 1993-2004, 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
 
23
   be 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
   This module simulates the PDP-11 commercial instruction set (CIS).
 
27
 
 
28
   17-Oct-02    RMS     Fixed compiler warning (found by Hans Pufal)
 
29
   08-Oct-02    RMS     Fixed macro definitions
 
30
 
 
31
   The commercial instruction set consists of three instruction formats:
 
32
 
 
33
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    register operands
 
34
   | 0  1  1  1  1  1| 0  0  0  0|      opcode     |    076030:076057
 
35
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    076070:076077
 
36
 
 
37
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    inline operands
 
38
   | 0  1  1  1  1  1| 0  0  0  1|      opcode     |    076130:076157
 
39
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    076170:076177
 
40
 
 
41
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    load descriptors
 
42
   | 0  1  1  1  1  1| 0  0  0  0|op| 1  0|  reg   |    076020:076027
 
43
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    076060:076067
 
44
 
 
45
   The CIS instructions operate on character strings, packed (decimal)
 
46
   strings, and numeric (decimal) strings.  Strings are described by
 
47
   a two word descriptor:
 
48
 
 
49
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
50
   |                 length in bytes               |    char string
 
51
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    descriptor
 
52
   |             starting byte address             |
 
53
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
54
 
 
55
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
56
   |  |str type|                    |   length     |    decimal string
 
57
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    descriptor
 
58
   |             starting byte address             |
 
59
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
60
 
 
61
   Decimal string types are:
 
62
 
 
63
     <14:12>            data type               bytes occupied by n digits
 
64
        0               signed zoned                    n
 
65
        1               unsigned zone                   n
 
66
        2               trailing overpunch              n
 
67
        3               leading overpunch               n
 
68
        4               trailing separate               n+1
 
69
        5               leading separate                n+1
 
70
        6               signed packed                   n/2 +1
 
71
        7               unsigned packed                 n/2 +1
 
72
 
 
73
   Zero length character strings occupy no memory; zero length decimal strings
 
74
   require either zero bytes (zoned, overpunch) or one byte (separate, packed).
 
75
 
 
76
   CIS instructions can run for a very long time, so they are interruptible
 
77
   and restartable.  In the simulator, all instructions run to completion.
 
78
   The code is unoptimized.
 
79
*/
 
80
 
 
81
#include "pdp11_defs.h"
 
82
 
 
83
/* Opcode bits */
 
84
 
 
85
#define INLINE          0100                            /* inline */
 
86
#define PACKED          0020                            /* packed */
 
87
#define NUMERIC         0000                            /* numeric */
 
88
 
 
89
/* Operand type definitions */
 
90
 
 
91
#define R0_DESC         1                               /* descr in R0:R1 */
 
92
#define R2_DESC         2                               /* descr in R2:R3 */
 
93
#define R4_DESC         3                               /* descr in R4:R5 */
 
94
#define R4_ARG          4                               /* argument in R4 */
 
95
#define IN_DESC         5                               /* inline descriptor */
 
96
#define IN_ARG          6                               /* inline argument */
 
97
#define IN_DESC_R0      7                               /* inline descr to R0:R1 */
 
98
#define MAXOPN          4                               /* max # operands */
 
99
 
 
100
/* Decimal data type definitions */
 
101
 
 
102
#define XZ              0                               /* signed zoned */
 
103
#define UZ              1                               /* unsigned zoned */
 
104
#define TO              2                               /* trailing overpunch */
 
105
#define LO              3                               /* leading overpunch */
 
106
#define TS              4                               /* trailing separate */
 
107
#define LS              5                               /* leading separate */
 
108
#define XP              6                               /* signed packed */
 
109
#define UP              7                               /* unsigned packed */
 
110
 
 
111
/* Decimal descriptor definitions */
 
112
 
 
113
#define DTYP_M          07                              /* type mask */
 
114
#define DTYP_V          12                              /* type position */
 
115
#define DLNT_M          037                             /* length mask */
 
116
#define DLNT_V          0                               /* length position */
 
117
#define GET_DTYP(x)     (((x) >> DTYP_V) & DTYP_M)
 
118
#define GET_DLNT(x)     (((x) >> DLNT_V) & DLNT_M)
 
119
 
 
120
/* Shift operand definitions */
 
121
 
 
122
#define ASHRND_M        017                             /* round digit mask */
 
123
#define ASHRND_V        8                               /* round digit pos */
 
124
#define ASHLNT_M        0377                            /* shift count mask */
 
125
#define ASHLNT_V        0                               /* shift length pos */
 
126
#define ASHSGN          0200                            /* shift sign */
 
127
#define GET_ASHRND(x)   (((x) >> ASHRND_V) & ASHRND_M)
 
128
#define GET_ASHLNT(x)   (((x) >> ASHLNT_V) & ASHLNT_M)
 
129
 
 
130
/* Operand array aliases */
 
131
 
 
132
#define A1LNT           arg[0]
 
133
#define A1ADR           arg[1]
 
134
#define A2LNT           arg[2]
 
135
#define A2ADR           arg[3]
 
136
#define A3LNT           arg[4]
 
137
#define A3ADR           arg[5]
 
138
#define A1              &arg[0]
 
139
#define A2              &arg[2]
 
140
#define A3              &arg[4]
 
141
 
 
142
/* Condition code macros */
 
143
 
 
144
#define GET_BIT(ir,n)   (((ir) >> (n)) & 1)
 
145
#define GET_SIGN_L(ir)  GET_BIT((ir), 31)
 
146
#define GET_SIGN_W(ir)  GET_BIT((ir), 15)
 
147
#define GET_SIGN_B(ir)  GET_BIT((ir), 7)
 
148
#define GET_Z(ir)       ((ir) == 0)
 
149
 
 
150
/* Decimal string structure */
 
151
 
 
152
#define DSTRLNT         4
 
153
#define DSTRMAX         (DSTRLNT - 1)
 
154
#define MAXDVAL         429496730                       /* 2^32 / 10 */
 
155
 
 
156
struct dstr {
 
157
        unsigned int32  sign;
 
158
        unsigned int32  val[DSTRLNT];  };
 
159
 
 
160
typedef struct dstr DSTR;
 
161
 
 
162
static DSTR Dstr0 = { 0, 0, 0, 0, 0 };
 
163
 
 
164
extern int32 isenable, dsenable;
 
165
extern int32 N, Z, V, C;
 
166
extern int32 R[8], trap_req;
 
167
extern int32 ReadW (int32 addr);
 
168
extern void WriteW (int32 data, int32 addr);
 
169
extern int32 ReadB (int32 addr);
 
170
extern void WriteB (int32 data, int32 addr);
 
171
int32 ReadDstr (int32 *dscr, DSTR *dec, int32 flag);
 
172
void WriteDstr (int32 *dscr, DSTR *dec, int32 flag);
 
173
int32 AddDstr (DSTR *src1, DSTR *src2, DSTR *dst, int32 cin);
 
174
void SubDstr (DSTR *src1, DSTR *src2, DSTR *dst);
 
175
int32 CmpDstr (DSTR *src1, DSTR *src2);
 
176
int32 TestDstr (DSTR *dsrc);
 
177
int32 LntDstr (DSTR *dsrc, int32 nz);
 
178
unsigned int32 NibbleLshift (DSTR *dsrc, int32 sc, unsigned int32 cin);
 
179
unsigned int32 NibbleRshift (DSTR *dsrc, int32 sc, unsigned int32 cin);
 
180
int32 WordLshift (DSTR *dsrc, int32 sc);
 
181
void WordRshift (DSTR *dsrc, int32 sc);
 
182
void CreateTable (DSTR *dsrc, DSTR mtable[10]);
 
183
 
 
184
/* Table of instruction operands */
 
185
 
 
186
static int32 opntab[128][MAXOPN] = {
 
187
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 000 - 007 */
 
188
        0, 0, 0, 0, 0, 0, 0, 0,
 
189
        0, 0, 0, 0, 0, 0, 0, 0,
 
190
        0, 0, 0, 0, 0, 0, 0, 0,
 
191
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 010 - 017 */
 
192
        0, 0, 0, 0, 0, 0, 0, 0,
 
193
        0, 0, 0, 0, 0, 0, 0, 0,
 
194
        0, 0, 0, 0, 0, 0, 0, 0,
 
195
        0, 0, 0, 0, 0, 0, 0, 0,                         /* LD2R */
 
196
        0, 0, 0, 0, 0, 0, 0, 0,
 
197
        0, 0, 0, 0, 0, 0, 0, 0,
 
198
        0, 0, 0, 0, 0, 0, 0, 0,
 
199
        R0_DESC, R2_DESC, R4_ARG, 0,                    /* MOVC */
 
200
        R0_DESC, R2_DESC, R4_ARG, 0,                    /* MOVRC */
 
201
        R0_DESC, R2_DESC, R4_DESC, 0,                   /* MOVTC */
 
202
                    0, 0, 0, 0,                         /* 033 */
 
203
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 034 - 037 */
 
204
        0, 0, 0, 0, 0, 0, 0, 0,
 
205
        R4_ARG, 0, 0, 0,                                /* LOCC */
 
206
        R4_ARG, 0, 0, 0,                                /* SKPC */
 
207
        R4_DESC, 0, 0, 0,                               /* SCANC */
 
208
        R4_DESC, 0, 0, 0,                               /* SPANC */
 
209
        R0_DESC, R2_DESC, R4_ARG, 0,                    /* CMPC */
 
210
        R2_DESC, 0, 0, 0,                               /* MATC */
 
211
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 046 - 047 */
 
212
        R0_DESC, R2_DESC, R4_DESC, 0,                   /* ADDN */
 
213
        R0_DESC, R2_DESC, R4_DESC, 0,                   /* SUBN */
 
214
        R0_DESC, R2_DESC, 0, 0,                         /* CMPN */
 
215
        R0_DESC, 0, 0, 0,                               /* CVTNL */
 
216
        R0_DESC, R2_DESC, 0, 0,                         /* CVTPN */
 
217
        R0_DESC, R2_DESC, 0, 0,                         /* CVTNP */
 
218
        R0_DESC, R2_DESC, R4_ARG, 0,                    /* ASHN */
 
219
        R0_DESC, 0, 0, 0,                               /* CVTLN */
 
220
        0, 0, 0, 0, 0, 0, 0, 0,                         /* LD3R */
 
221
        0, 0, 0, 0, 0, 0, 0, 0,
 
222
        0, 0, 0, 0, 0, 0, 0, 0,
 
223
        0, 0, 0, 0, 0, 0, 0, 0,
 
224
        R0_DESC, R2_DESC, R4_DESC, 0,                   /* ADDP */
 
225
        R0_DESC, R2_DESC, R4_DESC, 0,                   /* SUBP */
 
226
        R0_DESC, R2_DESC, 0, 0,                         /* CMPP */
 
227
        R0_DESC, 0, 0, 0,                               /* CVTPL */
 
228
        R0_DESC, R2_DESC, R4_DESC, 0,                   /* MULP */
 
229
        R0_DESC, R2_DESC, R4_DESC, 0,                   /* DIVP */
 
230
        R0_DESC, R2_DESC, R4_ARG, 0,                    /* ASHP */
 
231
        R0_DESC, 0, 0, 0,                               /* CVTLP */
 
232
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 100 - 107 */
 
233
        0, 0, 0, 0, 0, 0, 0, 0,
 
234
        0, 0, 0, 0, 0, 0, 0, 0,
 
235
        0, 0, 0, 0, 0, 0, 0, 0,
 
236
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 110 - 117 */
 
237
        0, 0, 0, 0, 0, 0, 0, 0,
 
238
        0, 0, 0, 0, 0, 0, 0, 0,
 
239
        0, 0, 0, 0, 0, 0, 0, 0,
 
240
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 120 - 127 */
 
241
        0, 0, 0, 0, 0, 0, 0, 0,
 
242
        0, 0, 0, 0, 0, 0, 0, 0,
 
243
        0, 0, 0, 0, 0, 0, 0, 0,
 
244
        IN_DESC, IN_DESC, IN_ARG, 0,                    /* MOVCI */
 
245
        IN_DESC, IN_DESC, IN_ARG, 0,                    /* MOVRCI */
 
246
        IN_DESC, IN_DESC, IN_ARG, IN_ARG,               /* MOVTCI */
 
247
                    0, 0, 0, 0,                         /* 133 */
 
248
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 134 - 137 */
 
249
        0, 0, 0, 0, 0, 0, 0, 0,
 
250
        IN_DESC_R0, IN_ARG, 0, 0,                       /* LOCCI */
 
251
        IN_DESC_R0, IN_ARG, 0, 0,                       /* SKPCI */
 
252
        IN_DESC_R0, IN_DESC, 0, 0,                      /* SCANCI */
 
253
        IN_DESC_R0, IN_DESC, 0, 0,                      /* SPANCI */
 
254
        IN_DESC, IN_DESC, IN_ARG, 0,                    /* CMPCI */
 
255
        IN_DESC_R0, IN_DESC, 0, 0,                      /* MATCI */
 
256
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 146 - 147 */
 
257
        IN_DESC, IN_DESC, IN_DESC, 0,                   /* ADDNI */
 
258
        IN_DESC, IN_DESC, IN_DESC, 0,                   /* SUBNI */
 
259
        IN_DESC, IN_DESC, 0, 0,                         /* CMPNI */
 
260
        IN_DESC, IN_ARG, 0, 0,                          /* CVTNLI */
 
261
        IN_DESC, IN_DESC, 0, 0,                         /* CVTPNI */
 
262
        IN_DESC, IN_DESC, 0, 0,                         /* CVTNPI */
 
263
        IN_DESC, IN_DESC, IN_ARG, 0,                    /* ASHNI */
 
264
        IN_DESC, IN_DESC, 0, 0,                         /* CVTLNI */
 
265
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 160 - 167 */
 
266
        0, 0, 0, 0, 0, 0, 0, 0,
 
267
        0, 0, 0, 0, 0, 0, 0, 0,
 
268
        0, 0, 0, 0, 0, 0, 0, 0,
 
269
        IN_DESC, IN_DESC, IN_DESC, 0,                   /* ADDPI */
 
270
        IN_DESC, IN_DESC, IN_DESC, 0,                   /* SUBPI */
 
271
        IN_DESC, IN_DESC, 0, 0,                         /* CMPPI */
 
272
        IN_DESC, 0, 0, 0,                               /* CVTPLI */
 
273
        IN_DESC, IN_DESC, IN_DESC, 0,                   /* MULPI */
 
274
        IN_DESC, IN_DESC, IN_DESC, 0,                   /* DIVPI */
 
275
        IN_DESC, IN_DESC, IN_ARG, 0,                    /* ASHPI */
 
276
        IN_DESC, IN_DESC, 0, 0                          /* CVTLPI */
 
277
};
 
278
 
 
279
/* ASCII to overpunch table: sign is <7>, digit is <4:0> */
 
280
 
 
281
static int32 overbin[128] = {
 
282
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 000 - 037 */
 
283
        0, 0, 0, 0, 0, 0, 0, 0,
 
284
        0, 0, 0, 0, 0, 0, 0, 0,
 
285
        0, 0, 0, 0, 0, 0, 0, 0,
 
286
        0, 0x80, 0, 0, 0, 0, 0, 0,                      /* 040 - 077 */
 
287
        0, 0, 0, 0, 0, 0, 0, 0,
 
288
        0, 1, 2, 3, 4, 5, 6, 7,
 
289
        8, 9, 0x80, 0, 0, 0, 0, 0,
 
290
        0, 1, 2, 3, 4, 5, 6, 7,                         /* 100 - 137 */
 
291
        8, 9, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
 
292
        0x87, 0x88, 0x89, 0, 0, 0, 0, 0,
 
293
        0, 0, 0, 0, 0, 0x80, 0, 0,
 
294
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 140 - 177 */
 
295
        0, 0, 0, 0, 0, 0, 0, 0,
 
296
        0, 0, 0, 0, 0, 0, 0, 0,
 
297
        0, 0, 0, 0, 0, 0x80, 0, 0
 
298
};
 
299
 
 
300
/* Overpunch to ASCII table: indexed by sign and digit */
 
301
 
 
302
static int32 binover[2][16] = {
 
303
        '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
 
304
                '0', '0', '0', '0', '0', '0',
 
305
        '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
 
306
                '0', '0', '0', '0', '0', '0'
 
307
};
 
308
 
 
309
static unsigned char movbuf[65536];
 
310
 
 
311
/* CIS emulator */
 
312
 
 
313
void cis11 (int32 IR)
 
314
{
 
315
int32 c, i, j, k, t, op, rn, addr;
 
316
int32 fill, mask, match, limit, mvlnt, shift;
 
317
int32 spc, ldivd, ldivr;
 
318
int32 arg[6];                                           /* operands */
 
319
uint32 nc, digit, result;
 
320
static DSTR accum, src1, src2, dst;
 
321
static DSTR mptable[10];
 
322
static DSTR Dstr1 = { 0, 0x10, 0, 0, 0 };
 
323
 
 
324
op = IR & 0177;                                         /* IR <6:0> */
 
325
for (i = j = 0; (i < MAXOPN) && opntab[op][i]; i++) {   /* parse operands */
 
326
        switch (opntab[op][i]) {                        /* case on op type */
 
327
        case R0_DESC:
 
328
            arg[j++] = R[0];
 
329
            arg[j++] = R[1];
 
330
            break;
 
331
        case R2_DESC:
 
332
            arg[j++] = R[2];
 
333
            arg[j++] = R[3];
 
334
            break;
 
335
        case R4_DESC:
 
336
            arg[j++] = R[4];
 
337
            arg[j++] = R[5];
 
338
            break;
 
339
        case R4_ARG:
 
340
            arg[j++] = R[4];
 
341
            break;
 
342
        case IN_DESC:
 
343
            addr = ReadW (PC | isenable);
 
344
            PC = (PC + 2) & 0177777;
 
345
            arg[j++] = ReadW (addr | dsenable);
 
346
            arg[j++] = ReadW (((addr + 2) & 0177777) | dsenable);
 
347
            break;
 
348
        case IN_DESC_R0:
 
349
            addr = ReadW (PC | isenable);
 
350
            PC = (PC + 2) & 0177777;
 
351
            R[0] = ReadW (addr | dsenable);
 
352
            R[1] = ReadW (((addr + 2) & 0177777) | dsenable);
 
353
            break;
 
354
        case IN_ARG:
 
355
            arg[j++] = ReadW (PC | isenable);
 
356
            PC = (PC + 2) & 0177777;
 
357
            break;  }                                   /* end case */
 
358
        }                                               /* end for */
 
359
switch (op) {                                           /* case on opcode */
 
360
 
 
361
/* MOVC, MOVTC, MOVCI, MOVTCI
 
362
 
 
363
   Operands:
 
364
        A1LNT, A1ADR    =       source string descriptor
 
365
        A2LNT, A2ADR    =       dest string descriptor
 
366
        A3LNT<7:0>      =       fill character
 
367
        A3ADR           =       translation table address (MOVTC, MOVTCI only)
 
368
 
 
369
   Condition codes:
 
370
        NZVC            =       set from src.lnt - dst.lnt
 
371
 
 
372
   Registers (MOVC, MOVTC only)
 
373
        R0              =       max (0, src.len - dst.len)
 
374
        R1:R3           =       0
 
375
        R4:R5           =       unchanged
 
376
 
 
377
        Notes:   
 
378
        - To avoid overlap problems, the entire source string is
 
379
          buffered in movbuf.  On a modern microprocessor, for most
 
380
          string sizes, this will be handled in the on chip cache.
 
381
        - If either the source or destination lengths are zero,
 
382
          the move loops exit immediately.
 
383
        - If the source length does not exceed the destination
 
384
          length, the fill loop exits immediately.
 
385
*/
 
386
 
 
387
case 030: case 032: case 0130: case 0132:
 
388
        mvlnt = (A1LNT < A2LNT)? A1LNT: A2LNT;          /* calc move lnt */
 
389
        for (i = 0; i < mvlnt; i++) {
 
390
            movbuf[i] = ReadB (((A1ADR + i) & 0177777) | dsenable);  }
 
391
        for (i = 0; i < mvlnt; i++) {
 
392
            t = movbuf[i];
 
393
            if (op & 2) t = ReadB (((A3ADR + t) & 0177777) | dsenable);
 
394
            WriteB (t, ((A2ADR + i) & 0177777) | dsenable);  }
 
395
        fill = A3LNT & 0377;                            /* do fill, if any */
 
396
        for (i = mvlnt; i < A2LNT; i++) {
 
397
            WriteB (fill, ((A2ADR + i) & 0177777) | dsenable);  }
 
398
        t = A1LNT - A2LNT;                              /* src.lnt - dst.lnt */
 
399
        N = GET_SIGN_W (t);                             /* set cc's from diff */
 
400
        Z = GET_Z (t);
 
401
        V = GET_SIGN_W ((A1LNT ^ A2LNT) & (~A2LNT ^ t));
 
402
        C = (A1LNT < A2LNT);
 
403
        if ((op & INLINE) == 0) {                       /* if reg, set reg */
 
404
            R[0] = C? 0: t & 0177777;
 
405
            R[1] = R[2] = R[3] = 0;
 
406
            R[4] = R[4] & 0377;  }
 
407
        return;
 
408
 
 
409
/* MOVRC, MOVRCI
 
410
 
 
411
   Operands:
 
412
        A1LNT, A1ADR    =       source string descriptor
 
413
        A2LNT, A2ADR    =       dest string descriptor
 
414
        A3LNT<7:0>      =       fill character
 
415
 
 
416
   Condition codes:
 
417
        NZVC            =       set from src.lnt - dst.lnt
 
418
 
 
419
   Registers (MOVRC only)
 
420
        R0              =       max (0, src.len - dst.len)
 
421
        R1:R3           =       0
 
422
        R4:R5           =       unchanged
 
423
 
 
424
   Notes: see MOVC, MOVCI
 
425
*/
 
426
 
 
427
case 031: case 0131:
 
428
        mvlnt = (A1LNT < A2LNT)? A1LNT: A2LNT;          /* calc move lnt */
 
429
        addr = A1ADR + A1LNT - mvlnt;
 
430
        for (i = 0; i < mvlnt; i++) {
 
431
            movbuf[i] = ReadB (((addr + i) & 0177777) | dsenable);  }
 
432
        addr = A2ADR + A2LNT - mvlnt;
 
433
        for (i = 0; i < mvlnt; i++) {
 
434
            WriteB (movbuf[i], ((addr + i) & 0177777) | dsenable);  }
 
435
        fill = A3LNT & 0377;                            /* do fill, if any */
 
436
        for (i = mvlnt, j = 0; i < A2LNT; i++, j++) {
 
437
            WriteB (fill, ((A2ADR + j) & 0177777) | dsenable);  }
 
438
        t = A1LNT - A2LNT;                              /* src.lnt - dst.lnt */
 
439
        N = GET_SIGN_W (t);                             /* set cc's from diff */
 
440
        Z = GET_Z (t);
 
441
        V = GET_SIGN_W ((A1LNT ^ A2LNT) & (~A2LNT ^ t));
 
442
        C = (A1LNT < A2LNT);
 
443
        if ((op & INLINE) == 0) {                       /* if reg, set reg */
 
444
            R[0] = C? 0: t & 0177777;
 
445
            R[1] = R[2] = R[3] = 0;
 
446
            R[4] = R[4] & 0377;  }
 
447
        return;
 
448
 
 
449
/* Load descriptors - no operands */
 
450
 
 
451
case 020: case 021: case 022: case 023:
 
452
case 024: case 025: case 026: case 027:
 
453
case 060: case 061: case 062: case 063:
 
454
case 064: case 065: case 066: case 067:
 
455
        limit = (op & 040)? 6: 4;
 
456
        rn = IR & 07;                                   /* get register */
 
457
        t = R[rn];
 
458
        spc = (rn == 7)? isenable: dsenable;
 
459
        for (j = 0; j < limit; j = j + 2) {             /* loop for 2,3 dscr */
 
460
            addr = ReadW (((t + j) & 0177777) | spc);
 
461
            R[j] = ReadW (addr | dsenable);
 
462
            R[j + 1] = ReadW (((addr + 2) & 0177777) | dsenable);  }
 
463
        if (rn >= limit) R[rn] = (R[rn] + limit) & 0177777;
 
464
        return;
 
465
 
 
466
/* LOCC, SKPC, LOCCI, SKPCI 
 
467
 
 
468
   Operands:
 
469
        R0, R1          =       source string descriptor
 
470
        A1LNT<7:0>      =       match character
 
471
 
 
472
   Condition codes:
 
473
        NZ              =       set from R0
 
474
        VC              =       0
 
475
 
 
476
   Registers:
 
477
        R0:R1           =       substring descriptor where operation terminated
 
478
*/
 
479
 
 
480
case 040: case 041: case 0140: case 0141:
 
481
        match = A1LNT & 0377;                           /* match character */
 
482
        for ( ; R[0] != 0; R[0]--) {                    /* loop */
 
483
            c = ReadB (R[1] | dsenable);                /* get char */
 
484
            if ((c == match) ^ (op & 1)) break;         /* = + LOC, != + SKP? */
 
485
            R[1] = (R[1] + 1) & 0177777;  }
 
486
        N = GET_SIGN_W (R[0]);
 
487
        Z = GET_Z (R[0]);
 
488
        V = C = 0;
 
489
        if ((op & INLINE) == 0) R[4] = R[4] & 0377;     /* if reg, set reg */
 
490
        return;
 
491
 
 
492
/* SCANC, SPANC, SCANCI, SPANCI
 
493
 
 
494
   Operands:
 
495
        R0, R1          =       source string descriptor
 
496
        A1LNT<7:0>      =       mask
 
497
        A1ADR           =       table address
 
498
 
 
499
   Condition codes:
 
500
        NZ              =       set from R0
 
501
        VC              =       0
 
502
 
 
503
   Registers:
 
504
        R0:R1           =       substring descriptor where operation terminated
 
505
*/
 
506
 
 
507
case 042: case 043: case 0142: case 0143:
 
508
        mask = A1LNT & 0377;                            /* mask character */
 
509
        for (; R[0] != 0; R[0]--) {                     /* loop */
 
510
            t = ReadB (R[1] | dsenable);                /* get char as index */
 
511
            c = ReadB (((A1ADR + t) & 0177777) | dsenable);
 
512
            if (((c & mask) != 0) ^ (op & 1)) break;    /* != + SCN, = + SPN? */
 
513
            R[1] = (R[1] + 1) & 0177777;  }
 
514
        N = GET_SIGN_W (R[0]);
 
515
        Z = GET_Z (R[0]);
 
516
        V = C = 0;
 
517
        if ((op & INLINE) == 0) R[4] = R[4] & 0377;     /* if reg, set reg */
 
518
        return;
 
519
 
 
520
/* CMPC, CMPCI
 
521
 
 
522
   Operands:
 
523
        A1LNT, A1ADR    =       source1 string descriptor
 
524
        A2LNT, A2ADR    =       source2 string descriptor
 
525
        A3LNT<7:0>      =       fill character
 
526
 
 
527
   Condition codes:
 
528
        NZVC            =       set from src1 - src2 at mismatch, or
 
529
                        =       0100 if equal
 
530
 
 
531
   Registers (CMPC only):
 
532
        R0:R1           =       unmatched source1 substring descriptor
 
533
        R2:R3           =       unmatched source2 substring descriptor
 
534
*/
 
535
 
 
536
case 044: case 0144:
 
537
        c = t = 0;
 
538
        for (i = 0; i < ((A1LNT > A2LNT)? A1LNT: A2LNT); i++) {
 
539
            if (i < A1LNT) c = ReadB (((A1ADR + i) & 0177777) | dsenable);
 
540
            else c = A3LNT & 0377;
 
541
            if (i < A2LNT) t = ReadB (((A2ADR + i) & 0177777) | dsenable);
 
542
            else t = A3LNT & 0377;
 
543
            if (c != t) break;  }
 
544
        j = c - t;                                      /* last chars read */
 
545
        N = GET_SIGN_B (j);                             /* set cc's */
 
546
        Z = GET_Z (j);
 
547
        V = GET_SIGN_B ((c ^ t) & (~t ^ j));
 
548
        C = (c < t);
 
549
        if ((op & INLINE) == 0) {                       /* if reg, set reg */
 
550
            j = (i > A1LNT)? A1LNT: i;                  /* #src1 chars used */
 
551
            k = (i > A2LNT)? A2LNT: i;                  /* #src2 chars used */
 
552
            R[0] = A1LNT - j;
 
553
            R[1] = (A1ADR + j) & 0177777;
 
554
            R[2] = A2LNT - k;
 
555
            R[3] = (A2ADR + k) & 0177777;
 
556
            R[4] = R[4] & 0377;  }
 
557
        return;
 
558
 
 
559
/* MATC, MATCI
 
560
 
 
561
   Operands:
 
562
        R0, R1          =       source string descriptor
 
563
        A1LNT, A1ADR    =       substring descriptor
 
564
 
 
565
   Condition codes:
 
566
        NZ              =       set from R0
 
567
        VC              =       0
 
568
 
 
569
   Registers:
 
570
        R0:R1           =       source substring descriptor for match
 
571
 
 
572
   Notes:
 
573
        - If the string is zero length, and the substring is not,
 
574
          the outer loop exits immediately, and the result is
 
575
          "no match"
 
576
        - If the substring is zero length, the inner loop always
 
577
          exits immediately, and the result is a "match"
 
578
        - If the string is zero length, and the substring is as
 
579
          well, the outer loop executes, the inner loop exits
 
580
          immediately, and the result is a match, but the result
 
581
          is the length of the string (zero), or "no match"
 
582
*/
 
583
 
 
584
case 0045: case 0145:
 
585
        for (match = 0; R[0] >= A1LNT; R[0]--) {        /* loop thru string */
 
586
            for (i = 0, match = 1; match && (i < A1LNT); i++) {
 
587
                c = ReadB (((R[1] + i) & 0177777) | dsenable);
 
588
                t = ReadB (((A1ADR + i) & 0177777) | dsenable);
 
589
                match = (c == t);  }                    /* end for substring */
 
590
            if (match) break;                           /* exit if match */
 
591
            R[1] = (R[1] + 1) & 0177777;  }             /* end for string */
 
592
        if (!match) {                                   /* if no match */
 
593
            R[1] = (R[1] + R[0]) & 0177777;
 
594
            R[0] = 0;  }
 
595
        N = GET_SIGN_W (R[0]);
 
596
        Z = GET_Z (R[0]);
 
597
        V = C = 0;
 
598
        return;
 
599
 
 
600
/* ADDN, SUBN, ADDP, SUBP, ADDNI, SUBNI, ADDPI, SUBPI
 
601
 
 
602
   Operands:
 
603
        A1LNT, A1ADR    =       source1 string descriptor
 
604
        A2LNT, A2ADR    =       source2 string descriptor
 
605
        A3LNT, A3ADR    =       destination string descriptor
 
606
 
 
607
   Condition codes:
 
608
        NZV             =       set from result
 
609
        C               =       0
 
610
 
 
611
   Registers (ADDN, ADDP, SUBN, SUBP only):
 
612
        R0:R3           =       0       
 
613
*/
 
614
 
 
615
case 050: case 051: case 070: case 071:
 
616
case 0150: case 0151: case 0170: case 0171:
 
617
        ReadDstr (A1, &src1, op);                       /* get source1 */
 
618
        ReadDstr (A2, &src2, op);                       /* get source2 */
 
619
        if (op & 1) src1.sign = src1.sign ^ 1;          /* sub? invert sign */
 
620
        if (src1.sign ^ src2.sign) {                    /* opp signs?  sub */
 
621
            if (CmpDstr (&src1, &src2) < 0) {           /* src1 < src2? */
 
622
                SubDstr (&src1, &src2, &dst);           /* src2 - src1 */
 
623
                dst.sign = src2.sign;  }                /* sign = src2 */
 
624
            else {
 
625
                SubDstr (&src2, &src1, &dst);           /* src1 - src2 */
 
626
                dst.sign = src1.sign;  }                /* sign = src1 */
 
627
            V = 0;  }                                   /* can't carry */
 
628
        else {                                          /* addition */
 
629
            V = AddDstr (&src1, &src2, &dst, 0);        /* add magnitudes */
 
630
            dst.sign = src1.sign;  }                    /* set result sign */
 
631
        C = 0;
 
632
        WriteDstr (A3, &dst, op);                       /* store result */
 
633
        if ((op & INLINE) == 0)                         /* if reg, clr reg */
 
634
            R[0] = R[1] = R[2] = R[3] = 0;
 
635
        return;
 
636
 
 
637
/* MULP, MULPI
 
638
 
 
639
   Operands:
 
640
        A1LNT, A1ADR    =       source1 string descriptor
 
641
        A2LNT, A2ADR    =       source2 string descriptor
 
642
        A3LNT, A3ADR    =       destination string descriptor
 
643
 
 
644
   Condition codes:
 
645
        NZV             =       set from result
 
646
        C               =       0
 
647
 
 
648
   Registers (MULP only):
 
649
        R0:R3           =       0       
 
650
*/
 
651
 
 
652
case 074: case 0174:
 
653
        dst = Dstr0;                                    /* clear result */
 
654
        if (ReadDstr (A1, &src1, op) && ReadDstr (A2, &src2, op)) {
 
655
            dst.sign = src1.sign ^ src2.sign;           /* sign of result */
 
656
            accum = Dstr0;                              /* clear accum */
 
657
            NibbleRshift (&src1, 1, 0);                 /* shift out sign */
 
658
            CreateTable (&src1, mptable);               /* create *1, *2, ... */
 
659
            for (i = 1; i < (DSTRLNT * 8); i++) {       /* 31 iterations */
 
660
                digit = (src2.val[i / 8] >> ((i % 8) * 4)) & 0xF;
 
661
                if (digit > 0)                          /* add in digit*mpcnd */
 
662
                    AddDstr (&mptable[digit], &accum, &accum, 0);
 
663
                nc = NibbleRshift (&accum, 1, 0);       /* ac right 4 */
 
664
                NibbleRshift (&dst, 1, nc);  }          /* result right 4 */
 
665
            V = TestDstr (&accum) != 0;  }              /* if ovflo, set V */
 
666
        else V = 0;                                     /* result = 0 */
 
667
        C = 0;                                          /* C = 0 */
 
668
        WriteDstr (A3, &dst, op);                       /* store result */
 
669
        if ((op & INLINE) == 0)                         /* if reg, clr reg */
 
670
                R[0] = R[1] = R[2] = R[3] = 0;
 
671
        return;
 
672
 
 
673
/* DIVP, DIVPI
 
674
 
 
675
   Operands:
 
676
        A1LNT, A1ADR    =       divisor string descriptor
 
677
        A2LNT, A2ADR    =       dividend string descriptor
 
678
        A3LNT, A3ADR    =       destination string descriptor
 
679
 
 
680
   Condition codes:
 
681
        NZV             =       set from result
 
682
        C               =       set if divide by zero
 
683
 
 
684
   Registers (DIVP only):
 
685
        R0:R3           =       0       
 
686
*/
 
687
 
 
688
case 075: case 0175:
 
689
        ldivr = ReadDstr (A1, &src1, op);               /* get divisor */
 
690
        if (ldivr == 0) {                               /* divisor = 0? */
 
691
            V = C = 1;                                  /* set cc's */
 
692
            return;  }
 
693
        ldivr = LntDstr (&src1, ldivr);                 /* get exact length */
 
694
        ldivd = ReadDstr (A2, &src2, op);               /* get dividend */
 
695
        ldivd = LntDstr (&src2, ldivd);                 /* get exact length */
 
696
        dst = Dstr0;                                    /* clear dest */
 
697
        NibbleRshift (&src1, 1, 0);                     /* right justify ops */
 
698
        NibbleRshift (&src2, 1, 0);
 
699
        if ((t = ldivd - ldivr) >= 0) {                 /* any divide to do? */
 
700
            WordLshift (&src1, t / 8);                  /* align divr to divd */
 
701
            NibbleLshift (&src1, t % 8, 0);
 
702
            CreateTable (&src1, mptable);               /* create *1, *2, ... */
 
703
            for (i = 0; i <= t; i++) {                  /* divide loop */
 
704
                for (digit = 9; digit > 0; digit--) {   /* find digit */
 
705
                    if (CmpDstr (&src2, &mptable[digit]) >= 0) {
 
706
                        SubDstr (&mptable[digit], &src2, &src2);
 
707
                        dst.val[0] = dst.val[0] | digit;
 
708
                        break;  }  }                    /* end if, for */
 
709
                NibbleLshift (&src2, 1, 0);             /* shift dividend */
 
710
                NibbleLshift (&dst, 1, 0);              /* shift quotient */
 
711
                }                                       /* end divide loop */
 
712
            dst.sign = src1.sign ^ src2.sign;           /* calculate sign */
 
713
            }                                           /* end if */
 
714
        V = C = 0;
 
715
        WriteDstr (A3, &dst, op);                       /* store result */
 
716
        if ((op & INLINE) == 0)                         /* if reg, clr reg */
 
717
            R[0] = R[1] = R[2] = R[3] = 0;
 
718
        return;
 
719
 
 
720
/* CMPN, CMPP, CMPNI, CMPPI
 
721
 
 
722
   Operands:
 
723
        A1LNT, A1ADR    =       source1 string descriptor
 
724
        A2LNT, A2ADR    =       source2 string descriptor
 
725
 
 
726
   Condition codes:
 
727
        NZ              =       set from comparison
 
728
        VC              =       0
 
729
 
 
730
   Registers (CMPN, CMPP only):
 
731
        R0:R3           =       0
 
732
*/
 
733
 
 
734
case 052: case 072: case 0152: case 0172:
 
735
        ReadDstr (A1, &src1, op);                       /* get source1 */
 
736
        ReadDstr (A2, &src2, op);                       /* get source2 */
 
737
        N = Z = V = C = 0;
 
738
        if (src1.sign != src2.sign) N = src1.sign;
 
739
        else {
 
740
            t = CmpDstr (&src1, &src2);                 /* compare strings */
 
741
            if (t < 0) N = 1;
 
742
            else if (t == 0) Z = 1;  }
 
743
        if ((op & INLINE) == 0)                         /* if reg, clr reg */
 
744
            R[0] = R[1] = R[2] = R[3] = 0;
 
745
        return;
 
746
 
 
747
/* ASHN, ASHP, ASHNI, ASHPI
 
748
 
 
749
   Operands:
 
750
        A1LNT, A1ADR    =       source string descriptor
 
751
        A2LNT, A2ADR    =       destination string descriptor
 
752
        A3LNT<11:8>     =       rounding digit
 
753
        A3LNT<7:0>      =       shift count
 
754
 
 
755
   Condition codes:
 
756
        NZV             =       set from result
 
757
        C               =       0
 
758
 
 
759
   Registers (ASHN, ASHP only):
 
760
        R0:R1, R4       =       0 
 
761
*/
 
762
 
 
763
case 056: case 076: case 0156: case 0176:
 
764
        ReadDstr (A1, &src1, op);                       /* get source */
 
765
        V = C = 0;                                      /* init cc's */
 
766
        shift = GET_ASHLNT (A3LNT);                     /* get shift count */
 
767
        if (shift & ASHSGN) {                           /* right shift? */
 
768
            shift = (ASHLNT_M + 1 - shift);             /* !shift! */
 
769
            WordRshift (&src1, shift / 8);              /* do word shifts */    
 
770
            NibbleRshift (&src1, shift % 8, 0);         /* do nibble shifts */
 
771
            t = GET_ASHRND (A3LNT);                     /* get rounding digit */
 
772
            if ((t + (src1.val[0] & 0xF)) > 9)          /* rounding needed? */
 
773
                AddDstr (&src1, &Dstr1, &src1, 0);      /* round */
 
774
            src1.val[0] = src1.val[0] & ~0xF;           /* clear sign */
 
775
        }                                               /* end right shift */
 
776
        else if (shift) {                               /* left shift? */
 
777
            if (WordLshift (&src1, shift / 8)) V = 1;   /* do word shifts */
 
778
            if (NibbleLshift (&src1, shift % 8, 0)) V = 1;
 
779
        }                                               /* end left shift */
 
780
        WriteDstr (A2, &src1, op);                      /* store result */
 
781
        if ((op & INLINE) == 0)                         /* if reg, clr reg */
 
782
            R[0] = R[1] = R[4] = 0;
 
783
        return;
 
784
 
 
785
/* CVTPN, CVTPNI
 
786
 
 
787
   Operands:
 
788
        A1LNT, A1ADR    =       source string descriptor
 
789
        A2LNT, A2ADR    =       destination string descriptor
 
790
 
 
791
   Condition codes:
 
792
        NZV             =       set from result
 
793
        C               =       0
 
794
 
 
795
    Registers (CVTPN only):
 
796
        R0:R1           =       0
 
797
*/
 
798
 
 
799
case 054: case 0154:
 
800
        ReadDstr (A1, &src1, PACKED);                   /* get source */
 
801
        V = C = 0;                                      /* init cc's */
 
802
        WriteDstr (A2, &src1, NUMERIC);                 /* write dest */
 
803
        if ((op & INLINE) == 0) R[0] = R[1] = 0;        /* if reg, clr reg */
 
804
        return;
 
805
 
 
806
/* CVTNP, CVTNPI
 
807
 
 
808
   Operands:
 
809
        A1LNT, A1ADR    =       source string descriptor
 
810
        A2LNT, A2ADR    =       destination string descriptor
 
811
 
 
812
   Condition codes:
 
813
        NZV             =       set from result
 
814
        C               =       0
 
815
 
 
816
    Registers (CVTNP only):
 
817
        R0:R1           =       0
 
818
*/
 
819
 
 
820
case 055: case 0155:
 
821
        ReadDstr (A1, &src1, NUMERIC);                  /* get source */
 
822
        V = C = 0;                                      /* init cc's */
 
823
        WriteDstr (A2, &src1, PACKED);                  /* write dest */
 
824
        if ((op & INLINE) == 0) R[0] = R[1] = 0;        /* if reg, clr reg */
 
825
        return;
 
826
 
 
827
/* CVTNL, CVTPL, CVTNLI, CVTPLI
 
828
 
 
829
   Operands:
 
830
        A1LNT, A1ADR    =       source string descriptor
 
831
        A2LNT           =       destination address (inline only)
 
832
 
 
833
   Condition codes:
 
834
        NZV             =       set from result
 
835
        C               =       source < 0 and result != 0
 
836
 
 
837
   Registers (CVTNL, CVTPL only):
 
838
        R0:R1           =       0
 
839
        R2:R3           =       result
 
840
*/
 
841
 
 
842
case 053: case 073: case 0153: case 0173:
 
843
        ReadDstr (A1, &src1, op);                       /* get source */
 
844
        V = result = 0;                                 /* clear V, result */
 
845
        for (i = (DSTRLNT * 8) - 1; i > 0; i--) {       /* loop thru digits */
 
846
            digit = (src1.val[i / 8] >> ((i % 8) * 4)) & 0xF;
 
847
            if (digit || result || V) {                 /* skip initial 0's */
 
848
                if (result >= MAXDVAL) V = 1;
 
849
                result = (result * 10) + digit;
 
850
                if (result < digit) V = 1;  }           /* end if */
 
851
            }                                           /* end for */
 
852
        if (src1.sign) result = (~result + 1) & 0xFFFFFFFF;
 
853
        N = GET_SIGN_L (result);
 
854
        Z = GET_Z (result);
 
855
        V = V | (N ^ src1.sign);                        /* overflow if +2**31 */
 
856
        C = src1.sign && (Z == 0);                      /* set C based on std */
 
857
        if (op & INLINE) {                              /* inline? */
 
858
            WriteW (result & 0177777, A2LNT | dsenable);
 
859
            WriteW ((result >> 16) & 0177777,
 
860
                ((A2LNT + 2) & 0177777) | dsenable);  }
 
861
        else {
 
862
            R[0] = R[1] = 0;
 
863
            R[2] = (result >> 16) & 0177777;
 
864
            R[3] = result & 0177777;  }
 
865
        return;
 
866
 
 
867
/* CVTLN, CVTLP, CVTLNI, CVTLPI
 
868
 
 
869
   Operands:
 
870
        A1LNT, A1ADR    =       destination string descriptor
 
871
        A2LNT, A2ADR    =       source long (CVTLNI, CVTLPI) - VAX format
 
872
        R2:R3           =       source long (CVTLN, CVTLP) - EIS format
 
873
 
 
874
   Condition codes:
 
875
        NZV             =       set from result
 
876
        C               =       0
 
877
 
 
878
   Registers (CVTLN, CVTLP only)
 
879
        R2:R3           =       0       
 
880
*/
 
881
 
 
882
case 057: case 077:
 
883
        result = (R[2] << 16) | R[3];                   /* op in EIS format */
 
884
        R[2] = R[3] = 0;                                /* clear registers */
 
885
        goto CVTLx;                                     /* join common code */
 
886
case 0157: case 0177:
 
887
        result = (A2ADR << 16) | A2LNT;                 /* op in VAX format */
 
888
CVTLx:
 
889
        dst = Dstr0;                                    /* clear result */
 
890
        if (dst.sign = GET_SIGN_L (result)) result = (~result + 1) & 0xFFFFFFFF;
 
891
        for (i = 1; (i < (DSTRLNT * 8)) && result; i++) {
 
892
            digit = result % 10;
 
893
            result = result / 10;
 
894
            dst.val[i / 8] = dst.val[i / 8] | (digit << ((i % 8) * 4));  }
 
895
        V = C = 0;
 
896
        WriteDstr (A1, &dst, op);                       /* write result */
 
897
        return;
 
898
default:
 
899
        setTRAP (TRAP_ILL);
 
900
        break;  }
 
901
return;
 
902
}                                                       /* end cis */
 
903
 
 
904
/* Get decimal string
 
905
 
 
906
   Arguments:
 
907
        dscr    =       decimal string descriptor
 
908
        src     =       decimal string structure
 
909
        flag    =       numeric/packed flag
 
910
 
 
911
   The routine returns the length in int32's of the non-zero part of
 
912
   the string.
 
913
 
 
914
   This routine plays fast and loose with operand checking, as did the
 
915
   original 11/23 microcode (half of which I wrote).  In particular,
 
916
 
 
917
   - If the flag specifies packed, the type is not checked at all.
 
918
     The sign of an unsigned string is assumed to be 0xF (an
 
919
     alternative for +).
 
920
   - If the flag specifies numeric, packed types will be treated
 
921
     as unsigned zoned.
 
922
   - For separate, only the '-' sign is checked, not the '+'.
 
923
 
 
924
   However, to simplify the code elsewhere, digits are range checked,
 
925
   and bad digits are replaced with 0's.
 
926
*/
 
927
 
 
928
int32 ReadDstr (int32 *dscr, DSTR *src, int32 flag)
 
929
{
 
930
int32 c, i, end, lnt, type, t;
 
931
 
 
932
*src = Dstr0;                                           /* clear result */
 
933
type = GET_DTYP (dscr[0]);                              /* get type */
 
934
lnt = GET_DLNT (dscr[0]);                               /* get string length */
 
935
if (flag & PACKED) {                                    /* packed? */
 
936
        end = lnt / 2;                                  /* last byte */
 
937
        for (i = 0; i <= end; i++) {                    /* loop thru string */
 
938
            c = ReadB (((dscr[1] + end - i) & 0177777) | dsenable);
 
939
            if (i == 0) t = c & 0xF;                    /* save sign */
 
940
            if ((i == end) && ((lnt & 1) == 0)) c = c & 0xF;
 
941
            if (c >= 0xA0) c = c & 0xF;                 /* check hi digit */
 
942
            if ((c & 0xF) >= 0xA) c = c & 0xF0;         /* check lo digit */    
 
943
            src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8));
 
944
            }                                           /* end for */
 
945
        if ((t == 0xB) || (t == 0xD)) src->sign = 1;    /* if -, set sign */
 
946
        src->val[0] = src->val[0] & ~0xF;               /* clear sign */
 
947
        }                                               /* end packed */
 
948
else {                                                  /* numeric */
 
949
        if (type >= TS) src->sign = (ReadB ((((type == TS)?
 
950
             dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable) == '-');
 
951
        for (i = 1; i <= lnt; i++) {                    /* loop thru string */
 
952
            c = ReadB (((dscr[1] + lnt - i) & 0177777) | dsenable);
 
953
            if ((i == 1) && (type == XZ) && ((c & 0xF0) == 0x70))
 
954
                src->sign = 1;                          /* signed zoned */
 
955
            else if (((i == 1) && (type == TO)) ||
 
956
                ((i == lnt) && (type == LO))) {
 
957
                c = overbin[c & 0177];                  /* get sign and digit */
 
958
                src->sign = c >> 7;  }                  /* set sign */
 
959
            c = c & 0xF;                                /* get digit */
 
960
            if (c > 9) c = 0;                           /* range check */
 
961
            src->val[i / 8] = src->val[i / 8] | (c << ((i % 8) * 4));
 
962
            }                                           /* end for */
 
963
        }                                               /* end numeric */
 
964
return TestDstr (src);                                  /* clean -0 */
 
965
}
 
966
       
 
967
/* Store decimal string
 
968
 
 
969
   Arguments:
 
970
        dsrc    =       decimal string descriptor
 
971
        src     =       decimal string structure
 
972
        flag    =       numeric/packed flag
 
973
   PSW.NZ are also set to their proper values
 
974
   PSW.V will be set on overflow; it must be initialized elsewhere
 
975
        (to allow for external overflow calculations)
 
976
 
 
977
   The rules for the stored sign and the PSW sign are:
 
978
        - Stored sign is negative if input is negative, string type
 
979
          is signed, and the result is non-zero or there was overflow
 
980
        - PSW sign is negative if input is negative, string type is
 
981
          signed, and the result is non-zero
 
982
   Thus, the stored sign and the PSW sign will differ in one case:
 
983
   a negative zero generated by overflow is stored with a negative
 
984
   sign, but PSW.N is clear
 
985
*/
 
986
 
 
987
void WriteDstr (int32 *dscr, DSTR *dst, int32 flag)
 
988
{
 
989
int32 c, i, limit, end, type, lnt;
 
990
uint32 mask;
 
991
static uint32 masktab[8] = {
 
992
        0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,
 
993
        0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000  };
 
994
static int32 unsignedtab[8] = { 0, 1, 0, 0, 0, 0, 0, 1 };
 
995
 
 
996
type = GET_DTYP (dscr[0]);                              /* get type */
 
997
lnt = GET_DLNT (dscr[0]);                               /* get string length */
 
998
mask = 0;                                               /* can't ovflo */
 
999
Z = 1;                                                  /* assume all 0's */
 
1000
limit = lnt / 8;                                        /* limit for test */
 
1001
for (i = 0; i < DSTRLNT; i++) {                         /* loop thru value */
 
1002
        if (i == limit) mask = masktab[lnt % 8];        /* at limit, get mask */
 
1003
        else if (i > limit) mask = 0xFFFFFFFF;          /* beyond, all ovflo */
 
1004
        if (dst->val[i] & mask) V = 1;                  /* test for ovflo */
 
1005
        if (dst->val[i] = dst->val[i] & ~mask) Z = 0;  } /* test nz */
 
1006
dst->sign = dst->sign & ~unsignedtab[type] & ~(Z & ~V);
 
1007
N = dst->sign & ~Z;                                     /* N = sign, if ~zero */
 
1008
 
 
1009
if (flag & PACKED) {                                    /* packed? */
 
1010
        end = lnt / 2;                                  /* end of string */
 
1011
        if (type == UP) dst->val[0] = dst->val[0] | 0xF;
 
1012
        else dst->val[0] = dst->val[0] | 0xC | dst->sign;
 
1013
        for (i = 0; i <= end; i++) {                    /* store string */
 
1014
            c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF;
 
1015
            WriteB (c, ((dscr[1] + end - i) & 0177777));
 
1016
                }                                       /* end for */
 
1017
        }                                               /* end packed */
 
1018
else {
 
1019
        if (type >= TS) WriteB (dst->sign? '-': '+', (((type == TS)?
 
1020
             dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable);
 
1021
        for (i = 1; i <= lnt; i++) {                    /* store string */
 
1022
            c = (dst->val[i / 8] >> ((i % 8) * 4)) & 0xF;       /* get digit */
 
1023
            if ((i == 1) && (type == XZ) && dst->sign)
 
1024
                c = c | 0x70;                           /* signed zoned */
 
1025
            else if (((i == 1) && (type == TO)) ||
 
1026
                ((i == lnt) && (type == LO)))
 
1027
                c = binover[dst->sign][c];              /* get sign and digit */
 
1028
            else c = c | 0x30;                          /* default */
 
1029
            WriteB (c, ((dscr[1] + lnt - i) & 0177777));        
 
1030
            }                                           /* end for */
 
1031
        }                                               /* end numeric */
 
1032
return;
 
1033
}
 
1034
 
 
1035
/* Add decimal string magnitudes
 
1036
 
 
1037
   Arguments:
 
1038
        s1      =       source1 decimal string
 
1039
        s2      =       source2 decimal string
 
1040
        ds      =       destination decimal string
 
1041
        cy      =       carry in
 
1042
   Output       =       1 if carry, 0 if no carry
 
1043
 
 
1044
   This algorithm courtesy Anton Chernoff, circa 1992 or even earlier
 
1045
 
 
1046
   We trace the history of a pair of adjacent digits to see how the
 
1047
   carry is fixed; each parenthesized item is a 4b digit.
 
1048
 
 
1049
   Assume we are adding:
 
1050
        (a)(b)  I
 
1051
   +    (x)(y)  J
 
1052
 
 
1053
   First compute I^J:
 
1054
        (a^x)(b^y)      TMP
 
1055
 
 
1056
   Note that the low bit of each digit is the same as the low bit of
 
1057
   the sum of the digits, ignoring the cary, since the low bit of the
 
1058
   sum is the xor of the bits.
 
1059
 
 
1060
   Now compute I+J+66 to get decimal addition with carry forced left
 
1061
   one digit:
 
1062
        (a+x+6+carry mod 16)(b+y+6 mod 16)      SUM
 
1063
 
 
1064
   Note that if there was a carry from b+y+6, then the low bit of the
 
1065
   left digit is different from the expected low bit from the xor.
 
1066
   If we xor this SUM into TMP, then the low bit of each digit is 1
 
1067
   if there was a carry, and 0 if not.  We need to subtract 6 from each
 
1068
   digit that did not have a carry, so take ~(SUM ^ TMP) & 0x11, shift
 
1069
   it right 4 to the digits that are affected, and subtract 6*adjustment
 
1070
   (actually, shift it right 3 and subtract 3*adjustment).
 
1071
*/
 
1072
 
 
1073
int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy)
 
1074
{
 
1075
int32 i;
 
1076
unsigned int32 sm1, sm2, tm1, tm2, tm3, tm4;
 
1077
 
 
1078
for (i = 0; i < DSTRLNT; i++) {                         /* loop low to high */
 
1079
        tm1 = s1->val[i] ^ (s2->val[i] + cy);           /* xor operands */
 
1080
        sm1 = s1->val[i] + (s2->val[i] + cy);           /* sum operands */
 
1081
        sm2 = sm1 + 0x66666666;                         /* force carry out */
 
1082
        cy = ((sm1 < s1->val[i]) || (sm2 < sm1));       /* check for overflow */
 
1083
        tm2 = tm1 ^ sm2;                                /* get carry flags */
 
1084
        tm3 = (tm2 >> 3) | (cy << 29);                  /* compute adjustment */
 
1085
        tm4 = 0x22222222 & ~tm3;                        /* clear where carry */
 
1086
        ds->val[i] = sm2 - (3 * tm4);  }                /* final result */
 
1087
return cy;
 
1088
}
 
1089
 
 
1090
/* Subtract decimal string magnitudes
 
1091
 
 
1092
   Arguments:
 
1093
        s1      =       source1 decimal string
 
1094
        s2      =       source2 decimal string
 
1095
        ds      =       destination decimal string
 
1096
   Outputs:             s2 - s1 in ds
 
1097
 
 
1098
   Note: the routine assumes that s1 <= s2
 
1099
 
 
1100
*/
 
1101
 
 
1102
void SubDstr (DSTR *s1, DSTR *s2, DSTR *ds)
 
1103
{
 
1104
int32 i;
 
1105
DSTR compl;
 
1106
 
 
1107
for (i = 0; i < DSTRLNT; i++) compl.val[i] = 0x99999999 - s1->val[i];
 
1108
AddDstr (&compl, s2, ds, 1);                            /* s1 + ~s2 + 1 */
 
1109
return;
 
1110
}
 
1111
 
 
1112
/* Compare decimal string magnitudes
 
1113
 
 
1114
   Arguments:
 
1115
        s1      =       source1 decimal string
 
1116
        s2      =       source2 decimal string
 
1117
   Output       =       1 if >, 0 if =, -1 if <
 
1118
*/
 
1119
 
 
1120
int32 CmpDstr (DSTR *s1, DSTR *s2)
 
1121
{
 
1122
int32 i;
 
1123
 
 
1124
for (i = DSTRMAX; i >=0; i--) {
 
1125
        if (s1->val[i] > s2->val[i]) return 1;
 
1126
        if (s1->val[i] < s2->val[i]) return -1;  }
 
1127
return 0;
 
1128
}
 
1129
 
 
1130
/* Test decimal string for zero
 
1131
 
 
1132
   Arguments:
 
1133
        dsrc    =       decimal string structure
 
1134
   Returns the non-zero length of the string, in int32 units
 
1135
   If the string is zero, the sign is cleared
 
1136
*/
 
1137
 
 
1138
int32 TestDstr (DSTR *dsrc)
 
1139
{
 
1140
int32 i;
 
1141
 
 
1142
for (i = DSTRMAX; i >= 0; i--) if (dsrc->val[i]) return (i + 1);
 
1143
dsrc->sign = 0;
 
1144
return 0;
 
1145
}
 
1146
 
 
1147
/* Get exact length of decimal string
 
1148
 
 
1149
   Arguments:
 
1150
        dsrc    =       decimal string structure
 
1151
        nz      =       result from TestDstr
 
1152
*/
 
1153
 
 
1154
int32 LntDstr (DSTR *dsrc, int32 nz)
 
1155
{
 
1156
int32 i;
 
1157
 
 
1158
for (i = 7; i > 0; i--) {
 
1159
        if ((dsrc->val[nz - 1] >> (i * 4)) & 0xF) break;  }
 
1160
return ((nz - 1) * 8) + i;
 
1161
}
 
1162
 
 
1163
/* Create table of multiples
 
1164
 
 
1165
   Arguments:
 
1166
        dsrc    =       base decimal string structure
 
1167
        mtable[10] =    array of decimal string structures
 
1168
 
 
1169
   Note that dsrc has a high order zero nibble; this
 
1170
        guarantees that the largest multiple won't overflow
 
1171
   Also note that mtable[0] is not filled in
 
1172
*/
 
1173
 
 
1174
void CreateTable (DSTR *dsrc, DSTR mtable[10])
 
1175
{
 
1176
int32 (i);
 
1177
 
 
1178
mtable[1] = *dsrc;
 
1179
for (i = 2; i < 10; i++) AddDstr (&mtable[1], &mtable[i-1], &mtable[i], 0);
 
1180
return;
 
1181
}
 
1182
 
 
1183
/* Word shift right
 
1184
 
 
1185
   Arguments:
 
1186
        dsrc    =       decimal string structure
 
1187
        sc      =       shift count
 
1188
*/
 
1189
 
 
1190
void WordRshift (DSTR *dsrc, int32 sc)
 
1191
{
 
1192
int32 i;
 
1193
 
 
1194
if (sc) {
 
1195
        for (i = 0; i < DSTRLNT; i++) {
 
1196
            if ((i + sc) < DSTRLNT) dsrc->val[i] = dsrc->val[i + sc];
 
1197
            else dsrc->val[i] = 0;  }  }
 
1198
return;
 
1199
}
 
1200
 
 
1201
/* Word shift left
 
1202
 
 
1203
   Arguments:
 
1204
        dsrc    =       decimal string structure
 
1205
        sc      =       shift count
 
1206
*/
 
1207
 
 
1208
int32 WordLshift (DSTR *dsrc, int32 sc)
 
1209
{
 
1210
int32 i, c;
 
1211
 
 
1212
c = 0;
 
1213
if (sc) {
 
1214
        for (i = DSTRMAX; i >= 0; i--) {
 
1215
            if (i > (DSTRMAX - sc)) c = c | dsrc->val[i];
 
1216
            if ((i - sc) >= 0) dsrc->val[i] = dsrc->val[i - sc];
 
1217
            else dsrc->val[i] = 0;  }  }
 
1218
return c;
 
1219
}               
 
1220
 
 
1221
/* Nibble shift decimal string right
 
1222
 
 
1223
   Arguments:
 
1224
        dsrc    =       decimal string structure
 
1225
        sc      =       shift count
 
1226
        cin     =       carry in
 
1227
*/
 
1228
 
 
1229
unsigned int32 NibbleRshift (DSTR *dsrc, int32 sc, unsigned int32 cin)
 
1230
{
 
1231
int32 i, s, rs, nc;
 
1232
 
 
1233
if (s = sc * 4) {
 
1234
        rs = 32 - s;
 
1235
        for (i = DSTRMAX; i >= 0; i--) {
 
1236
            nc = dsrc->val[i];
 
1237
            dsrc->val[i] = ((dsrc->val[i] >> s) |
 
1238
                (cin << rs)) & 0xFFFFFFFF;
 
1239
            cin = nc;  }
 
1240
        return cin;  }
 
1241
return 0;
 
1242
}
 
1243
 
 
1244
/* Nibble shift decimal string left
 
1245
 
 
1246
   Arguments:
 
1247
        dsrc    =       decimal string structure
 
1248
        sc      =       shift count
 
1249
        cin     =       carry in
 
1250
*/
 
1251
 
 
1252
unsigned int32 NibbleLshift (DSTR *dsrc, int32 sc, unsigned int32 cin)
 
1253
{
 
1254
int32 i, s, rs, nc;
 
1255
 
 
1256
if (s = sc * 4) {
 
1257
        rs = 32 - s;
 
1258
        for (i = 0; i < DSTRLNT; i++) {
 
1259
            nc = dsrc->val[i];
 
1260
            dsrc->val[i] = ((dsrc->val[i] << s) |
 
1261
                (cin >> rs)) & 0xFFFFFFFF;
 
1262
            cin = nc;  }
 
1263
        return cin;  }
 
1264
return 0;
 
1265
}