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