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