Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* gri_sys.c: GRI-909 simulator interface\r |
2 | \r | |
3 | Copyright (c) 2001-2008, 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 | 14-Jan-08 RMS Added GRI-99 support\r | |
27 | 18-Oct-02 RMS Fixed bug in symbolic decode (found by Hans Pufal)\r | |
28 | */\r | |
29 | \r | |
30 | #include "gri_defs.h"\r | |
31 | #include <ctype.h>\r | |
32 | \r | |
33 | extern DEVICE cpu_dev;\r | |
34 | extern UNIT cpu_unit;\r | |
35 | extern DEVICE tti_dev, tto_dev;\r | |
36 | extern DEVICE hsr_dev, hsp_dev;\r | |
37 | extern DEVICE rtc_dev;\r | |
38 | extern REG cpu_reg[];\r | |
39 | extern uint16 M[];\r | |
40 | extern int32 sim_switches;\r | |
41 | \r | |
42 | void fprint_addr (FILE *of, uint32 val, uint32 mod, uint32 dst);\r | |
43 | \r | |
44 | /* SCP data structures and interface routines\r | |
45 | \r | |
46 | sim_name simulator name string\r | |
47 | sim_PC pointer to saved PC register descriptor\r | |
48 | sim_emax maximum number of words for examine/deposit\r | |
49 | sim_devices array of pointers to simulated devices\r | |
50 | sim_stop_messages array of pointers to stop messages\r | |
51 | sim_load binary loader\r | |
52 | */\r | |
53 | \r | |
54 | char sim_name[] = "GRI-909";\r | |
55 | \r | |
56 | REG *sim_PC = &cpu_reg[0];\r | |
57 | \r | |
58 | int32 sim_emax = 2;\r | |
59 | \r | |
60 | DEVICE *sim_devices[] = {\r | |
61 | &cpu_dev,\r | |
62 | &tti_dev,\r | |
63 | &tto_dev,\r | |
64 | &hsr_dev,\r | |
65 | &hsp_dev,\r | |
66 | &rtc_dev,\r | |
67 | NULL\r | |
68 | };\r | |
69 | \r | |
70 | const char *sim_stop_messages[] = {\r | |
71 | "Unknown error",\r | |
72 | "Unimplemented unit",\r | |
73 | "HALT instruction",\r | |
74 | "Breakpoint",\r | |
75 | "Invalid interrupt request"\r | |
76 | };\r | |
77 | \r | |
78 | /* Binary loader\r | |
79 | \r | |
80 | Bootstrap loader format consists of blocks separated by zeroes. Each\r | |
81 | word in the block has three frames: a control frame (ignored) and two\r | |
82 | data frames. The user must specify the load address. Switch -c means\r | |
83 | continue and load all blocks until end of tape.\r | |
84 | */\r | |
85 | \r | |
86 | t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r | |
87 | {\r | |
88 | int32 c;\r | |
89 | uint32 org;\r | |
90 | t_stat r;\r | |
91 | char gbuf[CBUFSIZE];\r | |
92 | \r | |
93 | if (*cptr != 0) { /* more input? */\r | |
94 | cptr = get_glyph (cptr, gbuf, 0); /* get origin */\r | |
95 | org = get_uint (gbuf, 8, AMASK, &r);\r | |
96 | if (r != SCPE_OK) return r;\r | |
97 | if (*cptr != 0) return SCPE_ARG; /* no more */\r | |
98 | }\r | |
99 | else org = 0200; /* default 200 */\r | |
100 | \r | |
101 | for (;;) { /* until EOF */\r | |
102 | while ((c = getc (fileref)) == 0) ; /* skip starting 0's */\r | |
103 | if (c == EOF) break; /* EOF? done */\r | |
104 | for ( ; c != 0; ) { /* loop until ctl = 0 */\r | |
105 | /* ign ctrl frame */\r | |
106 | if ((c = getc (fileref)) == EOF) /* get high byte */\r | |
107 | return SCPE_FMT; /* EOF is error */\r | |
108 | if (!MEM_ADDR_OK (org)) return SCPE_NXM;\r | |
109 | M[org] = ((c & 0377) << 8); /* store high */\r | |
110 | if ((c = getc (fileref)) == EOF) /* get low byte */\r | |
111 | return SCPE_FMT; /* EOF is error */\r | |
112 | M[org] = M[org] | (c & 0377); /* store low */\r | |
113 | org = org + 1; /* incr origin */\r | |
114 | if ((c = getc (fileref)) == EOF) /* get ctrl frame */\r | |
115 | return SCPE_OK; /* EOF is ok */\r | |
116 | } /* end block for */\r | |
117 | if (!(sim_switches & SWMASK ('C'))) return SCPE_OK;\r | |
118 | } /* end tape for */\r | |
119 | return SCPE_OK;\r | |
120 | }\r | |
121 | \r | |
122 | /* Symbol tables */\r | |
123 | \r | |
124 | #define F_V_FL 16 /* class flag */\r | |
125 | #define F_M_FL 017\r | |
126 | #define F_V_FO 000 /* function out */\r | |
127 | #define F_V_FOI 001 /* FO, impl reg */\r | |
128 | #define F_V_SF 002 /* skip function */\r | |
129 | #define F_V_SFI 003 /* SF, impl reg */\r | |
130 | #define F_V_RR 004 /* reg reg */\r | |
131 | #define F_V_ZR 005 /* zero reg */\r | |
132 | #define F_V_RS 006 /* reg self */\r | |
133 | #define F_V_JC 010 /* jump cond */\r | |
134 | #define F_V_JU 011 /* jump uncond */\r | |
135 | #define F_V_RM 012 /* reg mem */\r | |
136 | #define F_V_ZM 013 /* zero mem */\r | |
137 | #define F_V_MR 014 /* mem reg */\r | |
138 | #define F_V_MS 015 /* mem self */\r | |
139 | #define F_2WD 010 /* 2 words */\r | |
140 | \r | |
141 | #define F_FO (F_V_FO << F_V_FL)\r | |
142 | #define F_FOI (F_V_FOI << F_V_FL)\r | |
143 | #define F_SF (F_V_SF << F_V_FL)\r | |
144 | #define F_SFI (F_V_SFI << F_V_FL)\r | |
145 | #define F_RR (F_V_RR << F_V_FL)\r | |
146 | #define F_ZR (F_V_ZR << F_V_FL)\r | |
147 | #define F_RS (F_V_RS << F_V_FL)\r | |
148 | #define F_JC (F_V_JC << F_V_FL)\r | |
149 | #define F_JU (F_V_JU << F_V_FL)\r | |
150 | #define F_RM (F_V_RM << F_V_FL)\r | |
151 | #define F_ZM (F_V_ZM << F_V_FL)\r | |
152 | #define F_MR (F_V_MR << F_V_FL)\r | |
153 | #define F_MS (F_V_MS << F_V_FL)\r | |
154 | \r | |
155 | struct fnc_op {\r | |
156 | uint32 inst; /* instr prot */\r | |
157 | uint32 imask; /* instr mask */\r | |
158 | uint32 oper; /* operator */\r | |
159 | uint32 omask; /* oper mask */\r | |
160 | };\r | |
161 | \r | |
162 | static const int32 masks[] = {\r | |
163 | 0176000, 0176077, 0000077, 0176077,\r | |
164 | 0000300, 0176300, 0000300, 0177777,\r | |
165 | 0000077, 0177777, 0000377, 0176377,\r | |
166 | 0176300, 0176377\r | |
167 | };\r | |
168 | \r | |
169 | /* Instruction mnemonics\r | |
170 | \r | |
171 | Order is critical, as some instructions are more precise versions of\r | |
172 | others. For example, JU must precede JC, otherwise, JU will be decoded\r | |
173 | as JC 0,ETZ,dst. There are some ambiguities, eg, what is 02-xxxx-06?\r | |
174 | Priority is as follows:\r | |
175 | \r | |
176 | FO (02-xxxx-rr)\r | |
177 | SF (rr-xxxx-02)\r | |
178 | MR (06-xxxx-rr)\r | |
179 | RM (rr-xxxx-06)\r | |
180 | JC (rr-xxxx-03)\r | |
181 | RR \r | |
182 | */\r | |
183 | \r | |
184 | static const char *opcode[] = {\r | |
185 | "FOM", "FOA", "FOI", "FO", /* FOx before FO */\r | |
186 | "SFM", "SFA", "SFI", "SF", /* SFx before SF */\r | |
187 | "ZM", "ZMD", "ZMI", "ZMID", /* ZM before RM */\r | |
188 | "MS", "MSD", "MSI", "MSID",\r | |
189 | "RM", "RMD", "RMI", "RMID",\r | |
190 | "MR", "MRD", "MRI", "MRID",\r | |
191 | "JO", "JOD", "JN", "JND", /* JU before JC */\r | |
192 | "JU", "JUD", "JC", "JCD",\r | |
193 | "ZR", "ZRC", "RR", "RRC", /* ZR before RR */\r | |
194 | "RS", "RSC",\r | |
195 | NULL\r | |
196 | };\r | |
197 | \r | |
198 | static const uint32 opc_val[] = {\r | |
199 | 0004000+F_FOI, 0004013+F_FOI, 0004004+F_FOI, 0004000+F_FO,\r | |
200 | 0000002+F_SFI, 0026002+F_SFI, 0010002+F_SFI, 0000002+F_SF,\r | |
201 | 0000006+F_ZM, 0000106+F_ZM, 0000206+F_ZM, 0000306+F_ZM,\r | |
202 | 0014006+F_MS, 0014106+F_MS, 0014206+F_MS, 0014306+F_MS,\r | |
203 | 0000006+F_RM, 0000106+F_RM, 0000206+F_RM, 0000306+F_RM,\r | |
204 | 0014000+F_MR, 0014100+F_MR, 0014200+F_MR, 0014300+F_MR,\r | |
205 | 0037003+F_JU, 0037103+F_JU, 0037203+F_JU, 0037303+F_JU,\r | |
206 | 0000403+F_JU, 0000503+F_JU, 0000003+F_JC, 0000103+F_JC,\r | |
207 | 0000000+F_ZR, 0000200+F_ZR, 0000000+F_RR, 0000200+F_RR,\r | |
208 | 0000000+F_RS, 0000200+F_RS\r | |
209 | };\r | |
210 | \r | |
211 | /* Unit mnemonics. All 64 units are decoded, most just to octal integers */\r | |
212 | \r | |
213 | static const char *unsrc[64] = {\r | |
214 | "0", "IR", "2", "TRP", "ISR", "MA", "MB", "SC", /* 00 - 07 */\r | |
215 | "SWR", "AX", "AY", "AO", "14", "15", "16", "MSR", /* 10 - 17 */\r | |
216 | "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */\r | |
217 | "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */\r | |
218 | "40", "41", "42", "43", "44", "45", "46", "47",\r | |
219 | "50", "51", "52", "53", "54", "CDR", "56", "CADR",\r | |
220 | "60", "61", "62", "63", "64", "65", "DWC", "DCA",\r | |
221 | "DISK", "LPR", "72", "73", "CAS", "RTC", "HSR", "TTI" /* 70 - 77 */\r | |
222 | };\r | |
223 | \r | |
224 | static const char *undst[64] = {\r | |
225 | "0", "IR", "2", "TRP", "ISR", "5", "MB", "SC", /* 00 - 07 */\r | |
226 | "SWR", "AX", "AY", "13", "EAO", "15", "16", "MSR", /* 10 - 17 */\r | |
227 | "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */\r | |
228 | "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */\r | |
229 | "40", "41", "42", "43", "44", "45", "46", "47",\r | |
230 | "50", "51", "52", "53", "54", "CDR", "56", "CADR",\r | |
231 | "60", "61", "62", "63", "64", "65", "DWC", "DCA",\r | |
232 | "DISK", "LPR", "72", "73", "CAS", "RTC", "HSP", "TTO" /* 70 - 77 */\r | |
233 | };\r | |
234 | \r | |
235 | /* Operators */\r | |
236 | \r | |
237 | static const char *opname[4] = {\r | |
238 | NULL, "P1", "L1", "R1"\r | |
239 | };\r | |
240 | \r | |
241 | /* Conditions */\r | |
242 | \r | |
243 | static const char *cdname[8] = {\r | |
244 | "NEVER", "ALWAYS", "ETZ", "NEZ", "LTZ", "GEZ", "LEZ", "GTZ"\r | |
245 | };\r | |
246 | \r | |
247 | /* Function out/sense function */\r | |
248 | \r | |
249 | static const char *fname[] = {\r | |
250 | "NOT", /* any SF */\r | |
251 | "POK", "LNK", "BOV", /* SFM */\r | |
252 | "SOV", "AOV", /* SFA */\r | |
253 | "IRDY", "ORDY", /* any SF */\r | |
254 | "CLL", "STL", "CML", "HLT", /* FOM */\r | |
255 | "ICF", "ICO", /* FOI */\r | |
256 | "ADD", "AND", "XOR", "OR", /* FOA */\r | |
257 | "INP", "IRDY", "ORDY", "STRT", /* any FO */\r | |
258 | NULL\r | |
259 | };\r | |
260 | \r | |
261 | static const struct fnc_op fop[] = {\r | |
262 | { 0000002, 0000077, 001, 001 }, /* NOT */\r | |
263 | { 0000002, 0176077, 010, 010 }, /* POK */\r | |
264 | { 0000002, 0176077, 004, 004 }, /* LNK */\r | |
265 | { 0000002, 0176077, 002, 002 }, /* BOV */\r | |
266 | { 0026002, 0176077, 004, 004 }, /* SOV */\r | |
267 | { 0026002, 0176077, 002, 002 }, /* AOV */\r | |
268 | { 0000002, 0000077, 010, 010 }, /* IRDY */\r | |
269 | { 0000002, 0000077, 002, 002 }, /* ORDY */\r | |
270 | { 0004000, 0176077, 001, 003 }, /* CLL */\r | |
271 | { 0004000, 0176077, 002, 003 }, /* STL */\r | |
272 | { 0004000, 0176077, 003, 003 }, /* CML */\r | |
273 | { 0004000, 0176077, 004, 004 }, /* HLT */\r | |
274 | { 0004004, 0176077, 001, 001 }, /* ICF */\r | |
275 | { 0004004, 0176077, 002, 002 }, /* ICO */\r | |
276 | { 0004013, 0176077, 000, 014 }, /* ADD */\r | |
277 | { 0004013, 0176077, 004, 014 }, /* AND */\r | |
278 | { 0004013, 0176077, 010, 014 }, /* XOR */\r | |
279 | { 0004013, 0176077, 014, 014 }, /* OR */\r | |
280 | { 0004000, 0176000, 011, 011 }, /* INP */\r | |
281 | { 0004000, 0176000, 010, 010 }, /* IRDY */\r | |
282 | { 0004000, 0176000, 002, 002 }, /* ORDY */\r | |
283 | { 0004000, 0176000, 001, 001 } /* STRT */\r | |
284 | };\r | |
285 | \r | |
286 | /* Print opcode field for FO, SF */\r | |
287 | \r | |
288 | void fprint_op (FILE *of, uint32 inst, uint32 op)\r | |
289 | {\r | |
290 | int32 i, nfirst;\r | |
291 | \r | |
292 | for (i = nfirst = 0; fname[i] != NULL; i++) {\r | |
293 | if (((inst & fop[i].imask) == fop[i].inst) &&\r | |
294 | ((op & fop[i].omask) == fop[i].oper)) {\r | |
295 | op = op & ~fop[i].omask;\r | |
296 | if (nfirst) fputc (' ', of);\r | |
297 | nfirst = 1;\r | |
298 | fprintf (of, "%s", fname[i]);\r | |
299 | }\r | |
300 | }\r | |
301 | if (op) fprintf (of, " %o", op);\r | |
302 | return;\r | |
303 | }\r | |
304 | \r | |
305 | /* Print address field with potential indexing */\r | |
306 | \r | |
307 | void fprint_addr (FILE *of, uint32 val, uint32 mode, uint32 dst)\r | |
308 | {\r | |
309 | if ((val & INDEX) &&\r | |
310 | ((dst == U_SC) || (mode != MEM_IMM)))\r | |
311 | fprintf (of, "#%o", val & AMASK);\r | |
312 | else fprintf (of, "%o", val);\r | |
313 | return;\r | |
314 | }\r | |
315 | \r | |
316 | /* Symbolic decode\r | |
317 | \r | |
318 | Inputs:\r | |
319 | *of = output stream\r | |
320 | addr = current PC\r | |
321 | *val = pointer to data\r | |
322 | *uptr = pointer to unit \r | |
323 | sw = switches\r | |
324 | Outputs:\r | |
325 | return = status code\r | |
326 | */\r | |
327 | \r | |
328 | #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)\r | |
329 | \r | |
330 | t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r | |
331 | UNIT *uptr, int32 sw)\r | |
332 | {\r | |
333 | int32 i, j;\r | |
334 | uint32 inst, src, dst, op, bop;\r | |
335 | \r | |
336 | inst = val[0];\r | |
337 | if (sw & SWMASK ('A')) { /* ASCII? */\r | |
338 | if (inst > 0377) return SCPE_ARG;\r | |
339 | fprintf (of, FMTASC (inst & 0177));\r | |
340 | return SCPE_OK;\r | |
341 | }\r | |
342 | if (sw & SWMASK ('C')) { /* characters? */\r | |
343 | fprintf (of, FMTASC ((inst >> 8) & 0177));\r | |
344 | fprintf (of, FMTASC (inst & 0177));\r | |
345 | return SCPE_OK;\r | |
346 | }\r | |
347 | if (!(sw & SWMASK ('M'))) return SCPE_ARG;\r | |
348 | \r | |
349 | /* Instruction decode */\r | |
350 | \r | |
351 | inst = val[0];\r | |
352 | src = I_GETSRC (inst); /* get fields */\r | |
353 | op = I_GETOP (inst);\r | |
354 | dst = I_GETDST (inst);\r | |
355 | bop = op >> 2; /* bus op */\r | |
356 | for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */\r | |
357 | j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */\r | |
358 | if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */\r | |
359 | \r | |
360 | switch (j) { /* case on class */\r | |
361 | \r | |
362 | case F_V_FO: /* func out */\r | |
363 | fprintf (of, "%s ", opcode[i]);\r | |
364 | fprint_op (of, inst, op);\r | |
365 | fprintf (of, ",%s", undst[dst]);\r | |
366 | break;\r | |
367 | \r | |
368 | case F_V_FOI: /* func out impl */\r | |
369 | fprintf (of, "%s ", opcode[i]);\r | |
370 | fprint_op (of, inst, op);\r | |
371 | break;\r | |
372 | \r | |
373 | case F_V_SF: /* skip func */\r | |
374 | fprintf (of, "%s %s,", opcode[i], unsrc[src]);\r | |
375 | fprint_op (of, inst, op);\r | |
376 | break;\r | |
377 | \r | |
378 | case F_V_SFI: /* skip func impl */\r | |
379 | fprintf (of, "%s ", opcode[i]);\r | |
380 | fprint_op (of, inst, op);\r | |
381 | break;\r | |
382 | \r | |
383 | case F_V_RR: /* reg reg */\r | |
384 | if (strcmp (unsrc[src], undst[dst]) == 0) {\r | |
385 | if (bop) fprintf (of, "%s %s,%s", opcode[i + 2],\r | |
386 | unsrc[src], opname[bop]);\r | |
387 | else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]);\r | |
388 | }\r | |
389 | else {\r | |
390 | if (bop) fprintf (of, "%s %s,%s,%s", opcode[i],\r | |
391 | unsrc[src], opname[bop], undst[dst]);\r | |
392 | else fprintf (of, "%s %s,%s", opcode[i],\r | |
393 | unsrc[src], undst[dst]);\r | |
394 | }\r | |
395 | break;\r | |
396 | \r | |
397 | case F_V_ZR: /* zero reg */\r | |
398 | if (bop) fprintf (of, "%s %s,%s", opcode[i],\r | |
399 | opname[bop], undst[dst]);\r | |
400 | else fprintf (of, "%s %s", opcode[i], undst[dst]);\r | |
401 | break;\r | |
402 | \r | |
403 | case F_V_JC: /* jump cond */\r | |
404 | fprintf (of, "%s %s,%s,",\r | |
405 | opcode[i], unsrc[src], cdname[op >> 1]);\r | |
406 | fprint_addr (of, val[1], 0, U_SC);\r | |
407 | break;\r | |
408 | \r | |
409 | case F_V_JU: /* jump uncond */\r | |
410 | fprintf (of, "%s ", opcode[i]);\r | |
411 | fprint_addr (of, val[1], 0, U_SC);\r | |
412 | break;\r | |
413 | \r | |
414 | case F_V_RM: /* reg mem */\r | |
415 | if (bop) fprintf (of, "%s %s,%s,",\r | |
416 | opcode[i], unsrc[src], opname[bop]);\r | |
417 | else fprintf (of, "%s %s,", opcode[i], unsrc[src]);\r | |
418 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r | |
419 | break;\r | |
420 | \r | |
421 | case F_V_ZM: /* zero mem */\r | |
422 | if (bop) fprintf (of, "%s %s,", opcode[i], opname[bop]);\r | |
423 | else fprintf (of, "%s ", opcode[i]);\r | |
424 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r | |
425 | break;\r | |
426 | \r | |
427 | case F_V_MR: /* mem reg */\r | |
428 | fprintf (of, "%s ", opcode[i]);\r | |
429 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r | |
430 | if (bop) fprintf (of, ",%s,%s", opname[bop], undst[dst]);\r | |
431 | else fprintf (of, ",%s", undst[dst]);\r | |
432 | break;\r | |
433 | \r | |
434 | case F_V_MS: /* mem self */\r | |
435 | fprintf (of, "%s ", opcode[i]);\r | |
436 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r | |
437 | if (bop) fprintf (of, ",%s", opname[bop]);\r | |
438 | break;\r | |
439 | } /* end case */\r | |
440 | \r | |
441 | return (j >= F_2WD)? -1: SCPE_OK;\r | |
442 | } /* end if */\r | |
443 | } /* end for */\r | |
444 | return SCPE_ARG;\r | |
445 | }\r | |
446 | \r | |
447 | /* Field parse routines\r | |
448 | \r | |
449 | get_fnc get function field\r | |
450 | get_ma get memory address\r | |
451 | get_sd get source or dest\r | |
452 | get_op get optional bus operator\r | |
453 | */\r | |
454 | \r | |
455 | char *get_fnc (char *cptr, t_value *val)\r | |
456 | {\r | |
457 | char gbuf[CBUFSIZE];\r | |
458 | int32 i;\r | |
459 | t_value d;\r | |
460 | t_stat r;\r | |
461 | uint32 inst = val[0];\r | |
462 | uint32 fncv = 0, fncm = 0;\r | |
463 | \r | |
464 | while (*cptr) {\r | |
465 | cptr = get_glyph (cptr, gbuf, 0); /* get glyph */\r | |
466 | d = get_uint (gbuf, 8, 017, &r); /* octal? */\r | |
467 | if (r == SCPE_OK) { /* ok? */\r | |
468 | if (d & fncm) return NULL; /* already filled? */\r | |
469 | fncv = fncv | d; /* save */\r | |
470 | fncm = fncm | d; /* field filled */\r | |
471 | }\r | |
472 | else { /* symbol? */\r | |
473 | for (i = 0; fname[i] != NULL; i++) { /* search table */\r | |
474 | if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */\r | |
475 | ((inst & fop[i].imask) == fop[i].inst)) {\r | |
476 | if (fop[i].oper & fncm) return NULL; /* already filled? */\r | |
477 | fncm = fncm | fop[i].omask;\r | |
478 | fncv = fncv | fop[i].oper;\r | |
479 | break;\r | |
480 | }\r | |
481 | }\r | |
482 | if (fname[i] == NULL) return NULL;\r | |
483 | } /* end else */\r | |
484 | } /* end while */\r | |
485 | val[0] = val[0] | (fncv << I_V_OP); /* store fnc */\r | |
486 | return cptr;\r | |
487 | }\r | |
488 | \r | |
489 | char *get_ma (char *cptr, t_value *val, char term)\r | |
490 | {\r | |
491 | char gbuf[CBUFSIZE];\r | |
492 | t_value d;\r | |
493 | t_stat r;\r | |
494 | \r | |
495 | cptr = get_glyph (cptr, gbuf, term); /* get glyph */\r | |
496 | if (gbuf[0] == '#') /* indexed? */\r | |
497 | d = get_uint (gbuf + 1, 8, AMASK, &r) | INDEX; /* [0, 77777] */\r | |
498 | else d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */\r | |
499 | if (r != SCPE_OK) return NULL;\r | |
500 | val[1] = d; /* second wd */\r | |
501 | return cptr;\r | |
502 | }\r | |
503 | \r | |
504 | char *get_sd (char *cptr, t_value *val, char term, t_bool src)\r | |
505 | {\r | |
506 | char gbuf[CBUFSIZE];\r | |
507 | int32 d;\r | |
508 | t_stat r;\r | |
509 | \r | |
510 | cptr = get_glyph (cptr, gbuf, term); /* get glyph */\r | |
511 | for (d = 0; d < 64; d++) { /* symbol match? */\r | |
512 | if ((strcmp (gbuf, unsrc[d]) == 0) ||\r | |
513 | (strcmp (gbuf, undst[d]) == 0)) break;\r | |
514 | }\r | |
515 | if (d >= 64) { /* no, [0,63]? */\r | |
516 | d = get_uint (gbuf, 8, 077, &r);\r | |
517 | if (r != SCPE_OK) return NULL;\r | |
518 | }\r | |
519 | val[0] = val[0] | (d << (src? I_V_SRC: I_V_DST)); /* or to inst */\r | |
520 | return cptr;\r | |
521 | }\r | |
522 | \r | |
523 | char *get_op (char *cptr, t_value *val, char term)\r | |
524 | {\r | |
525 | char gbuf[CBUFSIZE], *tptr;\r | |
526 | int32 i;\r | |
527 | \r | |
528 | tptr = get_glyph (cptr, gbuf, term); /* get glyph */\r | |
529 | for (i = 1; i < 4; i++) { /* symbol match? */\r | |
530 | if (strcmp (gbuf, opname[i]) == 0) {\r | |
531 | val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */\r | |
532 | return tptr;\r | |
533 | }\r | |
534 | }\r | |
535 | return cptr; /* original ptr */\r | |
536 | }\r | |
537 | \r | |
538 | /* Symbolic input\r | |
539 | \r | |
540 | Inputs:\r | |
541 | *cptr = pointer to input string\r | |
542 | addr = current PC\r | |
543 | *uptr = pointer to unit\r | |
544 | *val = pointer to output values\r | |
545 | sw = switches\r | |
546 | Outputs:\r | |
547 | status = error status\r | |
548 | */\r | |
549 | \r | |
550 | t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r | |
551 | {\r | |
552 | int32 i, j, k;\r | |
553 | char *tptr, gbuf[CBUFSIZE];\r | |
554 | \r | |
555 | while (isspace (*cptr)) cptr++; /* absorb spaces */\r | |
556 | if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */\r | |
557 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r | |
558 | val[0] = (t_value) cptr[0] & 0177;\r | |
559 | return SCPE_OK;\r | |
560 | }\r | |
561 | if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */\r | |
562 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r | |
563 | val[0] = (((t_value) cptr[0] & 0177) << 8) |\r | |
564 | ((t_value) cptr[1] & 0177);\r | |
565 | return SCPE_OK;\r | |
566 | }\r | |
567 | \r | |
568 | /* Instruction parse */\r | |
569 | \r | |
570 | cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r | |
571 | for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r | |
572 | if (opcode[i] == NULL) return SCPE_ARG;\r | |
573 | val[0] = opc_val[i] & DMASK; /* get value */\r | |
574 | j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */\r | |
575 | \r | |
576 | switch (j) { /* case on class */\r | |
577 | \r | |
578 | case F_V_FO: /* func out */\r | |
579 | tptr = strchr (cptr, ','); /* find dst */\r | |
580 | if (!tptr) return SCPE_ARG; /* none? */\r | |
581 | *tptr = 0; /* split fields */\r | |
582 | cptr = get_fnc (cptr, val); /* fo # */\r | |
583 | if (!cptr) return SCPE_ARG;\r | |
584 | cptr = get_sd (tptr + 1, val, 0, FALSE); /* dst */\r | |
585 | break;\r | |
586 | \r | |
587 | case F_V_FOI: /* func out impl */\r | |
588 | cptr = get_fnc (cptr, val); /* fo # */\r | |
589 | break;\r | |
590 | \r | |
591 | case F_V_SF: /* skip func */\r | |
592 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r | |
593 | if (!cptr) return SCPE_ARG;\r | |
594 | \r | |
595 | case F_V_SFI: /* skip func impl */\r | |
596 | cptr = get_fnc (cptr, val); /* fo # */\r | |
597 | break;\r | |
598 | \r | |
599 | case F_V_RR: /* reg-reg */\r | |
600 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r | |
601 | if (!cptr) return SCPE_ARG;\r | |
602 | cptr = get_op (cptr, val, ','); /* op */\r | |
603 | if (!cptr) return SCPE_ARG;\r | |
604 | cptr = get_sd (cptr, val, 0, FALSE); /* dst */\r | |
605 | break;\r | |
606 | \r | |
607 | case F_V_ZR: /* zero-reg */\r | |
608 | cptr = get_op (cptr, val, ','); /* op */\r | |
609 | if (!cptr) return SCPE_ARG;\r | |
610 | cptr = get_sd (cptr, val, 0, FALSE); /* dst */\r | |
611 | break;\r | |
612 | \r | |
613 | case F_V_RS: /* reg self */\r | |
614 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r | |
615 | if (!cptr) return SCPE_ARG;\r | |
616 | val[0] = val[0] | I_GETSRC (val[0]); /* duplicate */\r | |
617 | cptr = get_op (cptr, val, 0); /* op */\r | |
618 | break;\r | |
619 | \r | |
620 | case F_V_JC: /* jump cond */\r | |
621 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r | |
622 | if (!cptr) return SCPE_ARG;\r | |
623 | cptr = get_glyph (cptr, gbuf, ','); /* cond */\r | |
624 | for (k = 0; k < 8; k++) { /* symbol? */\r | |
625 | if (strcmp (gbuf, cdname[k]) == 0) break;\r | |
626 | }\r | |
627 | if (k >= 8) return SCPE_ARG;\r | |
628 | val[0] = val[0] | (k << (I_V_OP + 1)); /* or to inst */\r | |
629 | \r | |
630 | case F_V_JU: /* jump uncond */\r | |
631 | cptr = get_ma (cptr, val, 0); /* addr */\r | |
632 | break;\r | |
633 | \r | |
634 | case F_V_RM: /* reg mem */\r | |
635 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r | |
636 | if (!cptr) return SCPE_ARG;\r | |
637 | case F_V_ZM: /* zero mem */\r | |
638 | cptr = get_op (cptr, val, ','); /* op */\r | |
639 | if (!cptr) return SCPE_ARG;\r | |
640 | cptr = get_ma (cptr, val, 0); /* addr */\r | |
641 | break;\r | |
642 | \r | |
643 | case F_V_MR: /* mem reg */\r | |
644 | cptr = get_ma (cptr, val, ','); /* addr */\r | |
645 | if (!cptr) return SCPE_ARG;\r | |
646 | cptr = get_op (cptr, val, ','); /* op */\r | |
647 | if (!cptr) return SCPE_ARG;\r | |
648 | cptr = get_sd (cptr, val, 0, FALSE); /* dst */\r | |
649 | break;\r | |
650 | \r | |
651 | case F_V_MS: /* mem self */\r | |
652 | cptr = get_ma (cptr, val, ','); /* addr */\r | |
653 | if (!cptr) return SCPE_ARG;\r | |
654 | cptr = get_op (cptr, val, 0); /* op */\r | |
655 | break;\r | |
656 | } /* end case */\r | |
657 | \r | |
658 | if (!cptr || (*cptr != 0)) return SCPE_ARG; /* junk at end? */\r | |
659 | return (j >= F_2WD)? -1: SCPE_OK;\r | |
660 | }\r |