First Commit of my working state
[simh.git] / SDS / sds_sys.c
1 /* sds_sys.c: SDS 940 simulator interface
2
3 Copyright (c) 2001-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 "sds_defs.h"
28 #include <ctype.h>
29 #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
30
31 extern DEVICE cpu_dev;
32 extern DEVICE chan_dev;
33 extern DEVICE ptr_dev;
34 extern DEVICE ptp_dev;
35 extern DEVICE tti_dev;
36 extern DEVICE tto_dev;
37 extern DEVICE lpt_dev;
38 extern DEVICE rtc_dev;
39 extern DEVICE drm_dev;
40 extern DEVICE rad_dev;
41 extern DEVICE dsk_dev;
42 extern DEVICE mt_dev;
43 extern DEVICE mux_dev, muxl_dev;
44 extern UNIT cpu_unit;
45 extern REG cpu_reg[];
46 extern uint32 M[MAXMEMSIZE];
47
48 /* SCP data structures and interface routines
49
50 sim_name simulator name string
51 sim_PC pointer to saved PC register descriptor
52 sim_emax number of words for examine
53 sim_devices array of pointers to simulated devices
54 sim_stop_messages array of pointers to stop messages
55 sim_load binary loader
56 */
57
58 char sim_name[] = "SDS 940";
59
60 REG *sim_PC = &cpu_reg[0];
61
62 int32 sim_emax = 1;
63
64 DEVICE *sim_devices[] = {
65 &cpu_dev,
66 &chan_dev,
67 &ptr_dev,
68 &ptp_dev,
69 &tti_dev,
70 &tto_dev,
71 &lpt_dev,
72 &rtc_dev,
73 &drm_dev,
74 &rad_dev,
75 &dsk_dev,
76 &mt_dev,
77 &mux_dev,
78 &muxl_dev,
79 NULL
80 };
81
82 const char *sim_stop_messages[] = {
83 "Unknown error",
84 "IO device not ready",
85 "HALT instruction",
86 "Breakpoint",
87 "Invalid IO device",
88 "Invalid instruction",
89 "Invalid I/O operation",
90 "Nested indirects exceed limit",
91 "Nested EXU's exceed limit",
92 "Memory management trap during interrupt",
93 "Memory management trap during trap",
94 "Trap instruction not BRM",
95 "RTC instruction not MIN or SKR",
96 "Interrupt vector zero",
97 "Runaway carriage control tape"
98 };
99
100 /* Character conversion tables */
101
102 const char sds_to_ascii[64] = {
103 '0', '1', '2', '3', '4', '5', '6', '7',
104 '8', '9', ' ', '=', '\'', ':', '>', '%', /* 17 = check mark */
105 '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
106 'H', 'I', '?', '.', ')', '[', '<', '@', /* 37 = stop code */
107 '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
108 'Q', 'R', '!', '$', '*', ']', ';', '^', /* 57 = triangle */
109 '_', '/', 'S', 'T', 'U', 'V', 'W', 'X',
110 'Y', 'Z', '?', ',', '(', '~', '\\', '#' /* 72 = rec mark */
111 }; /* 75 = squiggle, 77 = del */
112
113 const char ascii_to_sds[128] = {
114 -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 37 */
115 032, 072, -1, -1, -1, 052, -1, -1,
116 -1, -1, -1, -1, -1, -1, -1, -1,
117 -1, -1, -1, -1, -1, -1, -1, -1,
118 012, 052, -1, 077, 053, 017, -1, 014, /* 40 - 77 */
119 074, 034, 054, 020, 073, 040, 033, 061,
120 000, 001, 002, 003, 004, 005, 006, 007,
121 010, 011, 015, 056, 036, 013, 016, 072,
122 037, 021, 022, 023, 024, 025, 026, 027, /* 100 - 137 */
123 030, 031, 041, 042, 043, 044, 045, 046,
124 047, 050, 051, 062, 063, 064, 065, 066,
125 067, 070, 071, 035, 076, 055, 057, 060,
126 000, 021, 022, 023, 024, 025, 026, 027, /* 140 - 177 */
127 030, 031, 041, 042, 043, 044, 045, 046,
128 047, 050, 051, 062, 063, 064, 065, 066,
129 067, 070, 071, -1, -1, -1, -1, -1
130 };
131
132 const char odd_par[64] = {
133 0100, 0001, 0002, 0103, 0004, 0105, 0106, 0007,
134 0010, 0111, 0112, 0013, 0114, 0015, 0016, 0117,
135 0020, 0121, 0122, 0023, 0124, 0025, 0026, 0127,
136 0130, 0031, 0032, 0133, 0034, 0135, 0136, 0037,
137 0040, 0141, 0142, 0043, 0144, 0045, 0046, 0147,
138 0150, 0051, 0052, 0153, 0054, 0155, 0156, 0057,
139 0160, 0061, 0062, 0163, 0064, 0165, 0166, 0067,
140 0070, 0171, 0172, 0073, 0174, 0075, 0076, 0177
141 };
142
143 /* Load carriage control tape
144
145 A carriage control tape consists of entries of the form
146
147 (repeat count) column number,column number,column number,...
148
149 The CCT entries are stored in lpt_cct[0:lnt-1], lpt_ccl contains the
150 number of entries
151 */
152
153 t_stat sim_load_cct (FILE *fileref)
154 {
155 int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];
156 t_stat r;
157 extern int32 lpt_ccl, lpt_ccp, lpt_cct[CCT_LNT];
158 char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE];
159
160 ptr = 0;
161 for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
162 mask = 0;
163 if (*cptr == '(') { /* repeat count? */
164 cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
165 rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
166 if (r != SCPE_OK) return SCPE_FMT;
167 }
168 else rpt = 1;
169 while (*cptr != 0) { /* get col no's */
170 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
171 col = get_uint (gbuf, 10, 7, &r); /* column number */
172 if (r != SCPE_OK) return SCPE_FMT;
173 mask = mask | (1 << col); /* set bit */
174 }
175 for ( ; rpt > 0; rpt--) { /* store vals */
176 if (ptr >= CCT_LNT) return SCPE_FMT;
177 cctbuf[ptr++] = mask;
178 }
179 }
180 if (ptr == 0) return SCPE_FMT;
181 lpt_ccl = ptr;
182 lpt_ccp = 0;
183 for (rpt = 0; rpt < lpt_ccl; rpt++) lpt_cct[rpt] = cctbuf[rpt];
184 return SCPE_OK;
185 }
186
187 /* Load command. -l means load a line printer tape. Otherwise, load
188 a bootstrap paper tape.
189 */
190
191 int32 get_word (FILE *fileref, int32 *ldr)
192 {
193 int32 i, c, wd;
194
195 for (i = wd = 0; i < 4; ) {
196 if ((c = fgetc (fileref)) == EOF) return -1;
197 if ((c == 0) && (*ldr == 0)) return -1;
198 if (c == 0) continue;
199 *ldr = 0;
200 wd = (wd << 6) | (c & 077);
201 i++;
202 }
203 return wd;
204 }
205
206 t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
207 {
208 int32 i, wd, buf[8];
209 int32 ldr = 1;
210 extern int32 sim_switches;
211 extern uint32 P;
212
213 if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
214 if (sim_switches & SWMASK ('L')) return sim_load_cct (fileref);
215 for (i = 0; i < 8; i++) { /* read boot */
216 if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_FMT;
217 buf[i] = wd;
218 }
219 if ((buf[0] != 023200012) || /* 2 = WIM 12,2 */
220 (buf[1] != 004100002) || /* 3 = BRX 2 */
221 (buf[2] != 007100011) || /* 4 = LDX 11 */
222 (buf[3] != 023200000) || /* 5 = WIM 0,2 */
223 (buf[4] != 004021000) || /* 6 = SKS 21000 */
224 (buf[5] != 004100005)) return SCPE_FMT; /* 7 = BRX 5 */
225 for (i = 0; i < 8; i++) M[i + 2] = buf[i]; /* copy boot */
226 if (I_GETOP (buf[6]) == BRU) P = buf[6] & VA_MASK;
227 for (i = buf[7] & VA_MASK; i <= VA_MASK; i++) { /* load data */
228 if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_OK;
229 M[i] = wd;
230 }
231 return SCPE_NXM;
232 }
233
234 /* Symbol tables */
235
236 #define I_V_FL 24 /* inst class */
237 #define I_M_FL 017 /* class mask */
238 #define I_V_NPN 000 /* no operand */
239 #define I_V_PPO 001 /* POP */
240 #define I_V_IOI 002 /* IO */
241 #define I_V_MRF 003 /* memory reference */
242 #define I_V_REG 004 /* register change */
243 #define I_V_SHF 005 /* shift */
244 #define I_V_OPO 006 /* opcode only */
245 #define I_V_CHC 007 /* chan cmd */
246 #define I_V_CHT 010 /* chan test */
247 #define I_NPN (I_V_NPN << I_V_FL)
248 #define I_PPO (I_V_PPO << I_V_FL)
249 #define I_IOI (I_V_IOI << I_V_FL)
250 #define I_MRF (I_V_MRF << I_V_FL)
251 #define I_REG (I_V_REG << I_V_FL)
252 #define I_SHF (I_V_SHF << I_V_FL)
253 #define I_OPO (I_V_OPO << I_V_FL)
254 #define I_CHC (I_V_CHC << I_V_FL)
255 #define I_CHT (I_V_CHT << I_V_FL)
256
257 static const int32 masks[] = {
258 037777777, 010000000, 017700000,
259 017740000, 017700000, 017774000,
260 017700000, 017377677, 027737677
261 };
262
263 static const char *opcode[] = {
264 "POP", "EIR", "DIR",
265 "ROV", "REO", "OTO", "OVT",
266 "IDT", "IET",
267 "BPT4", "BPT3", "BPT2", "BPT1",
268 "CLAB", "ABC", "BAC", "XAB",
269 "XXB", "STE", "LDE", "XEE",
270 "CLEAR",
271
272 "HLT", "BRU", "EOM", "EOD",
273 "MIY", "BRI", "MIW", "POT",
274 "ETR", "MRG", "EOR",
275 "NOP", "EXU",
276 "YIM", "WIM", "PIN",
277 "STA", "STB", "STX",
278 "SKS", "BRX", "BRM",
279 "SKE", "BRR", "SKB", "SKN",
280 "SUB", "ADD", "SUC", "ADC",
281 "SKR", "MIN", "XMA", "ADM",
282 "MUL", "DIV",
283 "SKM", "LDX", "SKA", "SKG",
284 "SKD", "LDB", "LDA", "EAX",
285
286 "BRU*",
287 "MIY*", "BRI*", "MIW*", "POT*",
288 "ETR*", "MRG*", "EOR*",
289 "EXU*",
290 "YIM*", "WIM*", "PIN*",
291 "STA*", "STB*", "STX*",
292 "BRX*", "BRM*",
293 "SKE*", "BRR*", "SKB*", "SKN*",
294 "SUB*", "ADD*", "SUC*", "ADC*",
295 "SKR*", "MIN*", "XMA*", "ADM*",
296 "MUL*", "DIV*",
297 "SKM*", "LDX*", "SKA*", "SKG*",
298 "SKD*", "LDB*", "LDA*", "EAX*",
299
300 "RSH", "RCY", "LRSH",
301 "LSH", "NOD", "LCY",
302 "RSH*", "LSH*",
303
304 "ALC", "DSC", "ASC", "TOP",
305 "CAT", "CET", "CZT", "CIT",
306
307 "CLA", "CLB", "CAB", /* encode only */
308 "CBA", "CBX", "CXB",
309 "XPO", "CXA", "CAX",
310 "CNA", "CLX", NULL,
311 NULL
312 };
313
314 static const int32 opc_val[] = {
315 010000000+I_PPO, 000220002+I_NPN, 000220004+I_NPN,
316 002200001+I_NPN, 002200010+I_NPN, 002200100+I_NPN, 002200101+I_NPN,
317 004020002+I_NPN, 004020004+I_NPN,
318 004020040+I_NPN, 004020100+I_NPN, 004020200+I_NPN, 004020400+I_NPN,
319 004600003+I_NPN, 004600005+I_NPN, 004600012+I_NPN, 004600014+I_NPN,
320 004600060+I_NPN, 004600122+I_NPN, 004600140+I_NPN, 004600160+I_NPN,
321 024600003+I_NPN,
322
323 000000000+I_NPN, 000100000+I_MRF, 000200000+I_IOI, 000600000+I_IOI,
324 001000000+I_MRF, 001100000+I_MRF, 001200000+I_MRF, 001300000+I_MRF,
325 001400000+I_MRF, 001600000+I_MRF, 001700000+I_MRF,
326 002000000+I_OPO, 002300000+I_MRF,
327 003000000+I_MRF, 003200000+I_MRF, 003300000+I_MRF,
328 003500000+I_MRF, 003600000+I_MRF, 003700000+I_MRF,
329 004000000+I_IOI, 004100000+I_MRF, 004300000+I_MRF,
330 005000000+I_MRF, 005100000+I_MRF, 005200000+I_MRF, 005300000+I_MRF,
331 005400000+I_MRF, 005500000+I_MRF, 005600000+I_MRF, 005700000+I_MRF,
332 006000000+I_MRF, 006100000+I_MRF, 006200000+I_MRF, 006300000+I_MRF,
333 006400000+I_MRF, 006500000+I_MRF,
334 007000000+I_MRF, 007100000+I_MRF, 007200000+I_MRF, 007300000+I_MRF,
335 007400000+I_MRF, 007500000+I_MRF, 007600000+I_MRF, 007700000+I_MRF,
336
337 000140000+I_MRF,
338 001040000+I_MRF, 001140000+I_MRF, 001240000+I_MRF, 001340000+I_MRF,
339 001440000+I_MRF, 001640000+I_MRF, 001740000+I_MRF,
340 002340000+I_MRF,
341 003040000+I_MRF, 003240000+I_MRF, 003340000+I_MRF,
342 003540000+I_MRF, 003640000+I_MRF, 003740000+I_MRF,
343 004140000+I_MRF, 004340000+I_MRF,
344 005040000+I_MRF, 005140000+I_MRF, 005240000+I_MRF, 005340000+I_MRF,
345 005440000+I_MRF, 005540000+I_MRF, 005640000+I_MRF, 005740000+I_MRF,
346 006040000+I_MRF, 006140000+I_MRF, 006240000+I_MRF, 006340000+I_MRF,
347 006440000+I_MRF, 006540000+I_MRF,
348 007040000+I_MRF, 007140000+I_MRF, 007240000+I_MRF, 007340000+I_MRF,
349 007440000+I_MRF, 007540000+I_MRF, 007640000+I_MRF, 007740000+I_MRF,
350
351 006600000+I_SHF, 006620000+I_SHF, 006624000+I_SHF,
352 006700000+I_SHF, 006710000+I_SHF, 006720000+I_SHF,
353 006640000+I_MRF, 006740000+I_MRF,
354
355 000250000+I_CHC, 000200000+I_CHC, 000212000+I_CHC, 000214000+I_CHC,
356 004014000+I_CHT, 004011000+I_CHT, 004012000+I_CHT, 004010400+I_CHT,
357
358 004600001+I_REG, 004600002+I_REG, 004600004+I_REG,
359 004600010+I_REG, 004600020+I_REG, 004600040+I_REG,
360 004600100+I_REG, 004600200+I_REG, 004600400+I_REG,
361 004601000+I_REG, 024600000+I_REG, 004600000+I_REG,
362 -1
363 };
364
365 static const char *chname[] = {
366 "W", "Y", "C", "D", "E", "F", "G", "H", NULL
367 };
368
369 /* Register change decode
370
371 Inputs:
372 *of = output stream
373 inst = mask bits
374 */
375
376 void fprint_reg (FILE *of, int32 inst)
377 {
378 int32 i, j, sp;
379
380 inst = inst & ~(I_M_OP << I_V_OP); /* clear opcode */
381 for (i = sp = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
382 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
383 if ((j == I_V_REG) && (opc_val[i] & inst)) { /* reg class? */
384 inst = inst & ~opc_val[i]; /* mask bit set? */
385 fprintf (of, (sp? " %s": "%s"), opcode[i]);
386 sp = 1;
387 }
388 }
389 return;
390 }
391
392 /* Symbolic decode
393
394 Inputs:
395 *of = output stream
396 addr = current PC
397 *val = pointer to values
398 *uptr = pointer to unit
399 sw = switches
400 Outputs:
401 return = status code
402 */
403
404 t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
405 UNIT *uptr, int32 sw)
406 {
407 int32 i, j, ch;
408 int32 inst, op, tag, va, shf, nonop;
409
410 inst = val[0]; /* get inst */
411 op = I_GETOP (inst); /* get fields */
412 tag = (inst >> 21) & 06;
413 va = inst & VA_MASK;
414 shf = inst & I_SHFMSK;
415 nonop = inst & 077777;
416
417 if (sw & SWMASK ('A')) { /* ASCII? */
418 if (inst > 0377) return SCPE_ARG;
419 fprintf (of, FMTASC (inst & 0177));
420 return SCPE_OK;
421 }
422 if (sw & SWMASK ('C')) { /* character? */
423 fprintf (of, "%c", sds_to_ascii[(inst >> 18) & 077]);
424 fprintf (of, "%c", sds_to_ascii[(inst >> 12) & 077]);
425 fprintf (of, "%c", sds_to_ascii[(inst >> 6) & 077]);
426 fprintf (of, "%c", sds_to_ascii[inst & 077]);
427 return SCPE_OK;
428 }
429 if (!(sw & SWMASK ('M'))) return SCPE_ARG;
430
431 /* Instruction decode */
432
433 for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
434 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
435 if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */
436
437 switch (j) { /* case on class */
438
439 case I_V_NPN: /* no operands */
440 case I_V_OPO: /* opcode only */
441 fprintf (of, "%s", opcode[i]); /* opcode */
442 break;
443
444 case I_V_SHF: /* shift */
445 fprintf (of, "%s %-o", opcode[i], shf);
446 if (tag) fprintf (of, ",%-o", tag);
447 break;
448
449 case I_V_PPO: /* pop */
450 fprintf (of, "POP %-o,%-o", op, nonop);
451 if (tag) fprintf (of, ",%-o", tag);
452 break;
453
454 case I_V_IOI: /* I/O */
455 fprintf (of, "%s %-o", opcode[i], nonop);
456 if (tag) fprintf (of, ",%-o", tag);
457 break;
458
459 case I_V_MRF: /* mem ref */
460 fprintf (of, "%s %-o", opcode[i], va);
461 if (tag) fprintf (of, ",%-o", tag);
462 break;
463
464 case I_V_REG: /* reg change */
465 fprint_reg (of, inst); /* decode */
466 break;
467
468 case I_V_CHC: /* chan cmd */
469 ch = I_GETEOCH (inst); /* get chan */
470 fprintf (of, "%s %s", opcode[i], chname[ch]);
471 break;
472
473 case I_V_CHT: /* chan test */
474 ch = I_GETSKCH (inst); /* get chan */
475 fprintf (of, "%s %s", opcode[i], chname[ch]);
476 break;
477 } /* end case */
478
479 return SCPE_OK;
480 } /* end if */
481 } /* end for */
482 return SCPE_ARG;
483 }
484
485 /* Get (optional) tag
486
487 Inputs:
488 *cptr = pointer to input string
489 *tag = pointer to tag
490 Outputs:
491 cptr = updated pointer to input string
492 */
493
494 char *get_tag (char *cptr, t_value *tag)
495 {
496 char *tptr, gbuf[CBUFSIZE];
497 t_stat r;
498
499 tptr = get_glyph (cptr, gbuf, 0); /* get next field */
500 *tag = get_uint (gbuf, 8, 07, &r) << I_V_TAG; /* parse */
501 if (r == SCPE_OK) return tptr; /* ok? advance */
502 *tag = 0;
503 return cptr; /* no change */
504 }
505
506 /* Symbolic input
507
508 Inputs:
509 *cptr = pointer to input string
510 addr = current PC
511 uptr = pointer to unit
512 *val = pointer to output values
513 sw = switches
514 Outputs:
515 status = error status
516 */
517
518 t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
519 {
520 int32 i, j, k;
521 t_value d, tag;
522 t_stat r;
523 char gbuf[CBUFSIZE];
524
525 while (isspace (*cptr)) cptr++;
526 for (i = 1; (i < 4) && (cptr[i] != 0); i++)
527 if (cptr[i] == 0) for (j = i + 1; j <= 4; j++) cptr[j] = 0;
528 if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
529 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
530 val[0] = (t_value) cptr[0] | 0200;
531 return SCPE_OK;
532 }
533 if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string? */
534 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
535 for (i = j = 0, val[0] = 0; i < 4; i++) {
536 if (cptr[i] == 0) j = 1; /* latch str end */
537 k = ascii_to_sds[cptr[i] & 0177]; /* cvt char */
538 if (j || (k < 0)) k = 0; /* bad, end? spc */
539 val[0] = (val[0] << 6) | k;
540 }
541 return SCPE_OK;
542 }
543
544 cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
545 for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
546 if (opcode[i] == NULL) return SCPE_ARG;
547 val[0] = opc_val[i] & DMASK; /* get value */
548 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
549
550 switch (j) { /* case on class */
551
552 case I_V_NPN: case I_V_OPO: /* opcode only */
553 break;
554
555 case I_V_SHF: /* shift */
556 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
557 d = get_uint (gbuf, 8, I_SHFMSK, &r); /* shift count */
558 if (r != SCPE_OK) return SCPE_ARG;
559 cptr = get_tag (cptr, &tag); /* get opt tag */
560 val[0] = val[0] | d | tag;
561 break;
562
563 case I_V_PPO: /* pop */
564 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
565 d = get_uint (gbuf, 8, 077, &r); /* opcode */
566 if (r != SCPE_OK) return SCPE_ARG;
567 val[0] = val[0] | d; /* fall thru */
568
569 case I_V_IOI: /* I/O */
570 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
571 d = get_uint (gbuf, 8, 077777, &r); /* 15b address */
572 if (r != SCPE_OK) return SCPE_ARG;
573 cptr = get_tag (cptr, &tag); /* get opt tag */
574 val[0] = val[0] | d | tag;
575 break;
576
577 case I_V_MRF: /* mem ref */
578 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
579 d = get_uint (gbuf, 8, VA_MASK, &r); /* virt address */
580 if (r != SCPE_OK) return SCPE_ARG;
581 cptr = get_tag (cptr, &tag); /* get opt tag */
582 val[0] = val[0] | d | tag;
583 break;
584
585 case I_V_REG: /* register */
586 for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
587 cptr = get_glyph (cptr, gbuf, 0)) {
588 for (i = 0; (opcode[i] != NULL) &&
589 (strcmp (opcode[i], gbuf) != 0); i++) ;
590 if (opcode[i] != NULL) {
591 k = opc_val[i] & DMASK;;
592 if (I_GETOP (k) != RCH) return SCPE_ARG;
593 val[0] = val[0] | k;
594 }
595 else {
596 d = get_uint (gbuf, 8, 077777, &r);
597 if (r != SCPE_OK) return SCPE_ARG;
598 else val[0] = val[0] | d;
599 }
600 }
601 break;
602
603 case I_V_CHC: case I_V_CHT: /* channel */
604 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
605 for (i = 0; (chname[i] != NULL) && (strcmp (chname[i], gbuf) != 0);
606 i++);
607 if (chname[i] != NULL) d = i; /* named chan */
608 else {
609 d = get_uint (gbuf, 8, NUM_CHAN - 1, &r);
610 if (r != SCPE_OK) return SCPE_ARG; /* numbered chan */
611 }
612 val[0] = val[0] | ((j == I_V_CHC)? I_SETEOCH (d): I_SETSKCH (d));
613 break;
614 } /* end case */
615
616 if (*cptr != 0) return SCPE_ARG; /* junk at end? */
617 return SCPE_OK;
618 }