1 /* vax_cis.c: VAX CIS instructions
3 Copyright (c) 2004-2008, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
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.
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
42 Zero length decimal strings require either zero bytes (trailing) or one byte
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.
53 #if defined (FULL_VAX)
55 /* Decimal string structure */
58 #define DSTRMAX (DSTRLNT - 1)
59 #define MAXDVAL 429496730 /* 2^32 / 10 */
61 #define C_SPACE 0x20 /* ASCII chars */
72 static DSTR Dstr_zero
= { 0, 0, 0, 0, 0 };
73 static DSTR Dstr_one
= { 0, 0x10, 0, 0, 0 };
79 extern int32 fault_PC
;
80 extern int32 ibcnt
, ppc
;
81 extern int32 sim_interval
;
82 extern jmp_buf save_env
;
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
);
103 extern int32
eval_int (void);
107 int32
op_cis (int32
*op
, int32 cc
, int32 opc
, int32 acc
)
109 int32 i
, j
, c
, t
, pop
, rpt
, V
;
110 int32 match
, fill
, sign
, shift
;
113 uint32 nc
, d
, result
;
115 DSTR accum
, src1
, src2
, dst
;
118 switch (opc
) { /* case on opcode */
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
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
133 R[4] = saved cc's/destination string length
134 R[5] = destination string address
137 NZC = set from op[0]:op[4]
141 R0 = src length remaining, or 0
142 R1 = addr of end of source string + 1
146 R5 = addr of end of dest string + 1
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 */
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 */
167 if (R
[2]) { /* move to do? */
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
;
178 R
[1] = (R
[1] + mvl
) & LMASK
; /* adv src, dst */
179 R
[5] = (R
[5] + mvl
) & LMASK
;
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
;
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
);
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 */
199 R
[0] = R
[0] & STR_LNMASK
; /* mask off state */
201 PSL
= PSL
& ~PSL_FPD
;
207 op[0:1] = source string descriptor
208 op[2] = escape character
209 op[3] = table address
210 op[4:5] = destination string descriptor
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
217 R[4] = destination string length
218 R[5] = destination string address
221 NZC = set from op[0]:op[4]
222 V = 1 if match to escape character
225 R0 = src length remaining, or 0
226 R1 = addr of end of source string + 1
229 R4 = dst length remaining, or 0
230 R5 = addr of end of dest string + 1
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 */
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 */
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 */
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
;
264 R
[0] = R
[0] & STR_LNMASK
; /* mask off state */
266 PSL
= PSL
& ~PSL_FPD
;
272 op[0:1] = substring descriptor
273 op[2:3] = string descriptor
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
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]
292 - If the string is zero length, and the substring is not,
293 the outer loop exits immediately, and the result is
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
308 if (PSL
& PSL_FPD
) { /* FPD? */
309 SETPC (fault_PC
+ STR_GETDPC (R
[0])); /* reset PC */
310 R
[2] = R
[2] & STR_LNMASK
;
313 R
[0] = STR_PACK (0, op
[0]); /* srclen + FPD data */
314 R
[1] = op
[1]; /* save operands */
317 PSL
= PSL
| PSL_FPD
; /* set FPD */
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? */
330 if (r
= sim_process_event ()) { /* presumably WRU */
331 PC
= fault_PC
; /* backup up PC */
332 ABORT (r
); /* abort flushes IB */
334 SET_IRQL
; /* update interrupts */
335 if (trpirq
) ABORT (ABORT_INTR
); /* pending? stop */
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
;
346 else { /* if no match */
347 R
[3] = (R
[3] + R
[2]) & LMASK
;
350 PSL
= PSL
& ~PSL_FPD
;
351 CC_IIZZ_L (R
[0]); /* set cc's */
357 op[0] = table address
359 op[2:3] = source string descriptor
361 Registers if PSL<fpd> = 1:
364 R[2] = delta-PC/0/source string length
365 R[3] = source string address
375 R3 = addr + 1 of last byte in source string
379 if (PSL
& PSL_FPD
) { /* FPD? */
380 SETPC (fault_PC
+ STR_GETDPC (R
[2])); /* reset PC */
383 R
[2] = STR_PACK (0, op
[2]); /* srclen + FPD data */
384 R
[0] = op
[1]; /* save operands */
387 PSL
= PSL
| PSL_FPD
; /* set FPD */
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
;
399 PSL
= PSL
& ~PSL_FPD
;
400 CC_IIZZ_L (R
[0]); /* set cc's */
407 op[1] = source string address
408 op[2] = dest string address
417 R1 = addr of source string
419 R3 = addr of dest string
423 if ((PSL
& PSL_FPD
) || (op
[0] > 31))
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 */
434 /* ADDP4, ADDP6, SUBP4, SUBP6
437 op[0:1] = src1 string descriptor
438 op[2:3] = src2 string descriptor
440 op[4:5] = dest string descriptor
443 NZV = set from result
448 R1 = addr of src1 string
450 R3 = addr of src2 string
453 R5 = addr of dest string
456 case ADDP4
: case SUBP4
:
457 op
[4] = op
[2]; /* copy dst */
459 case ADDP6
: case SUBP6
:
460 if ((PSL
& PSL_FPD
) || (op
[0] > 31) ||
461 (op
[2] > 31) || (op
[4] > 31))
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 */
472 SubDstr (&src2
, &src1
, &dst
); /* src1 - src2 */
473 dst
.sign
= src1
.sign
; /* sign = src1 */
475 V
= 0; /* can't carry */
477 else { /* addition */
478 V
= AddDstr (&src1
, &src2
, &dst
, 0); /* add magnitudes */
479 dst
.sign
= src1
.sign
; /* set result sign */
481 cc
= WriteDstr (op
[4], op
[5], &dst
, V
, acc
); /* store result */
486 if (opc
& 1) { /* ADDP6, SUBP6? */
495 op[0:1] = src1 string descriptor
496 op[2:3] = src2 string descriptor
497 op[4:5] = dest string descriptor
500 NZV = set from result
505 R1 = addr of src1 string
507 R3 = addr of src2 string
509 R5 = addr of dest string
513 if ((PSL
& PSL_FPD
) || (op
[0] > 31) ||
514 (op
[2] > 31) || (op
[4] > 31))
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 */
530 V
= TestDstr (&accum
) != 0; /* if ovflo, set V */
532 else V
= 0; /* result = 0 */
533 cc
= WriteDstr (op
[4], op
[5], &dst
, V
, acc
); /* store result */
545 op[0:1] = src1 string descriptor
546 op[2:3] = src2 string descriptor
547 op[4:5] = dest string descriptor
550 NZV = set from result
555 R1 = addr of src1 string
557 R3 = addr of src2 string
559 R5 = addr of dest string
563 if ((PSL
& PSL_FPD
) || (op
[0] > 31) ||
564 (op
[2] > 31) || (op
[4] > 31))
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 */
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
;
590 NibbleLshift (&src2
, 1, 0); /* shift dividend */
591 NibbleLshift (&dst
, 1, 0); /* shift quotient */
592 } /* end divide loop */
594 cc
= WriteDstr (op
[4], op
[5], &dst
, 0, acc
); /* store result */
606 op[0] = string length
607 op[1], op[2] = string lengths
610 op[0:1] = string1 descriptor
611 op[2:3] = string2 descriptor
614 NZ = set from comparison
619 R1 = addr of src1 string
621 R3 = addr of src2 string
625 op
[3] = op
[2]; /* reposition ops */
628 if ((PSL
& PSL_FPD
) || (op
[0] > 31) || (op
[2] > 31))
630 ReadDstr (op
[0], op
[1], &src1
, acc
); /* get src1 */
631 ReadDstr (op
[2], op
[3], &src2
, acc
); /* get src2 */
633 if (src1
.sign
!= src2
.sign
) cc
= (src1
.sign
)? CC_N
: 0;
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);
650 op[1:2] = source string descriptor
652 op[4:5] = dest string descriptor
655 NZV = set from result
660 R1 = addr of src1 string
662 R3 = addr of src2 string
666 if ((PSL
& PSL_FPD
) || (op
[1] > 31) || (op
[4] > 31))
668 ReadDstr (op
[1], op
[2], &src1
, acc
); /* get source */
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 */
694 op[0:1] = source string descriptor
695 op[2] = memory flag/register number
696 op[3] = memory address
699 NZV = set from result
704 R1 = addr of source string
710 if ((PSL
& PSL_FPD
) || (op
[0] > 31))
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;
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 */
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 */
734 return cc
| (V
? CC_V
: 0);
740 op[1:2] = dest string descriptor
743 NZV = set from result
750 R3 = addr of dest string
754 if ((PSL
& PSL_FPD
) || (op
[1] > 31))
756 dst
= Dstr_zero
; /* clear result */
758 if ((result
& LSIGN
) != 0) {
760 result
= (~result
+ 1) & LMASK
;
762 for (i
= 1; (i
< (DSTRLNT
* 8)) && result
; i
++) {
764 result
= result
/ 10;
765 dst
.val
[i
/ 8] = dst
.val
[i
/ 8] | (d
<< ((i
% 8) * 4));
767 cc
= WriteDstr (op
[1], op
[2], &dst
, 0, acc
); /* write result */
777 op[0:1] = source string descriptor
778 op[2:3] = dest string descriptor
781 NZV = set from result
786 R1 = address of sign byte of source string
788 R3 = addr of dest string
792 if ((PSL
& PSL_FPD
) || (op
[0] > 31) || (op
[2] > 31))
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? */
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]? */
804 dst
.val
[i
/ 8] = dst
.val
[i
/ 8] | (d
<< ((i
% 8) * 4));
806 TestDstr (&dst
); /* correct -0 */
807 cc
= WriteDstr (op
[2], op
[3], &dst
, 0, acc
); /* write result */
817 op[0:1] = source string descriptor
818 op[2:3] = dest string descriptor
821 NZV = set from result
826 R1 = addr of source string
828 R3 = addr of dest string
832 if ((PSL
& PSL_FPD
) || (op
[0] > 31) || (op
[2] > 31))
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
);
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 */
857 op[0:1] = source string descriptor
858 op[2] = table address
859 op[3:4] = dest string descriptor
862 NZV = set from result
867 R1 = addr of source string
869 R3 = addr of dest string
873 if ((PSL
& PSL_FPD
) || (op
[0] > 31) || (op
[3] > 31))
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? */
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;
890 dst
.val
[i
/ 8] = dst
.val
[i
/ 8] | (d
<< ((i
% 8) * 4));
892 TestDstr (&dst
); /* correct -0 */
893 cc
= WriteDstr (op
[3], op
[4], &dst
, 0, acc
); /* write result */
903 op[0:1] = source string descriptor
904 op[2] = table address
905 op[3:4] = dest string descriptor
908 NZV = set from result
913 R1 = addr of source string
915 R3 = addr of dest string
919 if ((PSL
& PSL_FPD
) || (op
[0] > 31) || (op
[3] > 31))
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 */
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
);
933 Write ((op
[4] + op
[3] - i
) & LMASK
, c
, L_BYTE
, WA
);
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 */
949 op[0:1] = source string descriptor
950 op[2] = pattern string address
951 op[3] = dest string address
954 N = source is negative
956 V = significant digits lost
957 C = significant digits seen
960 R0<31:16> = -count of source zeroes to supply
961 R0<15:0> = remaining source length
964 R2<19:16> = condition codes
967 R3 = pattern string address
968 R4 = original source length
969 R5 = dest string addr
975 R3 = addr of byte containing EO$END
977 R5 = addr of end of dst string + 1
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.
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 */
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)) {
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 */
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 */
1027 switch (pop
) { /* case on op */
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 */
1037 case EO_CLR_SIGNIF
: /* clear signif */
1038 cc
= cc
& ~CC_C
; /* clr C */
1041 case EO_SET_SIGNIF
: /* set signif */
1042 cc
= cc
| CC_C
; /* set C */
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 */
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 */
1056 case EO_LOAD_SIGN
: /* load sign */
1057 sign
= edit_read_sign (acc
);
1061 case EO_LOAD_PLUS
: /* load sign if + */
1062 if (!(cc
& CC_N
)) sign
= edit_read_sign (acc
);
1066 case EO_LOAD_MINUS
: /* load sign if - */
1067 if (cc
& CC_N
) sign
= edit_read_sign (acc
);
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 */
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
);
1086 R
[3]++; /* now fault safe */
1089 case EO_REPL_SIGN
: /* replace sign */
1090 t
= Read ((R
[3] + 1) & LMASK
, L_BYTE
, RA
);
1091 if (t
== 0) RSVD_OPND_FAULT
;
1093 Write ((R
[5] - t
) & LMASK
, fill
, L_BYTE
, WA
);
1094 R
[3]++; /* now fault safe */
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
;
1106 edit_adv_src (R
[0] - t
); /* adv src ptr */
1108 else R
[0] = R
[0] | (((R
[0] - t
) & WMASK
) << 16);
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 */
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
);
1125 edit_adv_src (rpt
); /* advance src */
1126 R
[5] = (R
[5] + rpt
) & LMASK
; /* advance dst */
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 */
1137 c
= (cc
& CC_C
)? (d
| 0x30): fill
; /* test for signif */
1138 Write ((R
[5] + j
) & LMASK
, c
, L_BYTE
, WA
);
1140 edit_adv_src (rpt
); /* advance src */
1141 R
[5] = (R
[5] + j
) & LMASK
; /* advance dst */
1144 default: /* undefined */
1146 } /* end case pattern */
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 */
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 */
1169 /* Get packed decimal string
1172 lnt = decimal string length
1173 adr = decimal string address
1174 src = decimal string structure
1177 The routine returns the length in int32's of the non-zero part of
1180 To simplify the code elsewhere, digits are range checked,
1181 and bad digits cause a fault.
1184 int32
ReadDstr (int32 lnt
, int32 adr
, DSTR
*src
, int32 acc
)
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 */
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));
1201 if ((t
== 0xB) || (t
== 0xD)) src
->sign
= 1; /* if -, set sign */
1202 return TestDstr (src
); /* clean -0 */
1205 /* Store decimal string
1208 lnt = decimal string length
1209 adr = decimal string address
1210 dst = decimal string structure
1211 V = initial overflow flag
1214 Returns condition codes.
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)
1220 The rules for the stored sign and the PSW sign are:
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
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
1232 int32
WriteDstr (int32 lnt
, int32 adr
, DSTR
*dst
, int32 pslv
, int32 acc
)
1234 int32 c
, i
, cc
, end
;
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
);
1247 /* Set CC for decimal string
1251 dst = decimal string structure
1255 cc = condition codes
1258 int32
SetCCDstr (int32 lnt
, DSTR
*dst
, int32 pslv
)
1260 int32 psln
, pslz
, i
, limit
;
1262 static uint32 masktab
[8] = {
1263 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,
1264 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000
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 */
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);
1283 /* Probe decimal string for accessibility */
1285 void ProbeDstr (int32 lnt
, int32 addr
, int32 acc
)
1287 Read (addr
, L_BYTE
, acc
);
1288 Read ((addr
+ lnt
) & LMASK
, L_BYTE
, acc
);
1292 /* Add decimal string magnitudes
1295 s1 = src1 decimal string
1296 s2 = src2 decimal string
1297 ds = dest decimal string
1299 Output = 1 if carry, 0 if no carry
1301 This algorithm courtesy Anton Chernoff, circa 1992 or even earlier.
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.
1306 Assume we are adding:
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.
1319 Now compute I+J+66 to get decimal addition with carry forced left
1322 (a+x+6+carry mod 16)(b+y+6 mod 16) SUM
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).
1333 int32
AddDstr (DSTR
*s1
, DSTR
*s2
, DSTR
*ds
, int32 cy
)
1336 uint32 sm1
, sm2
, tm1
, tm2
, tm3
, tm4
;
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 */
1351 /* Subtract decimal string magnitudes
1354 s1 = src1 decimal string
1355 s2 = src2 decimal string
1356 ds = dest decimal string
1357 Outputs: s2 - s1 in ds
1359 Note: the routine assumes that s1 <= s2
1363 void SubDstr (DSTR
*s1
, DSTR
*s2
, DSTR
*ds
)
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 */
1374 /* Compare decimal string magnitudes
1377 s1 = src1 decimal string
1378 s2 = src2 decimal string
1379 Output = 1 if >, 0 if =, -1 if <
1382 int32
CmpDstr (DSTR
*s1
, DSTR
*s2
)
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;
1393 /* Test decimal string for zero
1396 dsrc = decimal string structure
1398 Returns the non-zero length of the string, in int32 units
1399 If the string is zero, the sign is cleared
1402 int32
TestDstr (DSTR
*dsrc
)
1406 for (i
= DSTRMAX
; i
>= 0; i
--) if (dsrc
->val
[i
]) return (i
+ 1);
1411 /* Get exact length of decimal string
1414 dsrc = decimal string structure
1415 nz = result from TestDstr
1418 int32
LntDstr (DSTR
*dsrc
, int32 nz
)
1422 if (nz
== 0) return 0;
1423 for (i
= 7; i
> 0; i
--) {
1424 if ((dsrc
->val
[nz
- 1] >> (i
* 4)) & 0xF) break;
1426 return ((nz
- 1) * 8) + i
;
1429 /* Create table of multiples
1432 dsrc = base decimal string structure
1433 mtable[10] = array of decimal string structures
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
1440 void CreateTable (DSTR
*dsrc
, DSTR mtable
[10])
1445 for (i
= 2; i
< 10; i
++)
1446 AddDstr (&mtable
[1], &mtable
[i
-1], &mtable
[i
], 0);
1453 dsrc = decimal string structure
1457 void WordRshift (DSTR
*dsrc
, int32 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;
1473 dsrc = decimal string structure
1477 int32
WordLshift (DSTR
*dsrc
, int32 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;
1492 /* Nibble shift decimal string right
1495 dsrc = decimal string structure
1500 uint32
NibbleRshift (DSTR
*dsrc
, int32 sc
, uint32 cin
)
1506 for (i
= DSTRMAX
; i
>= 0; i
--) {
1508 dsrc
->val
[i
] = ((dsrc
->val
[i
] >> s
) |
1509 (cin
<< rs
)) & LMASK
;
1517 /* Nibble shift decimal string left
1520 dsrc = decimal string structure
1525 uint32
NibbleLshift (DSTR
*dsrc
, int32 sc
, uint32 cin
)
1531 for (i
= 0; i
< DSTRLNT
; i
++) {
1533 dsrc
->val
[i
] = ((dsrc
->val
[i
] << s
) |
1534 (cin
>> rs
)) & LMASK
;
1542 /* Do 4b of CRC calculation
1545 crc = current CRC ^ char
1546 tbl = 16 lw table base
1552 int32
do_crc_4b (int32 crc
, int32 tbl
, int32 acc
)
1554 int32 idx
= (crc
& 0xF) << 2;
1557 crc
= (crc
>> 4) & 0x0FFFFFFF;
1558 t
= Read ((tbl
+ idx
) & LMASK
, L_LONG
, RA
);
1564 int32
edit_read_src (int32 inc
, int32 acc
)
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 */
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 */
1579 c
= Read (r1
, L_BYTE
, RA
);
1580 return (((r0
& 1)? (c
>> 4): c
) & 0xF);
1583 void edit_adv_src (int32 inc
)
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? */
1591 R
[1] = (R
[1] + (inc
/ 2) + ((~R
[0] & inc
) & 1)) & LMASK
;/* retire src */
1592 R
[0] = (R
[0] - inc
) & 0x1F;
1596 int32
edit_read_sign (int32 acc
)
1600 sign
= Read ((R
[3] + 1) & LMASK
, L_BYTE
, RA
); /* read */
1601 R
[2] = ED_PUTSIGN (R
[2], sign
); /* now fault safe */
1610 extern int32 fault_PC
;
1611 extern int32 ibcnt
, ppc
;
1612 extern int32 pcq
[PCQ_SIZE
];
1614 extern jmp_buf save_env
;
1616 /* CIS instructions - invoke emulator interface
1618 opnd[0:5] = six operands to be pushed (if PSL<fpd> = 0)
1619 cc = condition codes
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.
1628 int32
op_cis (int32
*opnd
, int32 cc
, int32 opc
, int32 acc
)
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
);
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
);
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 */