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