First Commit of my working state
[simh.git] / I1620 / i1620_sys.c
1 /* i1620_sys.c: IBM 1620 simulator interface
2
3 Copyright (c) 2002-2005, Robert M. Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25 */
26
27 #include "i1620_defs.h"
28 #include <ctype.h>
29
30 #define LINE_LNT 50
31
32 extern DEVICE cpu_dev, tty_dev;
33 extern DEVICE ptr_dev, ptp_dev;
34 extern DEVICE lpt_dev;
35 extern DEVICE cdr_dev, cdp_dev;
36 extern DEVICE dp_dev;
37 extern UNIT cpu_unit;
38 extern REG cpu_reg[];
39 extern uint8 M[MAXMEMSIZE];
40 extern char cdr_to_alp[128], alp_to_cdp[256];
41
42 /* SCP data structures and interface routines
43
44 sim_name simulator name string
45 sim_PC pointer to saved PC register descriptor
46 sim_emax maximum number of words for examine/deposit
47 sim_devices array of pointers to simulated devices
48 sim_stop_messages array of pointers to stop messages
49 sim_load binary loader
50 */
51
52 char sim_name[] = "IBM 1620";
53
54 REG *sim_PC = &cpu_reg[0];
55
56 int32 sim_emax = LINE_LNT;
57
58 DEVICE *sim_devices[] = {
59 &cpu_dev,
60 &tty_dev,
61 &ptr_dev,
62 &ptp_dev,
63 &cdr_dev,
64 &cdp_dev,
65 &lpt_dev,
66 &dp_dev,
67 NULL
68 };
69
70 const char *sim_stop_messages[] = {
71 "Unknown error",
72 "HALT instruction",
73 "Breakpoint",
74 "Invalid instruction",
75 "Invalid digit",
76 "Invalid character",
77 "Invalid indicator",
78 "Invalid digit in P address",
79 "Invalid P address",
80 "P address exceeds indirect address limit",
81 "Invalid digit in Q address",
82 "Invalid Q address",
83 "Q address exceeds indirect address limit",
84 "Invalid IO device",
85 "Invalid return register",
86 "Invalid IO function",
87 "Instruction address must be even",
88 "Invalid select code",
89 "Index instruction with no band selected",
90 "P address must be odd",
91 "DCF address must be even",
92 "Invalid disk drive",
93 "Invalid disk sector address",
94 "Invalid disk sector count",
95 "Invalid disk buffer address",
96 "Disk address compare error",
97 "Disk write check error",
98 "Disk cylinder overflow error",
99 "Disk wrong length record error",
100 "Invalid CCT",
101 "Field exceeds memory",
102 "Record exceeds memory",
103 "No card in reader",
104 "Overflow check",
105 "Exponent check",
106 "Write address function disabled",
107 "Floating point mantissa too long",
108 "Floating point mantissa lengths unequal",
109 "Floating point exponent flag missing",
110 "Floating point divide by zero"
111 };
112
113 /* Binary loader -- load carriage control tape
114
115 A carriage control tape consists of entries of the form
116
117 (repeat count) column number,column number,column number,...
118
119 The CCT entries are stored in cct[0:lnt-1], cctlnt contains the
120 number of entries
121 */
122
123 t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
124 {
125 int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];
126 t_stat r;
127 extern int32 cct_lnt, cct_ptr, cct[CCT_LNT];
128 char cbuf[CBUFSIZE], gbuf[CBUFSIZE];
129
130 if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
131 ptr = 0;
132 for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
133 mask = 0;
134 if (*cptr == '(') { /* repeat count? */
135 cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
136 rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
137 if (r != SCPE_OK) return SCPE_FMT;
138 }
139 else rpt = 1;
140 while (*cptr != 0) { /* get col no's */
141 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
142 col = get_uint (gbuf, 10, 12, &r); /* column number */
143 if (r != SCPE_OK) return SCPE_FMT;
144 mask = mask | (1 << col); /* set bit */
145 }
146 for ( ; rpt > 0; rpt--) { /* store vals */
147 if (ptr >= CCT_LNT) return SCPE_FMT;
148 cctbuf[ptr++] = mask;
149 }
150 }
151 if (ptr == 0) return SCPE_FMT;
152 cct_lnt = ptr;
153 cct_ptr = 0;
154 for (rpt = 0; rpt < cct_lnt; rpt++) cct[rpt] = cctbuf[rpt];
155 return SCPE_OK;
156 }
157
158 /* Symbol table */
159
160 struct opc {
161 char *str; /* mnemonic */
162 uint32 opv; /* opcode & flags */
163 uint32 qv; /* q field */
164 };
165
166 #define I_V_FL 16 /* flags */
167 #define I_M_QX 0x01 /* Q indexable */
168 #define I_M_QM 0x02 /* Q immediate */
169 #define I_M_QNP 0x00 /* Q no print */
170 #define I_M_QCP 0x04 /* Q cond print */
171 #define I_M_QP 0x08 /* Q print */
172 #define I_M_PCP 0x00 /* P cond print */
173 #define I_M_PP 0x10 /* P print */
174 #define I_GETQF(x) (((x) >> I_V_FL) & 0x03)
175 #define I_GETQP(x) (((x) >> I_V_FL) & 0x0C)
176 #define I_GETPP(x) (((x) >> I_V_FL) & 0x10)
177
178 #define I_2 ((I_M_PP | I_M_QP | I_M_QX) << I_V_FL)
179 #define I_2M ((I_M_PP | I_M_QP | I_M_QM) << I_V_FL)
180 #define I_2X ((I_M_PP | I_M_QP | I_M_QX | I_M_QM) << I_V_FL)
181 #define I_2S ((I_M_PP | I_M_QP) << I_V_FL)
182 #define I_1 ((I_M_PP | I_M_QCP) << I_V_FL)
183 #define I_1E ((I_M_PP | I_M_QNP) << I_V_FL)
184 #define I_0 ((I_M_PCP | I_M_QCP) << I_V_FL)
185 #define I_0E ((I_M_PCP | I_M_QNP) << I_V_FL)
186
187 struct opc opcode[] = {
188 { "RNTY", 36+I_1E, 100 }, { "RATY", 37+I_1E, 100 },
189 { "WNTY", 38+I_1E, 100 }, { "WATY", 39+I_1E, 100 },
190 { "DNTY", 35+I_1E, 100 }, { "SPTY", 34+I_0E, 101 },
191 { "RCTY", 34+I_0E, 102 }, { "BKTY", 34+I_0E, 103 },
192 { "IXTY", 34+I_0E, 104 }, { "TBTY", 34+I_0E, 108 },
193 { "RNPT", 36+I_1E, 300 }, { "RAPT", 37+I_1E, 300 },
194 { "WNPT", 38+I_1E, 200 }, { "WAPT", 39+I_1E, 200 },
195 { "DNPT", 35+I_1E, 200 },
196 { "RNCD", 36+I_1E, 500 }, { "RACD", 37+I_1E, 500 },
197 { "WNCD", 38+I_1E, 400 }, { "WACD", 39+I_1E, 400 },
198 { "DNCD", 35+I_1E, 400 },
199 { "PRN", 38+I_1E, 900 }, { "PRNS", 38+I_1E, 901 },
200 { "PRA", 39+I_1E, 900 }, { "PRAS", 39+I_1E, 901 },
201 { "PRD", 35+I_1E, 900 }, { "PRDS", 35+I_1E, 901 },
202 { "SK", 34+I_1E, 701 },
203 { "RDGN", 36+I_1E, 700 }, { "CDGN", 36+I_1E, 701 },
204 { "RDN", 36+I_1E, 702 }, { "CDN", 36+I_1E, 703 },
205 { "RTGN", 36+I_1E, 704 }, { "CTGN", 36+I_1E, 705 },
206 { "RTN", 36+I_1E, 706 }, { "CTN", 36+I_1E, 707 },
207 { "WDGN", 38+I_1E, 700 }, { "WDN", 38+I_1E, 702 },
208 { "WTGN", 38+I_1E, 704 }, { "WTN", 38+I_1E, 706 },
209 { "RBPT", 37+I_1E, 3300 }, { "WBPT", 39+I_1E, 3200 },
210 { "BC1", 46+I_1E, 100 }, { "BNC1", 47+I_1E, 100 },
211 { "BC2", 46+I_1E, 200 }, { "BNC2", 47+I_1E, 200 },
212 { "BC3", 46+I_1E, 300 }, { "BNC3", 47+I_1E, 300 },
213 { "BC4", 46+I_1E, 400 }, { "BNC4", 47+I_1E, 400 },
214 { "BLC", 46+I_1E, 900 }, { "BNLC", 47+I_1E, 900 },
215 { "BH", 46+I_1E, 1100 }, { "BNH", 47+I_1E, 1100 },
216 { "BP", 46+I_1E, 1100 }, { "BNP", 47+I_1E, 1100 },
217 { "BE", 46+I_1E, 1200 }, { "BNE", 47+I_1E, 1200 },
218 { "BZ", 46+I_1E, 1200 }, { "BNZ", 47+I_1E, 1200 },
219 { "BNL", 46+I_1E, 1300 }, { "BL", 47+I_1E, 1300 },
220 { "BNN", 46+I_1E, 1300 }, { "BN", 47+I_1E, 1300 },
221 { "BV", 46+I_1E, 1400 }, { "BNV", 47+I_1E, 1400 },
222 { "BXV", 46+I_1E, 1500 }, { "BNXV", 47+I_1E, 1500 },
223 { "BA", 46+I_1E, 1900 }, { "BNA", 47+I_1E, 1900 },
224 { "BNBS", 46+I_1E, 3000 }, { "BEBS", 47+I_1E, 3000 },
225 { "BBAS", 46+I_1E, 3100 }, { "BANS", 47+I_1E, 3100 },
226 { "BBBS", 46+I_1E, 3200 }, { "BBNS", 47+I_1E, 3200 },
227 { "BCH9", 46+I_1E, 3300 },
228 { "BCOV", 46+I_1E, 3400 },
229 { "BSNX", 60+I_1E, 0 }, { "BSBA", 60+I_1E, 1 },
230 { "BSBB", 60+I_1E, 2 },
231 { "BSNI", 60+I_1E, 8 }, { "BSIA", 60+I_1E, 9 },
232
233 { "FADD", 1+I_2, 0 }, { "FSUB", 2+I_2, 0 },
234 { "FMUL", 3+I_2, 0 }, { "FSL", 5+I_2, 0 },
235 { "TFL", 6+I_2, 0 }, { "BTFL", 7+I_2, 0 },
236 { "FSR", 8+I_2, 0 }, { "FDIV", 9+I_2, 0 },
237 { "BTAM", 10+I_2M, 0 }, { "AM", 11+I_2M, 0 },
238 { "SM", 12+I_2M, 0 }, { "MM", 13+I_2M, 0 },
239 { "CM", 14+I_2M, 0 }, { "TDM", 15+I_2S, 0 },
240 { "TFM", 16+I_2M, 0 }, { "BTM", 17+I_2M, 0 },
241 { "LDM", 18+I_2M, 0 }, { "DM", 19+I_2M, 0 },
242 { "BTA", 20+I_2, 0 }, { "A", 21+I_2, 0 },
243 { "S", 22+I_2, 0 }, { "M", 23+I_2, 0 },
244 { "C", 24+I_2, 0 }, { "TD", 25+I_2, 0 },
245 { "TF", 26+I_2, 0 }, { "BT", 27+I_2, 0 },
246 { "LD", 28+I_2, 0 }, { "D", 29+I_2, 0 },
247 { "TRNM", 30+I_2, 0 }, { "TR", 31+I_2, 0 },
248 { "SF", 32+I_1, 0 }, { "CF", 33+I_1, 0 },
249 { "K", 34+I_2S, 0 }, { "DN", 35+I_2S, 0 },
250 { "RN", 36+I_2S, 0 }, { "RA", 37+I_2S, 0 },
251 { "WN", 38+I_2S, 0 }, { "WA", 39+I_2S, 0 },
252 { "NOP", 41+I_0, 0 }, { "BB", 42+I_0, 0 },
253 { "BD", 43+I_2, 0 }, { "BNF", 44+I_2, 0 },
254 { "BNR", 45+I_2, 0 }, { "BI", 46+I_2S, 0 },
255 { "BNI", 47+I_2S, 0 }, { "H", 48+I_0, 0 },
256 { "B", 49+I_1, 0 }, { "BNG", 55+I_2, 0 },
257 { "BS", 60+I_2S, 0 }, { "BX", 61+I_2, 0 },
258 { "BXM", 62+I_2X, 0 }, { "BCX", 63+I_2, 0 },
259 { "BCXM", 64+I_2X, 0 }, { "BLX", 65+I_2, 0 },
260 { "BLXM", 66+I_2X, 0 }, { "BSX", 67+I_2, 0 },
261 { "MA", 70+I_2, 0 }, { "MF", 71+I_2, 0 },
262 { "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 },
263 { "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 },
264 { "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 },
265 { "CPFL", 94+I_2, 0 }, { "EORF", 95+I_2, 0 },
266 { "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 },
267 { NULL, 0, 0 }
268 };
269
270 /* Print an address from five characters */
271
272 void fprint_addr (FILE *of, int32 spc, t_value *dig, t_bool flg)
273 {
274 int32 i, idx;
275
276 fputc (spc, of); /* spacer */
277 if (dig[ADDR_LEN - 1] & FLAG) { /* signed? */
278 fputc ('-', of); /* print minus */
279 dig[ADDR_LEN - 1] = dig[ADDR_LEN - 1] & ~FLAG;
280 }
281 for (i = 0; i < ADDR_LEN; i++) /* print digits */
282 fprintf (of, "%X", dig[i] & DIGIT);
283 if ((cpu_unit.flags & IF_IDX) && flg) { /* indexing? */
284 for (i = idx = 0; i < ADDR_LEN - 2; i++) { /* get index reg */
285 if (dig[ADDR_LEN - 2 - i] & FLAG)
286 idx = idx | (1 << i);
287 dig[ADDR_LEN - 2 - i] = dig[ADDR_LEN - 2 - i] & ~FLAG;
288 }
289 if (idx) fprintf (of, "(%d)", idx); /* print */
290 }
291 return;
292 }
293
294 /* Symbolic decode
295
296 Inputs:
297 *of = output stream
298 addr = current address
299 *val = values to decode
300 *uptr = pointer to unit
301 sw = switches
302 Outputs:
303 return = if >= 0, error code
304 if < 0, number of extra words retired
305 */
306
307 #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
308
309 t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
310 UNIT *uptr, int32 sw)
311 {
312 int32 pmp, qmp, i, c, d, any;
313 uint32 op, qv, opfl;
314
315 if (uptr == NULL) uptr = &cpu_unit;
316 if (sw & SWMASK ('C')) { /* character? */
317 if (uptr->flags & UNIT_BCD) {
318 if (addr & 1) return SCPE_ARG; /* must be even */
319 c = ((val[0] & DIGIT) << 4) | (val[1] & DIGIT);
320 if (alp_to_cdp[c] > 0)
321 fprintf (of, "%c", alp_to_cdp[c]);
322 else fprintf (of, "<%02x>", c);
323 return -1;
324 }
325 else fprintf (of, FMTASC (val[0] & 0177));
326 return SCPE_OK;
327 }
328 if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */
329 if (sw & SWMASK ('D')) { /* dump? */
330 for (i = d = 0; i < LINE_LNT; i++) d = d | val[i];
331 if (d & FLAG) { /* any flags? */
332 for (i = 0; i < LINE_LNT; i++) /* print flags */
333 fprintf (of, (val[i] & FLAG)? "_": " ");
334 fprintf (of, "\n\t");
335 }
336 for (i = 0; i < LINE_LNT; i++) /* print digits */
337 fprintf (of, "%X", val[i] & DIGIT) ;
338 return -(i - 1);
339 }
340 if (sw & SWMASK ('S')) { /* string? */
341 if (addr & 1) return SCPE_ARG; /* must be even */
342 for (i = 0; i < LINE_LNT; i = i + 2) {
343 c = ((val[i] & DIGIT) << 4) | (val[i + 1] & DIGIT);
344 if (alp_to_cdp[c] < 0) break;
345 fprintf (of, "%c", alp_to_cdp[c]);
346 }
347 if (i == 0) {
348 fprintf (of, "<%02X>", c);
349 return -1;
350 }
351 return -(i - 1);
352 }
353 if ((sw & SWMASK ('M')) == 0) return SCPE_ARG;
354
355 if (addr & 1) return SCPE_ARG; /* must be even */
356 op = ((val[0] & DIGIT) * 10) + (val[1] & DIGIT); /* get opcode */
357 for (i = qv = pmp = qmp = 0; i < ADDR_LEN; i++) { /* test addr */
358 if (val[I_P + i]) pmp = 1;
359 if (val[I_Q + i]) qmp = 1;
360 qv = (qv * 10) + (val[I_Q + i] & DIGIT);
361 }
362 if ((val[0] | val[1]) & FLAG) pmp = qmp = 1; /* flags force */
363 for (i = 0; opcode[i].str != NULL; i++) { /* find opcode */
364 opfl = opcode[i].opv & 0xFF0000;
365 if ((op == (opcode[i].opv & 0xFF)) &&
366 ((qv == opcode[i].qv) ||
367 ((opfl != I_1E) && (opfl != I_0E)))) break;
368 }
369 if (opcode[i].str == NULL) return SCPE_ARG;
370 if (I_GETQP (opfl) == I_M_QNP) qmp = 0; /* Q no print? */
371
372 fprintf (of, opcode[i].str); /* print opcode */
373 if (I_GETPP (opfl) == I_M_PP) /* P required? */
374 fprint_addr (of, ' ', &val[I_P], I_M_QX);
375 else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */
376 fprint_addr (of, ' ', &val[I_P], 0);
377 if (I_GETQP (opfl) == I_M_QP) { /* Q required? */
378 fprint_addr (of, ',', &val[I_Q], I_GETQF (opfl));
379 if (I_GETQF (opfl) & I_M_QM) /* immediate? */
380 val[I_Q] = val[I_Q] & ~FLAG; /* clr hi Q flag */
381 }
382 else if ((I_GETQP (opfl) == I_M_QCP) && (pmp || qmp)) /* Q opt & needed? */
383 fprint_addr (of, ',', &val[I_Q], 0);
384 for (i = any = 0; i < INST_LEN; i++) { /* print rem flags */
385 if (val[i] & FLAG) {
386 if (!any) fputc (',', of);
387 any = 1;
388 fprintf (of, "%d", i);
389 }
390 }
391 return -(INST_LEN - 1);
392 }
393
394 /* parse_addr - get sign + address + index */
395
396 t_stat parse_addr (char *cptr, t_value *val, int32 flg)
397 {
398 int32 i, sign = 0, addr, index;
399 static int32 idx_tst[ADDR_LEN] = { 0, 4, 2, 1, 0 };
400 char *tptr;
401
402 if (*cptr == '+') cptr++; /* +? skip */
403 else if (*cptr == '-') { /* -? skip, flag */
404 sign = 1;
405 cptr++;
406 }
407 errno = 0; /* get address */
408 addr = strtoul (cptr, &tptr, 16);
409 if (errno || (cptr == tptr) || (addr > 0xFFFFF)) /* err or too big? */
410 return SCPE_ARG;
411 if ((cpu_unit.flags & IF_IDX) && (flg & I_M_QX) && /* index allowed? */
412 (*tptr == '(')) { /* index specified */
413 errno = 0;
414 index = strtoul (cptr = tptr + 1, &tptr, 10); /* get index */
415 if (errno || (cptr == tptr) || (index > 7)) /* err or too big? */
416 return SCPE_ARG;
417 if (*tptr++ != ')') return SCPE_ARG;
418 }
419 else index = 0;
420 if (*tptr != 0) return SCPE_ARG; /* all done? */
421 for (i = ADDR_LEN - 1; i >= 0; i--) { /* cvt addr to dig */
422 val[i] = (addr & 0xF) | ((index & idx_tst[i])? FLAG: 0);
423 addr = addr >> 4;
424 }
425 if (sign) val[ADDR_LEN - 1] = val[ADDR_LEN - 1] | FLAG; /* set sign */
426 if (flg & I_M_QM) val[0] = val[0] | FLAG; /* set immediate */
427 return SCPE_OK;
428 }
429
430 /* Symbolic input
431
432 Inputs:
433 *cptr = pointer to input string
434 addr = current PC
435 *uptr = pointer to unit
436 *val = pointer to output values
437 sw = switches
438 Outputs:
439 status = > 0 error code
440 <= 0 -number of extra words
441 */
442
443 t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
444 {
445 int32 i, qv, opfl, last;
446 char t, la, *fptr, gbuf[CBUFSIZE];
447
448 while (isspace (*cptr)) cptr++; /* absorb spaces */
449 if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */
450 if ((t = *cptr & 0x7F) == 0) return SCPE_ARG; /* get char */
451 if (uptr->flags & UNIT_BCD) { /* BCD? */
452 if (addr & 1) return SCPE_ARG;
453 t = cdr_to_alp[t]; /* convert */
454 if (t < 0) return SCPE_ARG; /* invalid? */
455 val[0] = (t >> 4) & DIGIT; /* store */
456 val[1] = t & DIGIT;
457 return -1;
458 }
459 else val[0] = t; /* store ASCII */
460 return SCPE_OK;
461 }
462
463 if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */
464 if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* string? */
465 if (addr & 1) return SCPE_ARG; /* must be even */
466 for (i = 0; (i < sim_emax) && (*cptr != 0); i = i + 2) {
467 t = *cptr++ & 0x7F; /* get character */
468 t = cdr_to_alp[t]; /* convert */
469 if (t < 0) return SCPE_ARG; /* invalid? */
470 val[i] = (t >> 4) & DIGIT; /* store */
471 val[i + 1] = t & DIGIT;
472 }
473 if (i == 0) return SCPE_ARG; /* final check */
474 return -(i - 1);
475 }
476
477 if (addr & 1) return SCPE_ARG; /* even addr? */
478 cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
479 for (i = 0; opcode[i].str != NULL; i++) { /* look it up */
480 if (strcmp (gbuf, opcode[i].str) == 0) break;
481 }
482 if (opcode[i].str == NULL) return SCPE_ARG; /* successful? */
483 opfl = opcode[i].opv & 0xFF0000; /* get flags */
484 val[0] = (opcode[i].opv & 0xFF) / 10; /* store opcode */
485 val[1] = (opcode[i].opv & 0xFF) % 10;
486 qv = opcode[i].qv;
487 for (i = ADDR_LEN - 1; i >= 0; i--) { /* set P,Q fields */
488 val[I_P + i] = 0;
489 val[I_Q + i] = qv % 10;
490 qv = qv /10;
491 }
492
493 cptr = get_glyph (cptr, gbuf, ','); /* get P field */
494 if (gbuf[0]) { /* any? */
495 if (parse_addr (gbuf, &val[I_P], (I_GETPP (opfl)?
496 I_M_QX: 0))) return SCPE_ARG;
497 }
498 else if (I_GETPP (opfl) == I_M_PP) return SCPE_ARG;
499
500 if (I_GETQP (opfl) != I_M_QNP) { /* Q field allowed? */
501 cptr = get_glyph (cptr, gbuf, ','); /* get Q field */
502 if (gbuf[0]) { /* any? */
503 if (parse_addr (gbuf, &val[I_Q], I_GETQF (opfl)))
504 return SCPE_ARG;
505 }
506 else if (I_GETQP (opfl) == I_M_QP) return SCPE_ARG;
507 }
508
509 cptr = get_glyph (cptr, fptr = gbuf, ' '); /* get flag field */
510 last = -1; /* none yet */
511 while (t = *fptr++) { /* loop through */
512 if ((t < '0') || (t > '9')) return SCPE_ARG; /* must be digit */
513 t = t - '0'; /* convert */
514 if (t == 1) { /* ambiguous? */
515 la = *fptr++; /* get next */
516 if (la == '0') t = 10; /* 10? */
517 else if ((la == '1') && (*fptr == 0)) t = 11; /* 11 & end field? */
518 else --fptr; /* dont lookahead */
519 }
520 if (t <= last) return SCPE_ARG; /* in order? */
521 val[t] = val[t] | FLAG; /* set flag */
522 last = t; /* continue */
523 }
524
525 if (*cptr != 0) return SCPE_ARG;
526 return -(INST_LEN - 1);
527 }