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