1 /* i1620_sys.c: IBM 1620 simulator interface
3 Copyright (c) 2002-2005, Robert M. Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
27 #include "i1620_defs.h"
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
;
39 extern uint8 M
[MAXMEMSIZE
];
40 extern char cdr_to_alp
[128], alp_to_cdp
[256];
42 /* SCP data structures and interface routines
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
52 char sim_name
[] = "IBM 1620";
54 REG
*sim_PC
= &cpu_reg
[0];
56 int32 sim_emax
= LINE_LNT
;
58 DEVICE
*sim_devices
[] = {
70 const char *sim_stop_messages
[] = {
74 "Invalid instruction",
78 "Invalid digit in P address",
80 "P address exceeds indirect address limit",
81 "Invalid digit in Q address",
83 "Q address exceeds indirect address limit",
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",
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",
101 "Field exceeds memory",
102 "Record exceeds memory",
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"
113 /* Binary loader -- load carriage control tape
115 A carriage control tape consists of entries of the form
117 (repeat count) column number,column number,column number,...
119 The CCT entries are stored in cct[0:lnt-1], cctlnt contains the
123 t_stat
sim_load (FILE *fileref
, char *cptr
, char *fnam
, int flag
)
125 int32 col
, rpt
, ptr
, mask
, cctbuf
[CCT_LNT
];
127 extern int32 cct_lnt
, cct_ptr
, cct
[CCT_LNT
];
128 char cbuf
[CBUFSIZE
], gbuf
[CBUFSIZE
];
130 if ((*cptr
!= 0) || (flag
!= 0)) return SCPE_ARG
;
132 for ( ; (cptr
= fgets (cbuf
, CBUFSIZE
, fileref
)) != NULL
; ) { /* until eof */
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
;
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 */
146 for ( ; rpt
> 0; rpt
--) { /* store vals */
147 if (ptr
>= CCT_LNT
) return SCPE_FMT
;
148 cctbuf
[ptr
++] = mask
;
151 if (ptr
== 0) return SCPE_FMT
;
154 for (rpt
= 0; rpt
< cct_lnt
; rpt
++) cct
[rpt
] = cctbuf
[rpt
];
161 char *str
; /* mnemonic */
162 uint32 opv
; /* opcode & flags */
163 uint32 qv
; /* q field */
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)
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)
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 },
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 },
270 /* Print an address from five characters */
272 void fprint_addr (FILE *of
, int32 spc
, t_value
*dig
, t_bool flg
)
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
;
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
;
289 if (idx
) fprintf (of
, "(%d)", idx
); /* print */
298 addr = current address
299 *val = values to decode
300 *uptr = pointer to unit
303 return = if >= 0, error code
304 if < 0, number of extra words retired
307 #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
309 t_stat
fprint_sym (FILE *of
, t_addr addr
, t_value
*val
,
310 UNIT
*uptr
, int32 sw
)
312 int32 pmp
, qmp
, i
, c
, d
, any
;
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
);
325 else fprintf (of
, FMTASC (val
[0] & 0177));
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");
336 for (i
= 0; i
< LINE_LNT
; i
++) /* print digits */
337 fprintf (of
, "%X", val
[i
] & DIGIT
) ;
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
]);
348 fprintf (of
, "<%02X>", c
);
353 if ((sw
& SWMASK ('M')) == 0) return SCPE_ARG
;
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
);
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;
369 if (opcode
[i
].str
== NULL
) return SCPE_ARG
;
370 if (I_GETQP (opfl
) == I_M_QNP
) qmp
= 0; /* Q no print? */
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 */
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 */
386 if (!any
) fputc (',', of
);
388 fprintf (of
, "%d", i
);
391 return -(INST_LEN
- 1);
394 /* parse_addr - get sign + address + index */
396 t_stat
parse_addr (char *cptr
, t_value
*val
, int32 flg
)
398 int32 i
, sign
= 0, addr
, index
;
399 static int32 idx_tst
[ADDR_LEN
] = { 0, 4, 2, 1, 0 };
402 if (*cptr
== '+') cptr
++; /* +? skip */
403 else if (*cptr
== '-') { /* -? skip, flag */
407 errno
= 0; /* get address */
408 addr
= strtoul (cptr
, &tptr
, 16);
409 if (errno
|| (cptr
== tptr
) || (addr
> 0xFFFFF)) /* err or too big? */
411 if ((cpu_unit
.flags
& IF_IDX
) && (flg
& I_M_QX
) && /* index allowed? */
412 (*tptr
== '(')) { /* index specified */
414 index
= strtoul (cptr
= tptr
+ 1, &tptr
, 10); /* get index */
415 if (errno
|| (cptr
== tptr
) || (index
> 7)) /* err or too big? */
417 if (*tptr
++ != ')') return SCPE_ARG
;
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);
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 */
433 *cptr = pointer to input string
435 *uptr = pointer to unit
436 *val = pointer to output values
439 status = > 0 error code
440 <= 0 -number of extra words
443 t_stat
parse_sym (char *cptr
, t_addr addr
, UNIT
*uptr
, t_value
*val
, int32 sw
)
445 int32 i
, qv
, opfl
, last
;
446 char t
, la
, *fptr
, gbuf
[CBUFSIZE
];
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 */
459 else val
[0] = t
; /* store ASCII */
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
;
473 if (i
== 0) return SCPE_ARG
; /* final check */
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;
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;
487 for (i
= ADDR_LEN
- 1; i
>= 0; i
--) { /* set P,Q fields */
489 val
[I_Q
+ i
] = qv
% 10;
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
;
498 else if (I_GETPP (opfl
) == I_M_PP
) return SCPE_ARG
;
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
)))
506 else if (I_GETQP (opfl
) == I_M_QP
) return SCPE_ARG
;
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 */
520 if (t
<= last
) return SCPE_ARG
; /* in order? */
521 val
[t
] = val
[t
] | FLAG
; /* set flag */
522 last
= t
; /* continue */
525 if (*cptr
!= 0) return SCPE_ARG
;
526 return -(INST_LEN
- 1);