Commit | Line | Data |
---|---|---|
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 | |
67 | typedef struct {\r | |
68 | uint32 sign;\r | |
69 | uint32 val[DSTRLNT];\r | |
70 | } DSTR;\r | |
71 | \r | |
72 | static DSTR Dstr_zero = { 0, 0, 0, 0, 0 };\r | |
73 | static DSTR Dstr_one = { 0, 0x10, 0, 0, 0 };\r | |
74 | \r | |
75 | extern int32 R[16];\r | |
76 | extern int32 PSL;\r | |
77 | extern int32 trpirq;\r | |
78 | extern int32 p1;\r | |
79 | extern int32 fault_PC;\r | |
80 | extern int32 ibcnt, ppc;\r | |
81 | extern int32 sim_interval;\r | |
82 | extern jmp_buf save_env;\r | |
83 | \r | |
84 | int32 ReadDstr (int32 lnt, int32 addr, DSTR *dec, int32 acc);\r | |
85 | int32 WriteDstr (int32 lnt, int32 addr, DSTR *dec, int32 v, int32 acc);\r | |
86 | int32 SetCCDstr (int32 lnt, DSTR *src, int32 pslv);\r | |
87 | int32 AddDstr (DSTR *src1, DSTR *src2, DSTR *dst, int32 cin);\r | |
88 | void SubDstr (DSTR *src1, DSTR *src2, DSTR *dst);\r | |
89 | int32 CmpDstr (DSTR *src1, DSTR *src2);\r | |
90 | int32 TestDstr (DSTR *dsrc);\r | |
91 | void ProbeDstr (int32 lnt, int32 addr, int32 acc);\r | |
92 | int32 LntDstr (DSTR *dsrc, int32 nz);\r | |
93 | uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin);\r | |
94 | uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin);\r | |
95 | int32 WordLshift (DSTR *dsrc, int32 sc);\r | |
96 | void WordRshift (DSTR *dsrc, int32 sc);\r | |
97 | void CreateTable (DSTR *dsrc, DSTR mtable[10]);\r | |
98 | int32 do_crc_4b (int32 crc, int32 tbl, int32 acc);\r | |
99 | int32 edit_read_src (int32 inc, int32 acc);\r | |
100 | void edit_adv_src (int32 inc);\r | |
101 | int32 edit_read_sign (int32 acc);\r | |
102 | \r | |
103 | extern int32 eval_int (void);\r | |
104 | \r | |
105 | /* CIS emulator */\r | |
106 | \r | |
107 | int32 op_cis (int32 *op, int32 cc, int32 opc, int32 acc)\r | |
108 | {\r | |
109 | int32 i, j, c, t, pop, rpt, V;\r | |
110 | int32 match, fill, sign, shift;\r | |
111 | int32 ldivd, ldivr;\r | |
112 | int32 lenl, lenp;\r | |
113 | uint32 nc, d, result;\r | |
114 | t_stat r;\r | |
115 | DSTR accum, src1, src2, dst;\r | |
116 | DSTR mptable[10];\r | |
117 | \r | |
118 | switch (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 | |
1166 | return 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 | |
1184 | int32 ReadDstr (int32 lnt, int32 adr, DSTR *src, int32 acc)\r | |
1185 | {\r | |
1186 | int32 c, i, end, t;\r | |
1187 | \r | |
1188 | *src = Dstr_zero; /* clear result */\r | |
1189 | end = lnt / 2; /* last byte */\r | |
1190 | for (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 | |
1201 | if ((t == 0xB) || (t == 0xD)) src->sign = 1; /* if -, set sign */\r | |
1202 | return 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 | |
1232 | int32 WriteDstr (int32 lnt, int32 adr, DSTR *dst, int32 pslv, int32 acc)\r | |
1233 | {\r | |
1234 | int32 c, i, cc, end;\r | |
1235 | \r | |
1236 | end = lnt / 2; /* end of string */\r | |
1237 | ProbeDstr (end, adr, WA); /* test writeability */\r | |
1238 | cc = SetCCDstr (lnt, dst, pslv); /* set cond codes */\r | |
1239 | dst->val[0] = dst->val[0] | 0xC | dst->sign; /* set sign */\r | |
1240 | for (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 | |
1244 | return 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 | |
1258 | int32 SetCCDstr (int32 lnt, DSTR *dst, int32 pslv)\r | |
1259 | {\r | |
1260 | int32 psln, pslz, i, limit;\r | |
1261 | uint32 mask;\r | |
1262 | static uint32 masktab[8] = {\r | |
1263 | 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,\r | |
1264 | 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000\r | |
1265 | };\r | |
1266 | \r | |
1267 | mask = 0; /* can't ovflo */\r | |
1268 | pslz = 1; /* assume all 0's */\r | |
1269 | limit = lnt / 8; /* limit for test */\r | |
1270 | for (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 | |
1277 | dst->sign = dst->sign & ~(pslz & ~pslv);\r | |
1278 | psln = dst->sign & ~pslz; /* N = sign, if ~zero */\r | |
1279 | if (pslv && (PSL & PSW_DV)) SET_TRAP (TRAP_DECOVF);\r | |
1280 | return (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 | |
1285 | void ProbeDstr (int32 lnt, int32 addr, int32 acc)\r | |
1286 | {\r | |
1287 | Read (addr, L_BYTE, acc);\r | |
1288 | Read ((addr + lnt) & LMASK, L_BYTE, acc);\r | |
1289 | return;\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 | |
1333 | int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy)\r | |
1334 | {\r | |
1335 | int32 i;\r | |
1336 | uint32 sm1, sm2, tm1, tm2, tm3, tm4;\r | |
1337 | \r | |
1338 | for (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 | |
1348 | return 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 | |
1363 | void SubDstr (DSTR *s1, DSTR *s2, DSTR *ds)\r | |
1364 | {\r | |
1365 | int32 i;\r | |
1366 | DSTR compl;\r | |
1367 | \r | |
1368 | for (i = 0; i < DSTRLNT; i++) /* 10's comp s2 */\r | |
1369 | compl.val[i] = 0x99999999 - s1->val[i];\r | |
1370 | AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */\r | |
1371 | return;\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 | |
1382 | int32 CmpDstr (DSTR *s1, DSTR *s2)\r | |
1383 | {\r | |
1384 | int32 i;\r | |
1385 | \r | |
1386 | for (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 | |
1390 | return 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 | |
1402 | int32 TestDstr (DSTR *dsrc)\r | |
1403 | {\r | |
1404 | int32 i;\r | |
1405 | \r | |
1406 | for (i = DSTRMAX; i >= 0; i--) if (dsrc->val[i]) return (i + 1);\r | |
1407 | dsrc->sign = 0;\r | |
1408 | return 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 | |
1418 | int32 LntDstr (DSTR *dsrc, int32 nz)\r | |
1419 | {\r | |
1420 | int32 i;\r | |
1421 | \r | |
1422 | if (nz == 0) return 0;\r | |
1423 | for (i = 7; i > 0; i--) {\r | |
1424 | if ((dsrc->val[nz - 1] >> (i * 4)) & 0xF) break;\r | |
1425 | }\r | |
1426 | return ((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 | |
1440 | void CreateTable (DSTR *dsrc, DSTR mtable[10])\r | |
1441 | {\r | |
1442 | int32 (i);\r | |
1443 | \r | |
1444 | mtable[1] = *dsrc;\r | |
1445 | for (i = 2; i < 10; i++)\r | |
1446 | AddDstr (&mtable[1], &mtable[i-1], &mtable[i], 0);\r | |
1447 | return;\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 | |
1457 | void WordRshift (DSTR *dsrc, int32 sc)\r | |
1458 | {\r | |
1459 | int32 i;\r | |
1460 | \r | |
1461 | if (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 | |
1467 | return;\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 | |
1477 | int32 WordLshift (DSTR *dsrc, int32 sc)\r | |
1478 | {\r | |
1479 | int32 i, c;\r | |
1480 | \r | |
1481 | c = 0;\r | |
1482 | if (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 | |
1489 | return 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 | |
1500 | uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin)\r | |
1501 | {\r | |
1502 | int32 i, s, rs, nc;\r | |
1503 | \r | |
1504 | if (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 | |
1514 | return 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 | |
1525 | uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin)\r | |
1526 | {\r | |
1527 | int32 i, s, rs, nc;\r | |
1528 | \r | |
1529 | if (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 | |
1539 | return 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 | |
1552 | int32 do_crc_4b (int32 crc, int32 tbl, int32 acc)\r | |
1553 | {\r | |
1554 | int32 idx = (crc & 0xF) << 2;\r | |
1555 | int32 t;\r | |
1556 | \r | |
1557 | crc = (crc >> 4) & 0x0FFFFFFF;\r | |
1558 | t = Read ((tbl + idx) & LMASK, L_LONG, RA);\r | |
1559 | return crc ^ t;\r | |
1560 | }\r | |
1561 | \r | |
1562 | /* Edit routines */\r | |
1563 | \r | |
1564 | int32 edit_read_src (int32 inc, int32 acc)\r | |
1565 | {\r | |
1566 | int32 c, r0, r1;\r | |
1567 | \r | |
1568 | if (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 | |
1573 | r1 = (R[1] + (inc / 2) + ((~R[0] & inc) & 1)) & LMASK; /* eff addr */\r | |
1574 | r0 = (R[0] - inc) & 0x1F; /* eff lnt left */\r | |
1575 | if (r0 == 0) { /* nothing left? */\r | |
1576 | R[0] = -1; /* out of input */\r | |
1577 | RSVD_OPND_FAULT;\r | |
1578 | }\r | |
1579 | c = Read (r1, L_BYTE, RA);\r | |
1580 | return (((r0 & 1)? (c >> 4): c) & 0xF);\r | |
1581 | }\r | |
1582 | \r | |
1583 | void edit_adv_src (int32 inc)\r | |
1584 | {\r | |
1585 | if (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 | |
1591 | R[1] = (R[1] + (inc / 2) + ((~R[0] & inc) & 1)) & LMASK;/* retire src */\r | |
1592 | R[0] = (R[0] - inc) & 0x1F;\r | |
1593 | return;\r | |
1594 | }\r | |
1595 | \r | |
1596 | int32 edit_read_sign (int32 acc)\r | |
1597 | {\r | |
1598 | int32 sign;\r | |
1599 | \r | |
1600 | sign = Read ((R[3] + 1) & LMASK, L_BYTE, RA); /* read */\r | |
1601 | R[2] = ED_PUTSIGN (R[2], sign); /* now fault safe */\r | |
1602 | return sign;\r | |
1603 | }\r | |
1604 | \r | |
1605 | #else\r | |
1606 | \r | |
1607 | extern int32 R[16];\r | |
1608 | extern int32 PSL;\r | |
1609 | extern int32 SCBB;\r | |
1610 | extern int32 fault_PC;\r | |
1611 | extern int32 ibcnt, ppc;\r | |
1612 | extern int32 pcq[PCQ_SIZE];\r | |
1613 | extern int32 pcq_p;\r | |
1614 | extern 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 | |
1628 | int32 op_cis (int32 *opnd, int32 cc, int32 opc, int32 acc)\r | |
1629 | {\r | |
1630 | int32 vec;\r | |
1631 | \r | |
1632 | if (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 | |
1639 | else {\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 | |
1656 | PSL = PSL & ~(PSL_TP | PSL_FPD | PSW_DV | PSW_FU | PSW_IV | PSW_T);\r | |
1657 | JUMP (vec & ~03); /* set new PC */\r | |
1658 | return 0; /* set new cc's */\r | |
1659 | }\r | |
1660 | \r | |
1661 | #endif\r |