First Commit of my working state
[simh.git] / PDP11 / pdp11_cis.c
CommitLineData
196ba1fc
PH
1/* pdp11_cis.c: PDP-11 CIS optional instruction set simulator\r
2\r
3 Copyright (c) 1993-2006, 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 This module simulates the PDP-11 commercial instruction set (CIS).\r
27\r
28 30-May-06 RMS Added interrupt tests to character instructions\r
29 Added 11/44 stack probe test to MOVCx (only)\r
30 22-May-06 RMS Fixed bug in decode table (found by John Dundas)\r
31 Fixed bug in ASHP (reported by John Dundas)\r
32 Fixed bug in write decimal string with mmgt enabled\r
33 Fixed bug in 0-length strings in multiply/divide\r
34 16-Sep-04 RMS Fixed bug in CMPP/N of negative strings\r
35 17-Oct-02 RMS Fixed compiler warning (found by Hans Pufal)\r
36 08-Oct-02 RMS Fixed macro definitions\r
37\r
38 The commercial instruction set consists of three instruction formats:\r
39\r
40 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ register operands\r
41 | 0 1 1 1 1 1| 0 0 0 0| opcode | 076030:076057\r
42 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 076070:076077\r
43\r
44 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ inline operands\r
45 | 0 1 1 1 1 1| 0 0 0 1| opcode | 076130:076157\r
46 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 076170:076177\r
47\r
48 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ load descriptors\r
49 | 0 1 1 1 1 1| 0 0 0 0|op| 1 0| reg | 076020:076027\r
50 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 076060:076067\r
51\r
52 The CIS instructions operate on character strings, packed (decimal)\r
53 strings, and numeric (decimal) strings. Strings are described by\r
54 a two word descriptor:\r
55\r
56 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
57 | length in bytes | char string\r
58 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ descriptor\r
59 | starting byte address |\r
60 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
61\r
62 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
63 | |str type| | length | decimal string\r
64 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ descriptor\r
65 | starting byte address |\r
66 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
67\r
68 Decimal string types are:\r
69\r
70 <14:12> data type bytes occupied by n digits\r
71 0 signed zoned n\r
72 1 unsigned zone n\r
73 2 trailing overpunch n\r
74 3 leading overpunch n\r
75 4 trailing separate n+1\r
76 5 leading separate n+1\r
77 6 signed packed n/2 +1\r
78 7 unsigned packed n/2 +1\r
79\r
80 Zero length character strings occupy no memory; zero length decimal strings\r
81 require either zero bytes (zoned, overpunch) or one byte (separate, packed).\r
82\r
83 CIS instructions can run for a very long time, so they are interruptible\r
84 and restartable. In the simulator, all instructions run to completion.\r
85 The code is unoptimized.\r
86*/\r
87\r
88#include "pdp11_defs.h"\r
89\r
90/* Opcode bits */\r
91\r
92#define INLINE 0100 /* inline */\r
93#define PACKED 0020 /* packed */\r
94#define NUMERIC 0000 /* numeric */\r
95\r
96/* Interrupt test latency */\r
97\r
98#define INT_TEST 100\r
99\r
100/* Operand type definitions */\r
101\r
102#define R0_DESC 1 /* descr in R0:R1 */\r
103#define R2_DESC 2 /* descr in R2:R3 */\r
104#define R4_DESC 3 /* descr in R4:R5 */\r
105#define R4_ARG 4 /* argument in R4 */\r
106#define IN_DESC 5 /* inline descriptor */\r
107#define IN_ARG 6 /* inline argument */\r
108#define MAXOPN 4 /* max # operands */\r
109\r
110/* Decimal data type definitions */\r
111\r
112#define XZ 0 /* signed zoned */\r
113#define UZ 1 /* unsigned zoned */\r
114#define TO 2 /* trailing overpunch */\r
115#define LO 3 /* leading overpunch */\r
116#define TS 4 /* trailing separate */\r
117#define LS 5 /* leading separate */\r
118#define XP 6 /* signed packed */\r
119#define UP 7 /* unsigned packed */\r
120\r
121/* Decimal descriptor definitions */\r
122\r
123#define DTYP_M 07 /* type mask */\r
124#define DTYP_V 12 /* type position */\r
125#define DLNT_M 037 /* length mask */\r
126#define DLNT_V 0 /* length position */\r
127#define GET_DTYP(x) (((x) >> DTYP_V) & DTYP_M)\r
128#define GET_DLNT(x) (((x) >> DLNT_V) & DLNT_M)\r
129\r
130/* Shift operand definitions */\r
131\r
132#define ASHRND_M 017 /* round digit mask */\r
133#define ASHRND_V 8 /* round digit pos */\r
134#define ASHLNT_M 0377 /* shift count mask */\r
135#define ASHLNT_V 0 /* shift length pos */\r
136#define ASHSGN 0200 /* shift sign */\r
137#define GET_ASHRND(x) (((x) >> ASHRND_V) & ASHRND_M)\r
138#define GET_ASHLNT(x) (((x) >> ASHLNT_V) & ASHLNT_M)\r
139\r
140/* Operand array aliases */\r
141\r
142#define A1LNT arg[0]\r
143#define A1ADR arg[1]\r
144#define A2LNT arg[2]\r
145#define A2ADR arg[3]\r
146#define A3LNT arg[4]\r
147#define A3ADR arg[5]\r
148#define A1 &arg[0]\r
149#define A2 &arg[2]\r
150#define A3 &arg[4]\r
151\r
152/* Condition code macros */\r
153\r
154#define GET_BIT(ir,n) (((ir) >> (n)) & 1)\r
155#define GET_SIGN_L(ir) GET_BIT((ir), 31)\r
156#define GET_SIGN_W(ir) GET_BIT((ir), 15)\r
157#define GET_SIGN_B(ir) GET_BIT((ir), 7)\r
158#define GET_Z(ir) ((ir) == 0)\r
159\r
160/* Decimal string structure */\r
161\r
162#define DSTRLNT 4\r
163#define DSTRMAX (DSTRLNT - 1)\r
164#define MAXDVAL 429496730 /* 2^32 / 10 */\r
165\r
166typedef struct {\r
167 uint32 sign;\r
168 uint32 val[DSTRLNT];\r
169 } DSTR;\r
170\r
171static DSTR Dstr0 = { 0, 0, 0, 0, 0 };\r
172\r
173extern int32 isenable, dsenable;\r
174extern int32 N, Z, V, C, fpd, ipl;\r
175extern int32 R[8], trap_req;\r
176extern int32 sim_interval;\r
177extern uint32 cpu_type;\r
178extern FILE *sim_deb;\r
179\r
180int32 ReadDstr (int32 *dscr, DSTR *dec, int32 flag);\r
181void WriteDstr (int32 *dscr, DSTR *dec, int32 flag);\r
182int32 AddDstr (DSTR *src1, DSTR *src2, DSTR *dst, int32 cin);\r
183void SubDstr (DSTR *src1, DSTR *src2, DSTR *dst);\r
184int32 CmpDstr (DSTR *src1, DSTR *src2);\r
185int32 TestDstr (DSTR *dsrc);\r
186int32 LntDstr (DSTR *dsrc, int32 nz);\r
187uint32 NibbleLshift (DSTR *dsrc, int32 sc);\r
188uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin);\r
189int32 WordLshift (DSTR *dsrc, int32 sc);\r
190void WordRshift (DSTR *dsrc, int32 sc);\r
191void CreateTable (DSTR *dsrc, DSTR mtable[10]);\r
192t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st);\r
193int32 movx_setup (int32 op, int32 *arg);\r
194void movx_cleanup (int32 op);\r
195\r
196extern int32 ReadW (int32 addr);\r
197extern void WriteW (int32 data, int32 addr);\r
198extern int32 ReadB (int32 addr);\r
199extern int32 ReadMB (int32 addr);\r
200extern void WriteB (int32 data, int32 addr);\r
201extern int32 calc_ints (int32 nipl, int32 trq);\r
202\r
203/* Table of instruction operands */\r
204\r
205static int32 opntab[128][MAXOPN] = {\r
206 0, 0, 0, 0, 0, 0, 0, 0, /* 000 - 007 */\r
207 0, 0, 0, 0, 0, 0, 0, 0,\r
208 0, 0, 0, 0, 0, 0, 0, 0,\r
209 0, 0, 0, 0, 0, 0, 0, 0,\r
210 0, 0, 0, 0, 0, 0, 0, 0, /* 010 - 017 */\r
211 0, 0, 0, 0, 0, 0, 0, 0,\r
212 0, 0, 0, 0, 0, 0, 0, 0,\r
213 0, 0, 0, 0, 0, 0, 0, 0,\r
214 0, 0, 0, 0, 0, 0, 0, 0, /* LD2R */\r
215 0, 0, 0, 0, 0, 0, 0, 0,\r
216 0, 0, 0, 0, 0, 0, 0, 0,\r
217 0, 0, 0, 0, 0, 0, 0, 0,\r
218 0, 0, 0, 0, /* MOVC */\r
219 0, 0, 0, 0, /* MOVRC */\r
220 0, 0, 0, 0, /* MOVTC */\r
221 0, 0, 0, 0, /* 033 */\r
222 0, 0, 0, 0, 0, 0, 0, 0, /* 034 - 037 */\r
223 0, 0, 0, 0, 0, 0, 0, 0,\r
224 0, 0, 0, 0, /* LOCC */\r
225 0, 0, 0, 0, /* SKPC */\r
226 0, 0, 0, 0, /* SCANC */\r
227 0, 0, 0, 0, /* SPANC */\r
228 0, 0, 0, 0, /* CMPC */\r
229 0, 0, 0, 0, /* MATC */\r
230 0, 0, 0, 0, 0, 0, 0, 0, /* 046 - 047 */\r
231 R0_DESC, R2_DESC, R4_DESC, 0, /* ADDN */\r
232 R0_DESC, R2_DESC, R4_DESC, 0, /* SUBN */\r
233 R0_DESC, R2_DESC, 0, 0, /* CMPN */\r
234 R0_DESC, 0, 0, 0, /* CVTNL */\r
235 R0_DESC, R2_DESC, 0, 0, /* CVTPN */\r
236 R0_DESC, R2_DESC, 0, 0, /* CVTNP */\r
237 R0_DESC, R2_DESC, R4_ARG, 0, /* ASHN */\r
238 R0_DESC, 0, 0, 0, /* CVTLN */\r
239 0, 0, 0, 0, 0, 0, 0, 0, /* LD3R */\r
240 0, 0, 0, 0, 0, 0, 0, 0,\r
241 0, 0, 0, 0, 0, 0, 0, 0,\r
242 0, 0, 0, 0, 0, 0, 0, 0,\r
243 R0_DESC, R2_DESC, R4_DESC, 0, /* ADDP */\r
244 R0_DESC, R2_DESC, R4_DESC, 0, /* SUBP */\r
245 R0_DESC, R2_DESC, 0, 0, /* CMPP */\r
246 R0_DESC, 0, 0, 0, /* CVTPL */\r
247 R0_DESC, R2_DESC, R4_DESC, 0, /* MULP */\r
248 R0_DESC, R2_DESC, R4_DESC, 0, /* DIVP */\r
249 R0_DESC, R2_DESC, R4_ARG, 0, /* ASHP */\r
250 R0_DESC, 0, 0, 0, /* CVTLP */\r
251 0, 0, 0, 0, 0, 0, 0, 0, /* 100 - 107 */\r
252 0, 0, 0, 0, 0, 0, 0, 0,\r
253 0, 0, 0, 0, 0, 0, 0, 0,\r
254 0, 0, 0, 0, 0, 0, 0, 0,\r
255 0, 0, 0, 0, 0, 0, 0, 0, /* 110 - 117 */\r
256 0, 0, 0, 0, 0, 0, 0, 0,\r
257 0, 0, 0, 0, 0, 0, 0, 0,\r
258 0, 0, 0, 0, 0, 0, 0, 0,\r
259 0, 0, 0, 0, 0, 0, 0, 0, /* 120 - 127 */\r
260 0, 0, 0, 0, 0, 0, 0, 0,\r
261 0, 0, 0, 0, 0, 0, 0, 0,\r
262 0, 0, 0, 0, 0, 0, 0, 0,\r
263 IN_DESC, IN_DESC, IN_ARG, 0, /* MOVCI */\r
264 IN_DESC, IN_DESC, IN_ARG, 0, /* MOVRCI */\r
265 IN_DESC, IN_DESC, IN_ARG, IN_ARG, /* MOVTCI */\r
266 0, 0, 0, 0, /* 133 */\r
267 0, 0, 0, 0, 0, 0, 0, 0, /* 134 - 137 */\r
268 0, 0, 0, 0, 0, 0, 0, 0,\r
269 IN_DESC, IN_ARG, 0, 0, /* LOCCI */\r
270 IN_DESC, IN_ARG, 0, 0, /* SKPCI */\r
271 IN_DESC, IN_DESC, 0, 0, /* SCANCI */\r
272 IN_DESC, IN_DESC, 0, 0, /* SPANCI */\r
273 IN_DESC, IN_DESC, IN_ARG, 0, /* CMPCI */\r
274 IN_DESC, IN_DESC, 0, 0, /* MATCI */\r
275 0, 0, 0, 0, 0, 0, 0, 0, /* 146 - 147 */\r
276 IN_DESC, IN_DESC, IN_DESC, 0, /* ADDNI */\r
277 IN_DESC, IN_DESC, IN_DESC, 0, /* SUBNI */\r
278 IN_DESC, IN_DESC, 0, 0, /* CMPNI */\r
279 IN_DESC, IN_ARG, 0, 0, /* CVTNLI */\r
280 IN_DESC, IN_DESC, 0, 0, /* CVTPNI */\r
281 IN_DESC, IN_DESC, 0, 0, /* CVTNPI */\r
282 IN_DESC, IN_DESC, IN_ARG, 0, /* ASHNI */\r
283 IN_DESC, IN_DESC, 0, 0, /* CVTLNI */\r
284 0, 0, 0, 0, 0, 0, 0, 0, /* 160 - 167 */\r
285 0, 0, 0, 0, 0, 0, 0, 0,\r
286 0, 0, 0, 0, 0, 0, 0, 0,\r
287 0, 0, 0, 0, 0, 0, 0, 0,\r
288 IN_DESC, IN_DESC, IN_DESC, 0, /* ADDPI */\r
289 IN_DESC, IN_DESC, IN_DESC, 0, /* SUBPI */\r
290 IN_DESC, IN_DESC, 0, 0, /* CMPPI */\r
291 IN_DESC, IN_ARG, 0, 0, /* CVTPLI */\r
292 IN_DESC, IN_DESC, IN_DESC, 0, /* MULPI */\r
293 IN_DESC, IN_DESC, IN_DESC, 0, /* DIVPI */\r
294 IN_DESC, IN_DESC, IN_ARG, 0, /* ASHPI */\r
295 IN_DESC, IN_DESC, 0, 0 /* CVTLPI */\r
296 };\r
297\r
298/* ASCII to overpunch table: sign is <7>, digit is <4:0> */\r
299\r
300static int32 overbin[128] = {\r
301 0, 0, 0, 0, 0, 0, 0, 0, /* 000 - 037 */\r
302 0, 0, 0, 0, 0, 0, 0, 0,\r
303 0, 0, 0, 0, 0, 0, 0, 0,\r
304 0, 0, 0, 0, 0, 0, 0, 0,\r
305 0, 0x80, 0, 0, 0, 0, 0, 0, /* 040 - 077 */\r
306 0, 0, 0, 0, 0, 0, 0, 0,\r
307 0, 1, 2, 3, 4, 5, 6, 7,\r
308 8, 9, 0x80, 0, 0, 0, 0, 0,\r
309 0, 1, 2, 3, 4, 5, 6, 7, /* 100 - 137 */\r
310 8, 9, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,\r
311 0x87, 0x88, 0x89, 0, 0, 0, 0, 0,\r
312 0, 0, 0, 0, 0, 0x80, 0, 0,\r
313 0, 0, 0, 0, 0, 0, 0, 0, /* 140 - 177 */\r
314 0, 0, 0, 0, 0, 0, 0, 0,\r
315 0, 0, 0, 0, 0, 0, 0, 0,\r
316 0, 0, 0, 0, 0, 0x80, 0, 0\r
317 };\r
318\r
319/* Overpunch to ASCII table: indexed by sign and digit */\r
320\r
321static int32 binover[2][16] = {\r
322 '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',\r
323 '0', '0', '0', '0', '0', '0',\r
324 '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',\r
325 '0', '0', '0', '0', '0', '0'\r
326 };\r
327\r
328static unsigned char movbuf[65536];\r
329\r
330/* CIS emulator */\r
331\r
332t_stat cis11 (int32 IR)\r
333{\r
334int32 c, i, j, t, op, rn, addr;\r
335int32 match, limit, mvlnt, shift;\r
336int32 spc, ldivd, ldivr;\r
337int32 arg[6]; /* operands */\r
338int32 old_PC;\r
339uint32 nc, digit, result;\r
340t_stat st;\r
341static DSTR accum, src1, src2, dst;\r
342static DSTR mptable[10];\r
343static DSTR Dstr1 = { 0, 0x10, 0, 0, 0 };\r
344\r
345old_PC = (PC - 2) & 0177777; /* original PC */\r
346op = IR & 0177; /* IR <6:0> */\r
347for (i = j = 0; (i < MAXOPN) && opntab[op][i]; i++) { /* parse operands */\r
348 switch (opntab[op][i]) { /* case on op type */\r
349\r
350 case R0_DESC:\r
351 arg[j++] = R[0];\r
352 arg[j++] = R[1];\r
353 break;\r
354\r
355 case R2_DESC:\r
356 arg[j++] = R[2];\r
357 arg[j++] = R[3];\r
358 break;\r
359\r
360 case R4_DESC:\r
361 arg[j++] = R[4];\r
362 arg[j++] = R[5];\r
363 break;\r
364\r
365 case R4_ARG:\r
366 arg[j++] = R[4];\r
367 break;\r
368\r
369 case IN_DESC:\r
370 addr = ReadW (PC | isenable);\r
371 PC = (PC + 2) & 0177777;\r
372 arg[j++] = ReadW (addr | dsenable);\r
373 arg[j++] = ReadW (((addr + 2) & 0177777) | dsenable);\r
374 break;\r
375\r
376 case IN_ARG:\r
377 arg[j++] = ReadW (PC | isenable);\r
378 PC = (PC + 2) & 0177777;\r
379 break;\r
380\r
381 default:\r
382 return SCPE_IERR;\r
383 } /* end case */\r
384 } /* end for */\r
385switch (op) { /* case on opcode */\r
386\r
387/* MOVC, MOVTC, MOVCI, MOVTCI\r
388\r
389 Operands (MOVC, MOVTC):\r
390 R0, R1 = source string descriptor\r
391 R2, R3 = dest string descriptor\r
392 R4<7:0> = fill character\r
393 R5 = translation table address (MOVTC only)\r
394 Operands (MOVCI, MOVTCI):\r
395 A1LNT, A1ADR = source string descriptor\r
396 A2LNT, A2ADR = dest string descriptor\r
397 A3LNT<7:0> = fill character\r
398 A3ADR = translation table address (MOVTCI only)\r
399\r
400 Condition codes:\r
401 NZVC = set from src.lnt - dst.lnt\r
402\r
403 Registers (MOVC, MOVTC only)\r
404 R0 = max (0, src.len - dst.len)\r
405 R1:R3 = 0\r
406 R4:R5 = unchanged\r
407\r
408 Notes: \r
409 - If either the source or destination lengths are zero,\r
410 the move loops exit immediately.\r
411 - If the source length does not exceed the destination\r
412 length, the fill loop exits immediately.\r
413*/\r
414\r
415 case 030: case 032: case 0130: case 0132:\r
416 if (!fpd) { /* first time? */\r
417 mvlnt = movx_setup (op, arg); /* set up reg */\r
418 if (R[1] < R[3]) { /* move backwards? */\r
419 R[1] = (R[1] + mvlnt) & 0177777; /* bias addresses */\r
420 R[3] = (R[3] + mvlnt) & 0177777;\r
421 }\r
422 }\r
423\r
424/* At this point,\r
425\r
426 R0-R5 = arguments\r
427 M[SP] = move length */\r
428\r
429 if (R[0] && R[2]) { /* move to do? */\r
430 if (R[1] < R[3]) { /* backwards? */\r
431 for (i = 0; R[0] && R[2]; ) { /* move loop */\r
432 t = ReadB (((R[1] - 1) & 0177777) | dsenable);\r
433 if (op & 2) t = ReadB (((R[5] + t) & 0177777) | dsenable);\r
434 WriteB (t, ((R[3] - 1) & 0177777) | dsenable);\r
435 R[0]--;\r
436 R[1] = (R[1] - 1) & 0177777;\r
437 R[2]--;\r
438 R[3] = (R[3] - 1) & 0177777;\r
439 if ((++i >= INT_TEST) && R[0] && R[2]) {\r
440 if (cis_int_test (i, old_PC, &st)) return st;\r
441 i = 0;\r
442 }\r
443 } /* end for lnts */\r
444 mvlnt = ReadW (SP | dsenable); /* recover mvlnt */\r
445 R[3] = (R[3] + mvlnt) & 0177777; /* end of dst str */\r
446 } /* end if bkwd */\r
447 else { /* forward */\r
448 for (i = 0; R[0] && R[2]; ) { /* move loop */\r
449 t = ReadB ((R[1] & 0177777) | dsenable);\r
450 if (op & 2) t = ReadB (((R[5] + t) & 0177777) | dsenable);\r
451 WriteB (t, (R[3] & 0177777) | dsenable);\r
452 R[0]--;\r
453 R[1] = (R[1] + 1) & 0177777;\r
454 R[2]--;\r
455 R[3] = (R[3] + 1) & 0177777;\r
456 if ((++i >= INT_TEST) && R[0] && R[2]) {\r
457 if (cis_int_test (i, old_PC, &st)) return st;\r
458 i = 0;\r
459 }\r
460 } /* end for lnts */\r
461 } /* end else fwd */\r
462 } /* end if move */\r
463 for (i = 0; i < R[2]; i++) {\r
464 WriteB (R[4], ((R[3] + i) & 0177777) | dsenable);\r
465 }\r
466 movx_cleanup (op); /* cleanup */\r
467 return SCPE_OK;\r
468\r
469/* MOVRC, MOVRCI\r
470\r
471 Operands (MOVC, MOVTC):\r
472 R0, R1 = source string descriptor\r
473 R2, R3 = dest string descriptor\r
474 R4<7:0> = fill character\r
475 Operands (MOVCI, MOVTCI):\r
476 A1LNT, A1ADR = source string descriptor\r
477 A2LNT, A2ADR = dest string descriptor\r
478 A3LNT<7:0> = fill character\r
479\r
480 Condition codes:\r
481 NZVC = set from src.lnt - dst.lnt\r
482\r
483 Registers (MOVRC only)\r
484 R0 = max (0, src.len - dst.len)\r
485 R1:R3 = 0\r
486 R4:R5 = unchanged\r
487\r
488 Notes: see MOVC, MOVCI\r
489*/\r
490\r
491 case 031: case 0131:\r
492 if (!fpd) { /* first time? */\r
493 mvlnt = movx_setup (op, arg); /* set up reg */\r
494 R[1] = (R[1] + R[0] - mvlnt) & 0177777; /* eff move start */\r
495 R[3] = (R[3] + R[2] - mvlnt) & 0177777;\r
496 if (R[1] < R[3]) { /* move backwards? */\r
497 R[1] = (R[1] + mvlnt) & 0177777; /* bias addresses */\r
498 R[3] = (R[3] + mvlnt) & 0177777;\r
499 }\r
500 }\r
501\r
502/* At this point,\r
503\r
504 R0-R5 = arguments\r
505 M[SP] = move length */\r
506\r
507 if (R[0] && R[2]) { /* move to do? */\r
508 if (R[1] < R[3]) { /* backwards? */\r
509 for (i = 0; R[0] && R[2]; ) { /* move loop */\r
510 t = ReadB (((R[1] - 1) & 0177777) | dsenable);\r
511 WriteB (t, ((R[3] - 1) & 0177777) | dsenable);\r
512 R[0]--;\r
513 R[1] = (R[1] - 1) & 0177777;\r
514 R[2]--;\r
515 R[3] = (R[3] - 1) & 0177777;\r
516 if ((++i >= INT_TEST) && R[0] && R[2]) {\r
517 if (cis_int_test (i, old_PC, &st)) return st;\r
518 i = 0;\r
519 }\r
520 } /* end for lnts */\r
521 } /* end if bkwd */\r
522 else { /* forward */\r
523 for (i = 0; R[0] && R[2]; ) { /* move loop */\r
524 t = ReadB ((R[1] & 0177777) | dsenable);\r
525 WriteB (t, (R[3] & 0177777) | dsenable);\r
526 R[0]--;\r
527 R[1] = (R[1] + 1) & 0177777;\r
528 R[2]--;\r
529 R[3] = (R[3] + 1) & 0177777;\r
530 if ((++i >= INT_TEST) && R[0] && R[2]) {\r
531 if (cis_int_test (i, old_PC, &st)) return st;\r
532 i = 0;\r
533 }\r
534 } /* end for lnts */\r
535 mvlnt = ReadW (SP | dsenable); /* recover mvlnt */\r
536 R[3] = (R[3] - mvlnt) & 0177777; /* start of dst str */\r
537 } /* end else fwd */\r
538 } /* end if move */\r
539 for (i = 0; i < R[2]; i++) {\r
540 WriteB (R[4], ((R[3] - R[2] + i) & 0177777) | dsenable);\r
541 }\r
542 movx_cleanup (op); /* cleanup */\r
543 return SCPE_OK;\r
544\r
545/* Load descriptors - no operands */\r
546\r
547 case 020: case 021: case 022: case 023:\r
548 case 024: case 025: case 026: case 027:\r
549 case 060: case 061: case 062: case 063:\r
550 case 064: case 065: case 066: case 067:\r
551 limit = (op & 040)? 6: 4;\r
552 rn = IR & 07; /* get register */\r
553 t = R[rn];\r
554 spc = (rn == 7)? isenable: dsenable;\r
555 for (j = 0; j < limit; j = j + 2) { /* loop for 2,3 dscr */\r
556 addr = ReadW (((t + j) & 0177777) | spc);\r
557 R[j] = ReadW (addr | dsenable);\r
558 R[j + 1] = ReadW (((addr + 2) & 0177777) | dsenable);\r
559 }\r
560 if (rn >= limit) R[rn] = (R[rn] + limit) & 0177777;\r
561 return SCPE_OK;\r
562\r
563/* LOCC, SKPC, LOCCI, SKPCI \r
564\r
565 Operands (LOCC, SKPC):\r
566 R0, R1 = source string descriptor\r
567 R4<7:0> = match character\r
568 Operands (LOCCI, SKPCI):\r
569 A1LNT, A1ADR = source string descriptor\r
570 A2LNT<7:0> = match character\r
571\r
572 Condition codes:\r
573 NZ = set from R0\r
574 VC = 0\r
575\r
576 Registers:\r
577 R0:R1 = substring descriptor where operation terminated\r
578*/\r
579\r
580 case 0140: case 0141: /* inline */\r
581 if (!fpd) { /* FPD clear? */\r
582 WriteW (R[4], ((SP - 2) & 0177777) | dsenable); \r
583 SP = (SP - 2) & 0177777; /* push R4 */\r
584 R[0] = A1LNT; /* args to registers */\r
585 R[1] = A1ADR;\r
586 R[4] = A2LNT;\r
587 } /* fall through */\r
588 case 040: case 041: /* register */\r
589 fpd = 1; /* set FPD */\r
590 R[4] = R[4] & 0377; /* match character */\r
591 for (i = 0; R[0] != 0;) { /* loop */\r
592 c = ReadB (R[1] | dsenable); /* get char */\r
593 if ((c == R[4]) ^ (op & 1)) break; /* = + LOC, != + SKP? */\r
594 R[0]--; /* decr count, */\r
595 R[1] = (R[1] + 1) & 0177777; /* incr addr */\r
596 if ((++i >= INT_TEST) && R[0]) { /* test for intr? */\r
597 if (cis_int_test (i, old_PC, &st)) return st;\r
598 i = 0;\r
599 }\r
600 }\r
601 N = GET_SIGN_W (R[0]);\r
602 Z = GET_Z (R[0]);\r
603 V = C = 0;\r
604 fpd = 0; /* instr done */\r
605 if (op & INLINE) { /* inline? */\r
606 R[4] = ReadW (SP | dsenable); /* restore R4 */\r
607 SP = (SP + 2) & 0177777;\r
608 }\r
609 return SCPE_OK;\r
610\r
611/* SCANC, SPANC, SCANCI, SPANCI\r
612\r
613 Operands (SCANC, SPANC):\r
614 R0, R1 = source string descriptor\r
615 R4<7:0> = mask\r
616 R5 = table address\r
617 Operands (SCANCI, SPANCI):\r
618 A1LNT, A1ADR = source string descriptor\r
619 A2LNT<7:0> = match character\r
620 A2ADR = table address\r
621\r
622 Condition codes:\r
623 NZ = set from R0\r
624 VC = 0\r
625\r
626 Registers:\r
627 R0:R1 = substring descriptor where operation terminated\r
628*/\r
629\r
630 case 0142: case 0143: /* inline */\r
631 if (!fpd) { /* FPD clear? */\r
632 WriteW (R[4], ((SP - 4) & 0177777) | dsenable);\r
633 WriteW (R[5], ((SP - 2) & 0177777) | dsenable);\r
634 SP = (SP - 4) & 0177777; /* push R4, R5 */\r
635 R[0] = A1LNT; /* args to registers */\r
636 R[1] = A1ADR;\r
637 R[4] = A2LNT;\r
638 R[5] = A2ADR;\r
639 } /* fall through */\r
640 case 042: case 043: /* register */\r
641 fpd = 1; /* set FPD */\r
642 R[4] = R[4] & 0377; /* match character */\r
643 for (i = 0; R[0] != 0;) { /* loop */\r
644 t = ReadB (R[1] | dsenable); /* get char as index */\r
645 c = ReadB (((R[5] + t) & 0177777) | dsenable);\r
646 if (((c & R[4]) != 0) ^ (op & 1)) break; /* != + SCN, = + SPN? */\r
647 R[0]--; /* decr count, */\r
648 R[1] = (R[1] + 1) & 0177777; /* incr addr */\r
649 if ((++i >= INT_TEST) && R[0]) { /* test for intr? */\r
650 if (cis_int_test (i, old_PC, &st)) return st;\r
651 i = 0;\r
652 }\r
653 }\r
654 N = GET_SIGN_W (R[0]);\r
655 Z = GET_Z (R[0]);\r
656 V = C = 0;\r
657 fpd = 0; /* instr done */\r
658 if (op & INLINE) { /* inline? */\r
659 R[4] = ReadW (SP | dsenable); /* restore R4, R5 */\r
660 R[5] = ReadW (((SP + 2) & 0177777) | dsenable);\r
661 SP = (SP + 4) & 0177777;\r
662 }\r
663 return SCPE_OK;\r
664\r
665/* CMPC, CMPCI\r
666\r
667 Operands (CMPC):\r
668 R0, R1 = source1 string descriptor\r
669 R2, R3 = source2 string descriptor\r
670 R4<7:0> = fill character\r
671 Operands (CMPCI):\r
672 A1LNT, A1ADR = source1 string descriptor\r
673 A2LNT, A2ADR = source2 string descriptor\r
674 A3LNT<7:0> = fill character\r
675\r
676 Condition codes:\r
677 NZVC = set from src1 - src2 at mismatch, or\r
678 = 0100 if equal\r
679\r
680 Registers (CMPC only):\r
681 R0:R1 = unmatched source1 substring descriptor\r
682 R2:R3 = unmatched source2 substring descriptor\r
683*/\r
684\r
685 case 0144: /* inline */\r
686 if (!fpd) { /* FPD clear? */\r
687 WriteW (R[0], ((SP - 10) & 0177777) | dsenable);\r
688 WriteW (R[1], ((SP - 8) & 0177777) | dsenable);\r
689 WriteW (R[2], ((SP - 6) & 0177777) | dsenable);\r
690 WriteW (R[3], ((SP - 4) & 0177777) | dsenable);\r
691 WriteW (R[4], ((SP - 2) & 0177777) | dsenable);\r
692 SP = (SP - 10) & 0177777; /* push R0 - R4 */\r
693 R[0] = A1LNT; /* args to registers */\r
694 R[1] = A1ADR;\r
695 R[2] = A2LNT;\r
696 R[3] = A2ADR;\r
697 R[4] = A3LNT;\r
698 } /* fall through */\r
699 case 044: /* register */\r
700 fpd = 1; /* set FPD */\r
701 R[4] = R[4] & 0377; /* mask fill */\r
702 c = t = 0;\r
703 for (i = 0; (R[0] || R[2]); ) { /* until cnts == 0 */\r
704 if (R[0]) c = ReadB (R[1] | dsenable); /* get src1 or fill */\r
705 else c = R[4];\r
706 if (R[2]) t = ReadB (R[3] | dsenable); /* get src2 or fill */\r
707 else t = R[4];\r
708 if (c != t) break; /* if diff, done */\r
709 if (R[0]) { /* if more src1 */\r
710 R[0]--; /* decr count, */\r
711 R[1] = (R[1] + 1) & 0177777; /* incr addr */\r
712 }\r
713 if (R[2]) { /* if more src2 */\r
714 R[2]--; /* decr count, */\r
715 R[3] = (R[3] + 1) & 0177777; /* incr addr */\r
716 }\r
717 if ((++i >= INT_TEST) && (R[0] || R[2])) { /* test for intr? */\r
718 if (cis_int_test (i, old_PC, &st)) return st;\r
719 i = 0;\r
720 }\r
721 }\r
722 j = c - t; /* last chars read */\r
723 N = GET_SIGN_B (j); /* set cc's */\r
724 Z = GET_Z (j);\r
725 V = GET_SIGN_B ((c ^ t) & (~t ^ j));\r
726 C = (c < t);\r
727 fpd = 0; /* instr done */\r
728 if (op & INLINE) { /* inline? */\r
729 R[0] = ReadW (SP | dsenable); /* restore R0 - R4 */\r
730 R[1] = ReadW (((SP + 2) & 0177777) | dsenable);\r
731 R[2] = ReadW (((SP + 4) & 0177777) | dsenable);\r
732 R[3] = ReadW (((SP + 6) & 0177777) | dsenable);\r
733 R[4] = ReadW (((SP + 8) & 0177777) | dsenable);\r
734 SP = (SP + 10) & 0177777;\r
735 }\r
736 return SCPE_OK;\r
737\r
738/* MATC, MATCI\r
739\r
740 Operands (MATC):\r
741 R0, R1 = source string descriptor\r
742 R2, R3 = substring descriptor\r
743 Operands (MATCI):\r
744 A1LNT, A1ADR = source1 string descriptor\r
745 A2LNT, A2ADR = source2 string descriptor\r
746\r
747 Condition codes:\r
748 NZ = set from R0\r
749 VC = 0\r
750\r
751 Registers:\r
752 R0:R1 = source substring descriptor for match\r
753\r
754 Notes:\r
755 - If the string is zero length, and the substring is not,\r
756 the outer loop exits immediately, and the result is\r
757 "no match"\r
758 - If the substring is zero length, the inner loop always\r
759 exits immediately, and the result is a "match"\r
760 - If the string is zero length, and the substring is as\r
761 well, the outer loop executes, the inner loop exits\r
762 immediately, and the result is a match, but the result\r
763 is the length of the string (zero), or "no match"\r
764*/\r
765\r
766 case 0145: /* inline */\r
767 if (!fpd) { /* FPD clear? */\r
768 WriteW (R[2], ((SP - 4) & 0177777) | dsenable);\r
769 WriteW (R[3], ((SP - 2) & 0177777) | dsenable);\r
770 SP = (SP - 4) & 0177777; /* push R2, R3 */\r
771 R[0] = A1LNT; /* args to registers */\r
772 R[1] = A1ADR;\r
773 R[2] = A2LNT;\r
774 R[3] = A2ADR;\r
775 } /* fall through */\r
776 case 0045: /* register */\r
777 fpd = 1;\r
778 for (match = 0; R[0] >= R[2]; ) { /* loop thru string */\r
779 for (i = 0, match = 1; match && (i < R[2]); i++) {\r
780 c = ReadB (((R[1] + i) & 0177777) | dsenable);\r
781 t = ReadB (((R[3] + i) & 0177777) | dsenable);\r
782 match = (c == t); /* end for substring */\r
783 }\r
784 if (match) break; /* exit if match */\r
785 R[0]--; /* on to next char */\r
786 R[1] = (R[1] + 1) & 0177777;\r
787 if (cis_int_test (i, old_PC, &st)) return st;\r
788 }\r
789 if (!match) { /* if no match */\r
790 R[1] = (R[1] + R[0]) & 0177777;\r
791 R[0] = 0;\r
792 }\r
793 N = GET_SIGN_W (R[0]);\r
794 Z = GET_Z (R[0]);\r
795 V = C = 0;\r
796 fpd = 0; /* instr done */\r
797 if (op & INLINE) { /* inline? */\r
798 R[2] = ReadW (SP | dsenable); /* restore R2, R3 */\r
799 R[3] = ReadW (((SP + 2) & 0177777) | dsenable);\r
800 SP = (SP + 4) & 0177777;\r
801 }\r
802 return SCPE_OK;\r
803\r
804/* ADDN, SUBN, ADDP, SUBP, ADDNI, SUBNI, ADDPI, SUBPI\r
805\r
806 Operands:\r
807 A1LNT, A1ADR = source1 string descriptor\r
808 A2LNT, A2ADR = source2 string descriptor\r
809 A3LNT, A3ADR = destination string descriptor\r
810\r
811 Condition codes:\r
812 NZV = set from result\r
813 C = 0\r
814\r
815 Registers (ADDN, ADDP, SUBN, SUBP only):\r
816 R0:R3 = 0 \r
817*/\r
818\r
819 case 050: case 051: case 070: case 071:\r
820 case 0150: case 0151: case 0170: case 0171:\r
821 ReadDstr (A1, &src1, op); /* get source1 */\r
822 ReadDstr (A2, &src2, op); /* get source2 */\r
823 if (op & 1) src1.sign = src1.sign ^ 1; /* sub? invert sign */\r
824 if (src1.sign ^ src2.sign) { /* opp signs? sub */\r
825 if (CmpDstr (&src1, &src2) < 0) { /* src1 < src2? */\r
826 SubDstr (&src1, &src2, &dst); /* src2 - src1 */\r
827 dst.sign = src2.sign; /* sign = src2 */\r
828 }\r
829 else {\r
830 SubDstr (&src2, &src1, &dst); /* src1 - src2 */\r
831 dst.sign = src1.sign; /* sign = src1 */\r
832 }\r
833 V = 0; /* can't carry */\r
834 }\r
835 else { /* addition */\r
836 V = AddDstr (&src1, &src2, &dst, 0); /* add magnitudes */\r
837 dst.sign = src1.sign; /* set result sign */\r
838 }\r
839 C = 0;\r
840 WriteDstr (A3, &dst, op); /* store result */\r
841 if ((op & INLINE) == 0) /* if reg, clr reg */\r
842 R[0] = R[1] = R[2] = R[3] = 0;\r
843 return SCPE_OK;\r
844\r
845/* MULP, MULPI\r
846\r
847 Operands:\r
848 A1LNT, A1ADR = source1 string descriptor\r
849 A2LNT, A2ADR = source2 string descriptor\r
850 A3LNT, A3ADR = destination string descriptor\r
851\r
852 Condition codes:\r
853 NZV = set from result\r
854 C = 0\r
855\r
856 Registers (MULP only):\r
857 R0:R3 = 0 \r
858*/\r
859\r
860 case 074: case 0174:\r
861 dst = Dstr0; /* clear result */\r
862 if (ReadDstr (A1, &src1, op) && ReadDstr (A2, &src2, op)) {\r
863 dst.sign = src1.sign ^ src2.sign; /* sign of result */\r
864 accum = Dstr0; /* clear accum */\r
865 NibbleRshift (&src1, 1, 0); /* shift out sign */\r
866 CreateTable (&src1, mptable); /* create *1, *2, ... */\r
867 for (i = 1; i < (DSTRLNT * 8); i++) { /* 31 iterations */\r
868 digit = (src2.val[i / 8] >> ((i % 8) * 4)) & 0xF;\r
869 if (digit > 0) /* add in digit*mpcnd */\r
870 AddDstr (&mptable[digit], &accum, &accum, 0);\r
871 nc = NibbleRshift (&accum, 1, 0); /* ac right 4 */\r
872 NibbleRshift (&dst, 1, nc); /* result right 4 */\r
873 }\r
874 V = TestDstr (&accum) != 0; /* if ovflo, set V */\r
875 }\r
876 else V = 0; /* result = 0 */\r
877 C = 0; /* C = 0 */\r
878 WriteDstr (A3, &dst, op); /* store result */\r
879 if ((op & INLINE) == 0) /* if reg, clr reg */\r
880 R[0] = R[1] = R[2] = R[3] = 0;\r
881 return SCPE_OK;\r
882\r
883/* DIVP, DIVPI\r
884\r
885 Operands:\r
886 A1LNT, A1ADR = divisor string descriptor\r
887 A2LNT, A2ADR = dividend string descriptor\r
888 A3LNT, A3ADR = destination string descriptor\r
889\r
890 Condition codes:\r
891 NZV = set from result\r
892 C = set if divide by zero\r
893\r
894 Registers (DIVP only):\r
895 R0:R3 = 0 \r
896*/\r
897\r
898 case 075: case 0175:\r
899 ldivr = ReadDstr (A1, &src1, op); /* get divisor */\r
900 if (ldivr == 0) { /* divisor = 0? */\r
901 V = C = 1; /* set cc's */\r
902 return SCPE_OK;\r
903 }\r
904 ldivr = LntDstr (&src1, ldivr); /* get exact length */\r
905 ldivd = ReadDstr (A2, &src2, op); /* get dividend */\r
906 ldivd = LntDstr (&src2, ldivd); /* get exact length */\r
907 dst = Dstr0; /* clear dest */\r
908 NibbleRshift (&src1, 1, 0); /* right justify ops */\r
909 NibbleRshift (&src2, 1, 0);\r
910 if ((t = ldivd - ldivr) >= 0) { /* any divide to do? */\r
911 WordLshift (&src1, t / 8); /* align divr to divd */\r
912 NibbleLshift (&src1, t % 8);\r
913 CreateTable (&src1, mptable); /* create *1, *2, ... */\r
914 for (i = 0; i <= t; i++) { /* divide loop */\r
915 for (digit = 9; digit > 0; digit--) { /* find digit */\r
916 if (CmpDstr (&src2, &mptable[digit]) >= 0) {\r
917 SubDstr (&mptable[digit], &src2, &src2);\r
918 dst.val[0] = dst.val[0] | digit;\r
919 break;\r
920 } /* end if */\r
921 } /* end for */\r
922 NibbleLshift (&src2, 1); /* shift dividend */\r
923 NibbleLshift (&dst, 1); /* shift quotient */\r
924 } /* end divide loop */\r
925 dst.sign = src1.sign ^ src2.sign; /* calculate sign */\r
926 } /* end if */\r
927 V = C = 0;\r
928 WriteDstr (A3, &dst, op); /* store result */\r
929 if ((op & INLINE) == 0) /* if reg, clr reg */\r
930 R[0] = R[1] = R[2] = R[3] = 0;\r
931 return SCPE_OK;\r
932\r
933/* CMPN, CMPP, CMPNI, CMPPI\r
934\r
935 Operands:\r
936 A1LNT, A1ADR = source1 string descriptor\r
937 A2LNT, A2ADR = source2 string descriptor\r
938\r
939 Condition codes:\r
940 NZ = set from comparison\r
941 VC = 0\r
942\r
943 Registers (CMPN, CMPP only):\r
944 R0:R3 = 0\r
945*/\r
946\r
947 case 052: case 072: case 0152: case 0172:\r
948 ReadDstr (A1, &src1, op); /* get source1 */\r
949 ReadDstr (A2, &src2, op); /* get source2 */\r
950 N = Z = V = C = 0;\r
951 if (src1.sign != src2.sign) N = src1.sign;\r
952 else {\r
953 t = CmpDstr (&src1, &src2); /* compare strings */\r
954 if (t < 0) N = (src1.sign? 0: 1);\r
955 else if (t > 0) N = (src1.sign? 1: 0);\r
956 else Z = 1;\r
957 }\r
958 if ((op & INLINE) == 0) /* if reg, clr reg */\r
959 R[0] = R[1] = R[2] = R[3] = 0;\r
960 return SCPE_OK;\r
961\r
962/* ASHN, ASHP, ASHNI, ASHPI\r
963\r
964 Operands:\r
965 A1LNT, A1ADR = source string descriptor\r
966 A2LNT, A2ADR = destination string descriptor\r
967 A3LNT<11:8> = rounding digit\r
968 A3LNT<7:0> = shift count\r
969\r
970 Condition codes:\r
971 NZV = set from result\r
972 C = 0\r
973\r
974 Registers (ASHN, ASHP only):\r
975 R0:R1, R4 = 0 \r
976*/\r
977\r
978 case 056: case 076: case 0156: case 0176:\r
979 ReadDstr (A1, &src1, op); /* get source */\r
980 V = C = 0; /* init cc's */\r
981 shift = GET_ASHLNT (A3LNT); /* get shift count */\r
982 if (shift & ASHSGN) { /* right shift? */\r
983 shift = (ASHLNT_M + 1 - shift); /* !shift! */\r
984 WordRshift (&src1, shift / 8); /* do word shifts */ \r
985 NibbleRshift (&src1, shift % 8, 0); /* do nibble shifts */\r
986 t = GET_ASHRND (A3LNT); /* get rounding digit */\r
987 if ((t + (src1.val[0] & 0xF)) > 9) /* rounding needed? */\r
988 AddDstr (&src1, &Dstr1, &src1, 0); /* round */\r
989 src1.val[0] = src1.val[0] & ~0xF; /* clear sign */\r
990 } /* end right shift */\r
991 else if (shift) { /* left shift? */\r
992 if (WordLshift (&src1, shift / 8)) V = 1; /* do word shifts */\r
993 if (NibbleLshift (&src1, shift % 8)) V = 1;\r
994 } /* end left shift */\r
995 WriteDstr (A2, &src1, op); /* store result */\r
996 if ((op & INLINE) == 0) /* if reg, clr reg */\r
997 R[0] = R[1] = R[4] = 0;\r
998 return SCPE_OK;\r
999\r
1000/* CVTPN, CVTPNI\r
1001\r
1002 Operands:\r
1003 A1LNT, A1ADR = source string descriptor\r
1004 A2LNT, A2ADR = destination string descriptor\r
1005\r
1006 Condition codes:\r
1007 NZV = set from result\r
1008 C = 0\r
1009\r
1010 Registers (CVTPN only):\r
1011 R0:R1 = 0\r
1012*/\r
1013\r
1014 case 054: case 0154:\r
1015 ReadDstr (A1, &src1, PACKED); /* get source */\r
1016 V = C = 0; /* init cc's */\r
1017 WriteDstr (A2, &src1, NUMERIC); /* write dest */\r
1018 if ((op & INLINE) == 0) R[0] = R[1] = 0; /* if reg, clr reg */\r
1019 return SCPE_OK;\r
1020\r
1021/* CVTNP, CVTNPI\r
1022\r
1023 Operands:\r
1024 A1LNT, A1ADR = source string descriptor\r
1025 A2LNT, A2ADR = destination string descriptor\r
1026\r
1027 Condition codes:\r
1028 NZV = set from result\r
1029 C = 0\r
1030\r
1031 Registers (CVTNP only):\r
1032 R0:R1 = 0\r
1033*/\r
1034\r
1035 case 055: case 0155:\r
1036 ReadDstr (A1, &src1, NUMERIC); /* get source */\r
1037 V = C = 0; /* init cc's */\r
1038 WriteDstr (A2, &src1, PACKED); /* write dest */\r
1039 if ((op & INLINE) == 0) R[0] = R[1] = 0; /* if reg, clr reg */\r
1040 return SCPE_OK;\r
1041\r
1042/* CVTNL, CVTPL, CVTNLI, CVTPLI\r
1043\r
1044 Operands:\r
1045 A1LNT, A1ADR = source string descriptor\r
1046 A2LNT = destination address (inline only)\r
1047\r
1048 Condition codes:\r
1049 NZV = set from result\r
1050 C = source < 0 and result != 0\r
1051\r
1052 Registers (CVTNL, CVTPL only):\r
1053 R0:R1 = 0\r
1054 R2:R3 = result\r
1055*/\r
1056\r
1057 case 053: case 073: case 0153: case 0173:\r
1058 ReadDstr (A1, &src1, op); /* get source */\r
1059 V = result = 0; /* clear V, result */\r
1060 for (i = (DSTRLNT * 8) - 1; i > 0; i--) { /* loop thru digits */\r
1061 digit = (src1.val[i / 8] >> ((i % 8) * 4)) & 0xF;\r
1062 if (digit || result || V) { /* skip initial 0's */\r
1063 if (result >= MAXDVAL) V = 1;\r
1064 result = (result * 10) + digit;\r
1065 if (result < digit) V = 1;\r
1066 } /* end if */\r
1067 } /* end for */\r
1068 if (src1.sign) result = (~result + 1) & 0xFFFFFFFF;\r
1069 N = GET_SIGN_L (result);\r
1070 Z = GET_Z (result);\r
1071 V = V | (N ^ src1.sign); /* overflow if +2**31 */\r
1072 C = src1.sign && (Z == 0); /* set C based on std */\r
1073 if (op & INLINE) { /* inline? */\r
1074 WriteW (result & 0177777, A2LNT | dsenable);\r
1075 WriteW ((result >> 16) & 0177777,\r
1076 ((A2LNT + 2) & 0177777) | dsenable);\r
1077 }\r
1078 else {\r
1079 R[0] = R[1] = 0;\r
1080 R[2] = (result >> 16) & 0177777;\r
1081 R[3] = result & 0177777;\r
1082 }\r
1083 return SCPE_OK;\r
1084\r
1085/* CVTLN, CVTLP, CVTLNI, CVTLPI\r
1086\r
1087 Operands:\r
1088 A1LNT, A1ADR = destination string descriptor\r
1089 A2LNT, A2ADR = source long (CVTLNI, CVTLPI) - VAX format\r
1090 R2:R3 = source long (CVTLN, CVTLP) - EIS format\r
1091\r
1092 Condition codes:\r
1093 NZV = set from result\r
1094 C = 0\r
1095\r
1096 Registers (CVTLN, CVTLP only)\r
1097 R2:R3 = 0 \r
1098*/\r
1099\r
1100 case 057: case 077:\r
1101 result = (R[2] << 16) | R[3]; /* op in EIS format */\r
1102 R[2] = R[3] = 0; /* clear registers */\r
1103 goto CVTLx; /* join common code */\r
1104 case 0157: case 0177:\r
1105 result = (A2ADR << 16) | A2LNT; /* op in VAX format */\r
1106 CVTLx:\r
1107 dst = Dstr0; /* clear result */\r
1108 if (dst.sign = GET_SIGN_L (result)) result = (~result + 1) & 0xFFFFFFFF;\r
1109 for (i = 1; (i < (DSTRLNT * 8)) && result; i++) {\r
1110 digit = result % 10;\r
1111 result = result / 10;\r
1112 dst.val[i / 8] = dst.val[i / 8] | (digit << ((i % 8) * 4));\r
1113 }\r
1114 V = C = 0;\r
1115 WriteDstr (A1, &dst, op); /* write result */\r
1116 return SCPE_OK;\r
1117\r
1118 default:\r
1119 setTRAP (TRAP_ILL);\r
1120 break;\r
1121 } /* end case */\r
1122return SCPE_OK;\r
1123} /* end cis */\r
1124\r
1125/* Get decimal string\r
1126\r
1127 Arguments:\r
1128 dscr = decimal string descriptor\r
1129 src = decimal string structure\r
1130 flag = numeric/packed flag\r
1131\r
1132 The routine returns the length in int32's of the non-zero part of\r
1133 the string.\r
1134\r
1135 This routine plays fast and loose with operand checking, as did the\r
1136 original 11/23 microcode (half of which I wrote). In particular,\r
1137\r
1138 - If the flag specifies packed, the type is not checked at all.\r
1139 The sign of an unsigned string is assumed to be 0xF (an\r
1140 alternative for +).\r
1141 - If the flag specifies numeric, packed types will be treated\r
1142 as unsigned zoned.\r
1143 - For separate, only the '-' sign is checked, not the '+'.\r
1144\r
1145 However, to simplify the code elsewhere, digits are range checked,\r
1146 and bad digits are replaced with 0's.\r
1147*/\r
1148\r
1149int32 ReadDstr (int32 *dscr, DSTR *src, int32 flag)\r
1150{\r
1151int32 c, i, end, lnt, type, t;\r
1152\r
1153*src = Dstr0; /* clear result */\r
1154type = GET_DTYP (dscr[0]); /* get type */\r
1155lnt = GET_DLNT (dscr[0]); /* get string length */\r
1156if (flag & PACKED) { /* packed? */\r
1157 end = lnt / 2; /* last byte */\r
1158 for (i = 0; i <= end; i++) { /* loop thru string */\r
1159 c = ReadB (((dscr[1] + end - i) & 0177777) | dsenable);\r
1160 if (i == 0) t = c & 0xF; /* save sign */\r
1161 if ((i == end) && ((lnt & 1) == 0)) c = c & 0xF;\r
1162 if (c >= 0xA0) c = c & 0xF; /* check hi digit */\r
1163 if ((c & 0xF) >= 0xA) c = c & 0xF0; /* check lo digit */ \r
1164 src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8));\r
1165 } /* end for */\r
1166 if ((t == 0xB) || (t == 0xD)) src->sign = 1; /* if -, set sign */\r
1167 src->val[0] = src->val[0] & ~0xF; /* clear sign */\r
1168 } /* end packed */\r
1169else { /* numeric */\r
1170 if (type >= TS) src->sign = (ReadB ((((type == TS)?\r
1171 dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable) == '-');\r
1172 for (i = 1; i <= lnt; i++) { /* loop thru string */\r
1173 c = ReadB (((dscr[1] + lnt - i) & 0177777) | dsenable);\r
1174 if ((i == 1) && (type == XZ) && ((c & 0xF0) == 0x70))\r
1175 src->sign = 1; /* signed zoned */\r
1176 else if (((i == 1) && (type == TO)) ||\r
1177 ((i == lnt) && (type == LO))) {\r
1178 c = overbin[c & 0177]; /* get sign and digit */\r
1179 src->sign = c >> 7; /* set sign */\r
1180 }\r
1181 c = c & 0xF; /* get digit */\r
1182 if (c > 9) c = 0; /* range check */\r
1183 src->val[i / 8] = src->val[i / 8] | (c << ((i % 8) * 4));\r
1184 } /* end for */\r
1185 } /* end numeric */\r
1186return TestDstr (src); /* clean -0 */\r
1187}\r
1188 \r
1189/* Store decimal string\r
1190\r
1191 Arguments:\r
1192 dsrc = decimal string descriptor\r
1193 src = decimal string structure\r
1194 flag = numeric/packed flag\r
1195\r
1196 PSW.NZ are also set to their proper values\r
1197 PSW.V will be set on overflow; it must be initialized elsewhere\r
1198 (to allow for external overflow calculations)\r
1199\r
1200 The rules for the stored sign and the PSW sign are:\r
1201\r
1202 - Stored sign is negative if input is negative, string type\r
1203 is signed, and the result is non-zero or there was overflow\r
1204 - PSW sign is negative if input is negative, string type is\r
1205 signed, and the result is non-zero\r
1206\r
1207 Thus, the stored sign and the PSW sign will differ in one case:\r
1208 a negative zero generated by overflow is stored with a negative\r
1209 sign, but PSW.N is clear\r
1210*/\r
1211\r
1212void WriteDstr (int32 *dscr, DSTR *dst, int32 flag)\r
1213{\r
1214int32 c, i, limit, end, type, lnt;\r
1215uint32 mask;\r
1216static uint32 masktab[8] = {\r
1217 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,\r
1218 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000\r
1219 };\r
1220static int32 unsignedtab[8] = { 0, 1, 0, 0, 0, 0, 0, 1 };\r
1221\r
1222type = GET_DTYP (dscr[0]); /* get type */\r
1223lnt = GET_DLNT (dscr[0]); /* get string length */\r
1224mask = 0; /* can't ovflo */\r
1225Z = 1; /* assume all 0's */\r
1226limit = lnt / 8; /* limit for test */\r
1227for (i = 0; i < DSTRLNT; i++) { /* loop thru value */\r
1228 if (i == limit) mask = masktab[lnt % 8]; /* at limit, get mask */\r
1229 else if (i > limit) mask = 0xFFFFFFFF; /* beyond, all ovflo */\r
1230 if (dst->val[i] & mask) V = 1; /* test for ovflo */\r
1231 if (dst->val[i] = dst->val[i] & ~mask) Z = 0; /* test nz */\r
1232 }\r
1233dst->sign = dst->sign & ~unsignedtab[type] & ~(Z & ~V);\r
1234N = dst->sign & ~Z; /* N = sign, if ~zero */\r
1235\r
1236if (flag & PACKED) { /* packed? */\r
1237 end = lnt / 2; /* end of string */\r
1238 if (type == UP) dst->val[0] = dst->val[0] | 0xF;\r
1239 else dst->val[0] = dst->val[0] | 0xC | dst->sign;\r
1240 for (i = 0; i <= end; i++) { /* store string */\r
1241 c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF;\r
1242 WriteB (c, ((dscr[1] + end - i) & 0177777) | dsenable);\r
1243 } /* end for */\r
1244 } /* end packed */\r
1245else {\r
1246 if (type >= TS) WriteB (dst->sign? '-': '+', (((type == TS)?\r
1247 dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable);\r
1248 for (i = 1; i <= lnt; i++) { /* store string */\r
1249 c = (dst->val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */\r
1250 if ((i == 1) && (type == XZ) && dst->sign)\r
1251 c = c | 0x70; /* signed zoned */\r
1252 else if (((i == 1) && (type == TO)) ||\r
1253 ((i == lnt) && (type == LO)))\r
1254 c = binover[dst->sign][c]; /* get sign and digit */\r
1255 else c = c | 0x30; /* default */\r
1256 WriteB (c, ((dscr[1] + lnt - i) & 0177777) |dsenable ); \r
1257 } /* end for */\r
1258 } /* end numeric */\r
1259return;\r
1260}\r
1261\r
1262/* Add decimal string magnitudes\r
1263\r
1264 Arguments:\r
1265 s1 = source1 decimal string\r
1266 s2 = source2 decimal string\r
1267 ds = destination decimal string\r
1268 cy = carry in\r
1269 Output = 1 if carry, 0 if no carry\r
1270\r
1271 This algorithm courtesy Anton Chernoff, circa 1992 or even earlier.\r
1272\r
1273 We trace the history of a pair of adjacent digits to see how the\r
1274 carry is fixed; each parenthesized item is a 4b digit.\r
1275\r
1276 Assume we are adding:\r
1277\r
1278 (a)(b) I\r
1279 + (x)(y) J\r
1280\r
1281 First compute I^J:\r
1282\r
1283 (a^x)(b^y) TMP\r
1284\r
1285 Note that the low bit of each digit is the same as the low bit of\r
1286 the sum of the digits, ignoring the cary, since the low bit of the\r
1287 sum is the xor of the bits.\r
1288\r
1289 Now compute I+J+66 to get decimal addition with carry forced left\r
1290 one digit:\r
1291\r
1292 (a+x+6+carry mod 16)(b+y+6 mod 16) SUM\r
1293\r
1294 Note that if there was a carry from b+y+6, then the low bit of the\r
1295 left digit is different from the expected low bit from the xor.\r
1296 If we xor this SUM into TMP, then the low bit of each digit is 1\r
1297 if there was a carry, and 0 if not. We need to subtract 6 from each\r
1298 digit that did not have a carry, so take ~(SUM ^ TMP) & 0x11, shift\r
1299 it right 4 to the digits that are affected, and subtract 6*adjustment\r
1300 (actually, shift it right 3 and subtract 3*adjustment).\r
1301*/\r
1302\r
1303int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy)\r
1304{\r
1305int32 i;\r
1306uint32 sm1, sm2, tm1, tm2, tm3, tm4;\r
1307\r
1308for (i = 0; i < DSTRLNT; i++) { /* loop low to high */\r
1309 tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */\r
1310 sm1 = s1->val[i] + (s2->val[i] + cy); /* sum operands */\r
1311 sm2 = sm1 + 0x66666666; /* force carry out */\r
1312 cy = ((sm1 < s1->val[i]) || (sm2 < sm1)); /* check for overflow */\r
1313 tm2 = tm1 ^ sm2; /* get carry flags */\r
1314 tm3 = (tm2 >> 3) | (cy << 29); /* compute adjustment */\r
1315 tm4 = 0x22222222 & ~tm3; /* clear where carry */\r
1316 ds->val[i] = sm2 - (3 * tm4); /* final result */\r
1317 }\r
1318return cy;\r
1319}\r
1320\r
1321/* Subtract decimal string magnitudes\r
1322\r
1323 Arguments:\r
1324 s1 = source1 decimal string\r
1325 s2 = source2 decimal string\r
1326 ds = destination decimal string\r
1327 Outputs: s2 - s1 in ds\r
1328\r
1329 Note: the routine assumes that s1 <= s2\r
1330\r
1331*/\r
1332\r
1333void SubDstr (DSTR *s1, DSTR *s2, DSTR *ds)\r
1334{\r
1335int32 i;\r
1336DSTR compl;\r
1337\r
1338for (i = 0; i < DSTRLNT; i++) compl.val[i] = 0x99999999 - s1->val[i];\r
1339AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */\r
1340return;\r
1341}\r
1342\r
1343/* Compare decimal string magnitudes\r
1344\r
1345 Arguments:\r
1346 s1 = source1 decimal string\r
1347 s2 = source2 decimal string\r
1348 Output = 1 if >, 0 if =, -1 if <\r
1349*/\r
1350\r
1351int32 CmpDstr (DSTR *s1, DSTR *s2)\r
1352{\r
1353int32 i;\r
1354\r
1355for (i = DSTRMAX; i >=0; i--) {\r
1356 if (s1->val[i] > s2->val[i]) return 1;\r
1357 if (s1->val[i] < s2->val[i]) return -1;\r
1358 }\r
1359return 0;\r
1360}\r
1361\r
1362/* Test decimal string for zero\r
1363\r
1364 Arguments:\r
1365 dsrc = decimal string structure\r
1366\r
1367 Returns the non-zero length of the string, in int32 units\r
1368 If the string is zero, the sign is cleared\r
1369*/\r
1370\r
1371int32 TestDstr (DSTR *dsrc)\r
1372{\r
1373int32 i;\r
1374\r
1375for (i = DSTRMAX; i >= 0; i--) if (dsrc->val[i]) return (i + 1);\r
1376dsrc->sign = 0;\r
1377return 0;\r
1378}\r
1379\r
1380/* Get exact length of decimal string\r
1381\r
1382 Arguments:\r
1383 dsrc = decimal string structure\r
1384 nz = result from TestDstr\r
1385*/\r
1386\r
1387int32 LntDstr (DSTR *dsrc, int32 nz)\r
1388{\r
1389int32 i;\r
1390\r
1391if (nz == 0) return 0;\r
1392for (i = 7; i > 0; i--) {\r
1393 if ((dsrc->val[nz - 1] >> (i * 4)) & 0xF) break;\r
1394 }\r
1395return ((nz - 1) * 8) + i;\r
1396}\r
1397\r
1398/* Create table of multiples\r
1399\r
1400 Arguments:\r
1401 dsrc = base decimal string structure\r
1402 mtable[10] = array of decimal string structures\r
1403\r
1404 Note that dsrc has a high order zero nibble; this\r
1405 guarantees that the largest multiple won't overflow.\r
1406 Also note that mtable[0] is not filled in.\r
1407*/\r
1408\r
1409void CreateTable (DSTR *dsrc, DSTR mtable[10])\r
1410{\r
1411int32 (i);\r
1412\r
1413mtable[1] = *dsrc;\r
1414for (i = 2; i < 10; i++) AddDstr (&mtable[1], &mtable[i-1], &mtable[i], 0);\r
1415return;\r
1416}\r
1417\r
1418/* Word shift right\r
1419\r
1420 Arguments:\r
1421 dsrc = decimal string structure\r
1422 sc = shift count\r
1423*/\r
1424\r
1425void WordRshift (DSTR *dsrc, int32 sc)\r
1426{\r
1427int32 i;\r
1428\r
1429if (sc) {\r
1430 for (i = 0; i < DSTRLNT; i++) {\r
1431 if ((i + sc) < DSTRLNT) dsrc->val[i] = dsrc->val[i + sc];\r
1432 else dsrc->val[i] = 0;\r
1433 }\r
1434 }\r
1435return;\r
1436}\r
1437\r
1438/* Word shift left\r
1439\r
1440 Arguments:\r
1441 dsrc = decimal string structure\r
1442 sc = shift count\r
1443*/\r
1444\r
1445int32 WordLshift (DSTR *dsrc, int32 sc)\r
1446{\r
1447int32 i, c;\r
1448\r
1449c = 0;\r
1450if (sc) {\r
1451 for (i = DSTRMAX; i >= 0; i--) {\r
1452 if (i > (DSTRMAX - sc)) c = c | dsrc->val[i];\r
1453 if ((i - sc) >= 0) dsrc->val[i] = dsrc->val[i - sc];\r
1454 else dsrc->val[i] = 0;\r
1455 }\r
1456 }\r
1457return c;\r
1458} \r
1459\r
1460/* Nibble shift decimal string right\r
1461\r
1462 Arguments:\r
1463 dsrc = decimal string structure\r
1464 sc = shift count\r
1465 cin = carry in\r
1466*/\r
1467\r
1468uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin)\r
1469{\r
1470int32 i, s, rs, nc;\r
1471\r
1472if (s = sc * 4) {\r
1473 rs = 32 - s;\r
1474 for (i = DSTRMAX; i >= 0; i--) {\r
1475 nc = dsrc->val[i];\r
1476 dsrc->val[i] = ((dsrc->val[i] >> s) |\r
1477 (cin << rs)) & 0xFFFFFFFF;\r
1478 cin = nc;\r
1479 }\r
1480 return cin;\r
1481 }\r
1482return 0;\r
1483}\r
1484\r
1485/* Nibble shift decimal string left\r
1486\r
1487 Arguments:\r
1488 dsrc = decimal string structure\r
1489 sc = shift count\r
1490*/\r
1491\r
1492uint32 NibbleLshift (DSTR *dsrc, int32 sc)\r
1493{\r
1494int32 i, s, rs;\r
1495uint32 sv_val, cout;\r
1496\r
1497cout = 0;\r
1498if (s = sc * 4) {\r
1499 rs = 32 - s;\r
1500 for (i = 0; i < DSTRLNT; i++) {\r
1501 sv_val = dsrc->val[i];\r
1502 dsrc->val[i] = ((dsrc->val[i] << s) | cout) & 0xFFFFFFFF;\r
1503 cout = sv_val >> rs;\r
1504 }\r
1505 return cout;\r
1506 }\r
1507return 0;\r
1508}\r
1509\r
1510/* Common setup routine for MOVC class instructions */\r
1511\r
1512int32 movx_setup (int32 op, int32 *arg)\r
1513{\r
1514int32 mvlnt, t;\r
1515\r
1516if (CPUT (CPUT_44)) { /* 11/44? */\r
1517 ReadMB (((SP - 0200) & 0177777) | dsenable); /* probe both blocks */\r
1518 ReadMB (((SP - 0100) & 0177777) | dsenable); /* in 64W stack area */\r
1519 }\r
1520if (op & INLINE) { /* inline */\r
1521 mvlnt = (A1LNT < A2LNT)? A1LNT: A2LNT;\r
1522 WriteW (mvlnt, ((SP - 14) & 0177777) | dsenable); /* push move length */\r
1523 WriteW (R[0], ((SP - 12) & 0177777) | dsenable); /* push R0 - R5 */\r
1524 WriteW (R[1], ((SP - 10) & 0177777) | dsenable);\r
1525 WriteW (R[2], ((SP - 8) & 0177777) | dsenable);\r
1526 WriteW (R[3], ((SP - 6) & 0177777) | dsenable);\r
1527 WriteW (R[4], ((SP - 4) & 0177777) | dsenable);\r
1528 WriteW (R[5], ((SP - 2) & 0177777) | dsenable);\r
1529 SP = (SP - 14) & 0177777;\r
1530 R[0] = A1LNT; /* args to registers */\r
1531 R[1] = A1ADR;\r
1532 R[2] = A2LNT;\r
1533 R[3] = A2ADR;\r
1534 R[4] = A3LNT;\r
1535 R[5] = A3ADR & 0177777;\r
1536 }\r
1537else { /* register */\r
1538 mvlnt = (R[0] < R[2])? R[0]: R[2];\r
1539 WriteW (mvlnt, ((SP - 2) & 0177777) | dsenable); /* push move length */\r
1540 SP = (SP - 2) & 0177777;\r
1541 }\r
1542fpd = 1;\r
1543t = R[0] - R[2]; /* src.lnt - dst.lnt */\r
1544N = GET_SIGN_W (t); /* set cc's from diff */\r
1545Z = GET_Z (t);\r
1546V = GET_SIGN_W ((R[0] ^ R[2]) & (~R[2] ^ t));\r
1547C = (R[0] < R[2]);\r
1548return mvlnt;\r
1549}\r
1550\r
1551/* Common cleanup routine for MOVC class instructions */\r
1552\r
1553void movx_cleanup (int32 op)\r
1554{\r
1555SP = (SP + 2) & 0177777; /* discard mvlnt */\r
1556if (op & INLINE) { /* inline? */\r
1557 R[0] = ReadW (SP | dsenable); /* restore R0 - R5 */\r
1558 R[1] = ReadW (((SP + 2) & 0177777) | dsenable);\r
1559 R[2] = ReadW (((SP + 4) & 0177777) | dsenable);\r
1560 R[3] = ReadW (((SP + 6) & 0177777) | dsenable);\r
1561 R[4] = ReadW (((SP + 8) & 0177777) | dsenable);\r
1562 R[5] = ReadW (((SP + 10) & 0177777) | dsenable);\r
1563 SP = (SP + 12) & 0177777;\r
1564 }\r
1565else R[1] = R[2] = R[3] = 0; /* reg, clear R1 - R3 */\r
1566fpd = 0; /* instr done */\r
1567return;\r
1568}\r
1569 \r
1570/* Test for CIS mid-instruction interrupt */\r
1571\r
1572t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st)\r
1573{\r
1574while (cycles >= 0) { /* until delay done */\r
1575 if (sim_interval > cycles) { /* event > delay */\r
1576 sim_interval = sim_interval - cycles;\r
1577 break;\r
1578 }\r
1579 else { /* event <= delay */\r
1580 cycles = cycles - sim_interval; /* decr delay */\r
1581 sim_interval = 0; /* process event */\r
1582 *st = sim_process_event ();\r
1583 trap_req = calc_ints (ipl, trap_req); /* recalc int req */\r
1584 if ((*st != SCPE_OK) || /* bad status or */\r
1585 trap_req & TRAP_INT) { /* interrupt? */\r
1586 PC = oldpc; /* back out */\r
1587 return TRUE;\r
1588 } /* end if stop */\r
1589 } /* end else event */\r
1590 } /* end while delay */\r
1591return FALSE;\r
1592}\r