Commit | Line | Data |
---|---|---|
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 | |
166 | typedef struct {\r | |
167 | uint32 sign;\r | |
168 | uint32 val[DSTRLNT];\r | |
169 | } DSTR;\r | |
170 | \r | |
171 | static DSTR Dstr0 = { 0, 0, 0, 0, 0 };\r | |
172 | \r | |
173 | extern int32 isenable, dsenable;\r | |
174 | extern int32 N, Z, V, C, fpd, ipl;\r | |
175 | extern int32 R[8], trap_req;\r | |
176 | extern int32 sim_interval;\r | |
177 | extern uint32 cpu_type;\r | |
178 | extern FILE *sim_deb;\r | |
179 | \r | |
180 | int32 ReadDstr (int32 *dscr, DSTR *dec, int32 flag);\r | |
181 | void WriteDstr (int32 *dscr, DSTR *dec, int32 flag);\r | |
182 | int32 AddDstr (DSTR *src1, DSTR *src2, DSTR *dst, int32 cin);\r | |
183 | void SubDstr (DSTR *src1, DSTR *src2, DSTR *dst);\r | |
184 | int32 CmpDstr (DSTR *src1, DSTR *src2);\r | |
185 | int32 TestDstr (DSTR *dsrc);\r | |
186 | int32 LntDstr (DSTR *dsrc, int32 nz);\r | |
187 | uint32 NibbleLshift (DSTR *dsrc, int32 sc);\r | |
188 | uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin);\r | |
189 | int32 WordLshift (DSTR *dsrc, int32 sc);\r | |
190 | void WordRshift (DSTR *dsrc, int32 sc);\r | |
191 | void CreateTable (DSTR *dsrc, DSTR mtable[10]);\r | |
192 | t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st);\r | |
193 | int32 movx_setup (int32 op, int32 *arg);\r | |
194 | void movx_cleanup (int32 op);\r | |
195 | \r | |
196 | extern int32 ReadW (int32 addr);\r | |
197 | extern void WriteW (int32 data, int32 addr);\r | |
198 | extern int32 ReadB (int32 addr);\r | |
199 | extern int32 ReadMB (int32 addr);\r | |
200 | extern void WriteB (int32 data, int32 addr);\r | |
201 | extern int32 calc_ints (int32 nipl, int32 trq);\r | |
202 | \r | |
203 | /* Table of instruction operands */\r | |
204 | \r | |
205 | static 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 | |
300 | static 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 | |
321 | static 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 | |
328 | static unsigned char movbuf[65536];\r | |
329 | \r | |
330 | /* CIS emulator */\r | |
331 | \r | |
332 | t_stat cis11 (int32 IR)\r | |
333 | {\r | |
334 | int32 c, i, j, t, op, rn, addr;\r | |
335 | int32 match, limit, mvlnt, shift;\r | |
336 | int32 spc, ldivd, ldivr;\r | |
337 | int32 arg[6]; /* operands */\r | |
338 | int32 old_PC;\r | |
339 | uint32 nc, digit, result;\r | |
340 | t_stat st;\r | |
341 | static DSTR accum, src1, src2, dst;\r | |
342 | static DSTR mptable[10];\r | |
343 | static DSTR Dstr1 = { 0, 0x10, 0, 0, 0 };\r | |
344 | \r | |
345 | old_PC = (PC - 2) & 0177777; /* original PC */\r | |
346 | op = IR & 0177; /* IR <6:0> */\r | |
347 | for (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 | |
385 | switch (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 | |
1122 | return 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 | |
1149 | int32 ReadDstr (int32 *dscr, DSTR *src, int32 flag)\r | |
1150 | {\r | |
1151 | int32 c, i, end, lnt, type, t;\r | |
1152 | \r | |
1153 | *src = Dstr0; /* clear result */\r | |
1154 | type = GET_DTYP (dscr[0]); /* get type */\r | |
1155 | lnt = GET_DLNT (dscr[0]); /* get string length */\r | |
1156 | if (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 | |
1169 | else { /* 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 | |
1186 | return 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 | |
1212 | void WriteDstr (int32 *dscr, DSTR *dst, int32 flag)\r | |
1213 | {\r | |
1214 | int32 c, i, limit, end, type, lnt;\r | |
1215 | uint32 mask;\r | |
1216 | static uint32 masktab[8] = {\r | |
1217 | 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,\r | |
1218 | 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000\r | |
1219 | };\r | |
1220 | static int32 unsignedtab[8] = { 0, 1, 0, 0, 0, 0, 0, 1 };\r | |
1221 | \r | |
1222 | type = GET_DTYP (dscr[0]); /* get type */\r | |
1223 | lnt = GET_DLNT (dscr[0]); /* get string length */\r | |
1224 | mask = 0; /* can't ovflo */\r | |
1225 | Z = 1; /* assume all 0's */\r | |
1226 | limit = lnt / 8; /* limit for test */\r | |
1227 | for (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 | |
1233 | dst->sign = dst->sign & ~unsignedtab[type] & ~(Z & ~V);\r | |
1234 | N = dst->sign & ~Z; /* N = sign, if ~zero */\r | |
1235 | \r | |
1236 | if (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 | |
1245 | else {\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 | |
1259 | return;\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 | |
1303 | int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy)\r | |
1304 | {\r | |
1305 | int32 i;\r | |
1306 | uint32 sm1, sm2, tm1, tm2, tm3, tm4;\r | |
1307 | \r | |
1308 | for (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 | |
1318 | return 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 | |
1333 | void SubDstr (DSTR *s1, DSTR *s2, DSTR *ds)\r | |
1334 | {\r | |
1335 | int32 i;\r | |
1336 | DSTR compl;\r | |
1337 | \r | |
1338 | for (i = 0; i < DSTRLNT; i++) compl.val[i] = 0x99999999 - s1->val[i];\r | |
1339 | AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */\r | |
1340 | return;\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 | |
1351 | int32 CmpDstr (DSTR *s1, DSTR *s2)\r | |
1352 | {\r | |
1353 | int32 i;\r | |
1354 | \r | |
1355 | for (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 | |
1359 | return 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 | |
1371 | int32 TestDstr (DSTR *dsrc)\r | |
1372 | {\r | |
1373 | int32 i;\r | |
1374 | \r | |
1375 | for (i = DSTRMAX; i >= 0; i--) if (dsrc->val[i]) return (i + 1);\r | |
1376 | dsrc->sign = 0;\r | |
1377 | return 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 | |
1387 | int32 LntDstr (DSTR *dsrc, int32 nz)\r | |
1388 | {\r | |
1389 | int32 i;\r | |
1390 | \r | |
1391 | if (nz == 0) return 0;\r | |
1392 | for (i = 7; i > 0; i--) {\r | |
1393 | if ((dsrc->val[nz - 1] >> (i * 4)) & 0xF) break;\r | |
1394 | }\r | |
1395 | return ((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 | |
1409 | void CreateTable (DSTR *dsrc, DSTR mtable[10])\r | |
1410 | {\r | |
1411 | int32 (i);\r | |
1412 | \r | |
1413 | mtable[1] = *dsrc;\r | |
1414 | for (i = 2; i < 10; i++) AddDstr (&mtable[1], &mtable[i-1], &mtable[i], 0);\r | |
1415 | return;\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 | |
1425 | void WordRshift (DSTR *dsrc, int32 sc)\r | |
1426 | {\r | |
1427 | int32 i;\r | |
1428 | \r | |
1429 | if (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 | |
1435 | return;\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 | |
1445 | int32 WordLshift (DSTR *dsrc, int32 sc)\r | |
1446 | {\r | |
1447 | int32 i, c;\r | |
1448 | \r | |
1449 | c = 0;\r | |
1450 | if (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 | |
1457 | return 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 | |
1468 | uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin)\r | |
1469 | {\r | |
1470 | int32 i, s, rs, nc;\r | |
1471 | \r | |
1472 | if (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 | |
1482 | return 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 | |
1492 | uint32 NibbleLshift (DSTR *dsrc, int32 sc)\r | |
1493 | {\r | |
1494 | int32 i, s, rs;\r | |
1495 | uint32 sv_val, cout;\r | |
1496 | \r | |
1497 | cout = 0;\r | |
1498 | if (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 | |
1507 | return 0;\r | |
1508 | }\r | |
1509 | \r | |
1510 | /* Common setup routine for MOVC class instructions */\r | |
1511 | \r | |
1512 | int32 movx_setup (int32 op, int32 *arg)\r | |
1513 | {\r | |
1514 | int32 mvlnt, t;\r | |
1515 | \r | |
1516 | if (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 | |
1520 | if (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 | |
1537 | else { /* 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 | |
1542 | fpd = 1;\r | |
1543 | t = R[0] - R[2]; /* src.lnt - dst.lnt */\r | |
1544 | N = GET_SIGN_W (t); /* set cc's from diff */\r | |
1545 | Z = GET_Z (t);\r | |
1546 | V = GET_SIGN_W ((R[0] ^ R[2]) & (~R[2] ^ t));\r | |
1547 | C = (R[0] < R[2]);\r | |
1548 | return mvlnt;\r | |
1549 | }\r | |
1550 | \r | |
1551 | /* Common cleanup routine for MOVC class instructions */\r | |
1552 | \r | |
1553 | void movx_cleanup (int32 op)\r | |
1554 | {\r | |
1555 | SP = (SP + 2) & 0177777; /* discard mvlnt */\r | |
1556 | if (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 | |
1565 | else R[1] = R[2] = R[3] = 0; /* reg, clear R1 - R3 */\r | |
1566 | fpd = 0; /* instr done */\r | |
1567 | return;\r | |
1568 | }\r | |
1569 | \r | |
1570 | /* Test for CIS mid-instruction interrupt */\r | |
1571 | \r | |
1572 | t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st)\r | |
1573 | {\r | |
1574 | while (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 | |
1591 | return FALSE;\r | |
1592 | }\r |