First Commit of my working state
[simh.git] / HP2100 / hp2100_sys.c
1 /* hp2100_sys.c: HP 2100 simulator interface
2
3 Copyright (c) 1993-2008, 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 24-Apr-08 JDB Changed fprint_sym to handle step with irq pending
27 07-Dec-07 JDB Added BACI device
28 27-Nov-07 JDB Added RTE OS/VMA/EMA mnemonics
29 21-Dec-06 JDB Added "fwanxm" external for sim_load check
30 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF messages
31 25-Sep-04 JDB Added memory protect device
32 Fixed display of CCA/CCB/CCE instructions
33 01-Jun-04 RMS Added latent 13037 support
34 19-Apr-04 RMS Recognize SFS x,C and SFC x,C
35 22-Mar-02 RMS Revised for dynamically allocated memory
36 14-Feb-02 RMS Added DMS instructions
37 04-Feb-02 RMS Fixed bugs in alter/skip display and parsing
38 01-Feb-02 RMS Added terminal multiplexor support
39 16-Jan-02 RMS Added additional device support
40 17-Sep-01 RMS Removed multiconsole support
41 27-May-01 RMS Added multiconsole support
42 14-Mar-01 RMS Revised load/dump interface (again)
43 30-Oct-00 RMS Added examine to file support
44 15-Oct-00 RMS Added dynamic device number support
45 27-Oct-98 RMS V2.4 load interface
46 */
47
48 #include "hp2100_defs.h"
49 #include "hp2100_cpu.h"
50 #include <ctype.h>
51
52 extern DEVICE cpu_dev;
53 extern UNIT cpu_unit;
54 extern DEVICE mp_dev;
55 extern DEVICE dma0_dev, dma1_dev;
56 extern DEVICE ptr_dev, ptp_dev;
57 extern DEVICE tty_dev, clk_dev;
58 extern DEVICE lps_dev, lpt_dev;
59 extern DEVICE baci_dev;
60 extern DEVICE mtd_dev, mtc_dev;
61 extern DEVICE msd_dev, msc_dev;
62 extern DEVICE dpd_dev, dpc_dev;
63 extern DEVICE dqd_dev, dqc_dev;
64 extern DEVICE drd_dev, drc_dev;
65 extern DEVICE ds_dev;
66 extern DEVICE muxl_dev, muxu_dev, muxc_dev;
67 extern DEVICE ipli_dev, iplo_dev;
68 extern REG cpu_reg[];
69 extern uint16 *M;
70 extern uint32 fwanxm;
71
72 /* SCP data structures and interface routines
73
74 sim_name simulator name string
75 sim_PC pointer to saved PC register descriptor
76 sim_emax maximum number of words for examine/deposit
77 sim_devices array of pointers to simulated devices
78 sim_stop_messages array of pointers to stop messages
79 sim_load binary loader
80 */
81
82 char sim_name[] = "HP 2100";
83
84 char halt_msg[] = "HALT instruction xxxxxx";
85
86 REG *sim_PC = &cpu_reg[0];
87
88 int32 sim_emax = 3;
89
90 DEVICE *sim_devices[] = {
91 &cpu_dev,
92 &mp_dev,
93 &dma0_dev,
94 &dma1_dev,
95 &ptr_dev,
96 &ptp_dev,
97 &tty_dev,
98 &clk_dev,
99 &lps_dev,
100 &lpt_dev,
101 &baci_dev,
102 &dpd_dev, &dpc_dev,
103 &dqd_dev, &dqc_dev,
104 &drd_dev, &drc_dev,
105 &ds_dev,
106 &mtd_dev, &mtc_dev,
107 &msd_dev, &msc_dev,
108 &muxl_dev, &muxu_dev, &muxc_dev,
109 &ipli_dev, &iplo_dev,
110 NULL
111 };
112
113 const char *sim_stop_messages[] = {
114 "Unknown error",
115 "Unimplemented instruction",
116 "Non-existent I/O device",
117 halt_msg,
118 "Breakpoint",
119 "Indirect address loop",
120 "Indirect address interrupt (should not happen!)",
121 "No connection on interprocessor link",
122 "Device/unit offline",
123 "Device/unit powered off"
124 };
125
126 /* Binary loader
127
128 The binary loader consists of blocks preceded and trailed by zero frames.
129 A block consists of 16b words (punched big endian), as follows:
130
131 count'xxx
132 origin
133 word 0
134 :
135 word count-1
136 checksum
137
138 The checksum includes the origin but not the count.
139 */
140
141 int32 fgetw (FILE *fileref)
142 {
143 int c1, c2;
144
145 if ((c1 = fgetc (fileref)) == EOF) return -1;
146 if ((c2 = fgetc (fileref)) == EOF) return -1;
147 return ((c1 & 0377) << 8) | (c2 & 0377);
148 }
149
150 t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
151 {
152 int32 origin, csum, zerocnt, count, word, i;
153
154 if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
155 for (zerocnt = 1;; zerocnt = -10) { /* block loop */
156 for (;; zerocnt++) { /* skip 0's */
157 if ((count = fgetc (fileref)) == EOF) return SCPE_OK;
158 else if (count) break;
159 else if (zerocnt == 0) return SCPE_OK;
160 }
161 if (fgetc (fileref) == EOF) return SCPE_FMT;
162 if ((origin = fgetw (fileref)) < 0) return SCPE_FMT;
163 csum = origin; /* seed checksum */
164 for (i = 0; i < count; i++) { /* get data words */
165 if ((word = fgetw (fileref)) < 0) return SCPE_FMT;
166 if (MEM_ADDR_OK (origin)) M[origin] = word;
167 origin = origin + 1;
168 csum = csum + word;
169 }
170 if ((word = fgetw (fileref)) < 0) return SCPE_FMT;
171 if ((word ^ csum) & DMASK) return SCPE_CSUM;
172 }
173 }
174
175 /* Symbol tables */
176
177 #define I_V_FL 16 /* flag start */
178 #define I_M_FL 017 /* flag mask */
179 #define I_V_NPN 0 /* no operand */
180 #define I_V_NPC 1 /* no operand + C */
181 #define I_V_MRF 2 /* mem ref */
182 #define I_V_ASH 3 /* alter/skip, shift */
183 #define I_V_ESH 4 /* extended shift */
184 #define I_V_EMR 5 /* extended mem ref */
185 #define I_V_IO1 6 /* I/O + HC */
186 #define I_V_IO2 7 /* I/O only */
187 #define I_V_EGZ 010 /* ext grp, 1 op + 0 */
188 #define I_V_EG2 011 /* ext grp, 2 op */
189 #define I_V_ALT 012 /* alternate use instr */
190 #define I_NPN (I_V_NPN << I_V_FL)
191 #define I_NPC (I_V_NPC << I_V_FL)
192 #define I_MRF (I_V_MRF << I_V_FL)
193 #define I_ASH (I_V_ASH << I_V_FL)
194 #define I_ESH (I_V_ESH << I_V_FL)
195 #define I_EMR (I_V_EMR << I_V_FL)
196 #define I_IO1 (I_V_IO1 << I_V_FL)
197 #define I_IO2 (I_V_IO2 << I_V_FL)
198 #define I_EGZ (I_V_EGZ << I_V_FL)
199 #define I_EG2 (I_V_EG2 << I_V_FL)
200 #define I_ALT (I_V_ALT << I_V_FL)
201
202 static const int32 masks[] = {
203 0177777, 0176777, 0074000, 0170000,
204 0177760, 0177777, 0176700, 0177700,
205 0177777, 0177777, 0177777
206 };
207
208 static const char *opcode[] = {
209
210 /* These mnemonics are used by debug printouts, so put them first. */
211
212 "$LIBR", "$LIBX", ".TICK", ".TNAM", /* RTE-6/VM OS firmware */
213 ".STIO", ".FNW", ".IRT", ".LLS",
214 ".SIP", ".YLD", ".CPM", ".ETEQ",
215 ".ENTN", "$OTST", ".ENTC", ".DSPI",
216 "$DCPC", "$MPV", "$DEV", "$TBG", /* alternates for dual-use */
217
218 ".PMAP", "$LOC", "$VTST",/* --- */ /* RTE-6/VM VMA firmware */
219 /* --- --- --- --- */
220 ".IMAP", ".IMAR", ".JMAP", ".JMAR",
221 ".LPXR", ".LPX", ".LBPR", ".LBP",
222
223 ".EMIO", "MMAP", "$ETST",/* --- */ /* RTE-IV EMA firmware */
224 /* --- --- --- --- */
225 /* --- --- --- --- */
226 /* --- --- --- */ ".EMAP",
227
228 /* Regular mnemonics. */
229
230 "NOP", "NOP", "AND", "JSB",
231 "XOR", "JMP", "IOR", "ISZ",
232 "ADA", "ADB" ,"CPA", "CPB",
233 "LDA", "LDB", "STA", "STB",
234 "DIAG", "ASL", "LSL", "TIMER",
235 "RRL", "ASR", "LSR", "RRR",
236 "MPY", "DIV", "DLD", "DST",
237 "FAD", "FSB", "FMP", "FDV",
238 "FIX", "FLT",
239 "STO", "CLO", "SOC", "SOS",
240 "HLT", "STF", "CLF",
241 "SFC", "SFS", "MIA", "MIB",
242 "LIA", "LIB", "OTA", "OTB",
243 "STC", "CLC",
244 "SYA", "USA", "PAA", "PBA",
245 "XMA",
246 "XLA", "XSA", "XCA", "LFA",
247 "RSA", "RVA",
248 "MBI", "MBF",
249 "MBW", "MWI", "MWF", "MWW",
250 "SYB", "USB", "PAB", "PBB",
251 "SSM", "JRS",
252 "XMM", "XMS", "XMB",
253 "XLB", "XSB", "XCB", "LFB",
254 "RSB", "RVB", "DJP", "DJS",
255 "SJP", "SJS", "UJP", "UJS",
256 "SAX", "SBX", "CAX", "CBX",
257 "LAX", "LBX", "STX",
258 "CXA", "CXB", "LDX",
259 "ADX", "XAX", "XBX",
260 "SAY", "SBY", "CAY", "CBY",
261 "LAY", "LBY", "STY",
262 "CYA", "CYB", "LDY",
263 "ADY", "XAY", "XBY",
264 "ISX", "DSX", "JLY", "LBT",
265 "SBT", "MBT", "CBT", "SBT",
266 "ISY", "DSY", "JPY", "SBS",
267 "CBS", "TBS", "CMW", "MVW",
268 NULL, /* decode only */
269 NULL
270 };
271
272 static const int32 opc_val[] = {
273 0105340+I_NPN, 0105341+I_NPN, 0105342+I_NPN, 0105343+I_NPN, /* RTE-6/VM OS */
274 0105344+I_NPN, 0105345+I_NPN, 0105346+I_NPN, 0105347+I_NPN,
275 0105350+I_NPN, 0105351+I_NPN, 0105352+I_NPN, 0105353+I_NPN,
276 0105354+I_ALT, 0105355+I_ALT, 0105356+I_ALT, 0105357+I_ALT,
277 0105354+I_NPN, 0105355+I_NPN, 0105356+I_NPN, 0105357+I_NPN, /* alternates */
278
279 0105240+I_ALT, 0105241+I_ALT, 0105242+I_ALT, /* --- */ /* RTE-6/VM VMA */
280 /* --- --- --- --- */
281 0105250+I_NPN, 0105251+I_NPN, 0105252+I_NPN, 0105253+I_NPN,
282 0105254+I_NPN, 0105255+I_NPN, 0105256+I_NPN, 0105257+I_ALT,
283
284 0105240+I_NPN, 0105241+I_NPN, 0105242+I_NPN, /* RTE-IV EMA */
285 /* --- --- --- --- */
286 /* --- --- --- --- */
287 /* --- --- --- */ 0105257+I_NPN,
288
289 0000000+I_NPN, 0002000+I_NPN, 0010000+I_MRF, 0014000+I_MRF,
290 0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF,
291 0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF,
292 0060000+I_MRF, 0064000+I_MRF, 0070000+I_MRF, 0074000+I_MRF,
293 0100000+I_NPN, 0100020+I_ESH, 0100040+I_ESH, 0100060+I_NPN,
294 0100100+I_ESH, 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH,
295 0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR,
296 0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR,
297 0105100+I_NPN, 0105120+I_NPN,
298 0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPC, 0102301+I_NPC,
299 0102000+I_IO1, 0102100+I_IO2, 0103100+I_IO2,
300 0102200+I_IO1, 0102300+I_IO1, 0102400+I_IO1, 0106400+I_IO1,
301 0102500+I_IO1, 0106500+I_IO1, 0102600+I_IO1, 0106600+I_IO1,
302 0102700+I_IO1, 0106700+I_IO1,
303 0101710+I_NPN, 0101711+I_NPN, 0101712+I_NPN, 0101713+I_NPN,
304 0101722+I_NPN,
305 0101724+I_EMR, 0101725+I_EMR, 0101726+I_EMR, 0101727+I_NPN,
306 0101730+I_NPN, 0101731+I_NPN,
307 0105702+I_NPN, 0105703+I_NPN,
308 0105704+I_NPN, 0105705+I_NPN, 0105706+I_NPN, 0105707+I_NPN,
309 0105710+I_NPN, 0105711+I_NPN, 0105712+I_NPN, 0105713+I_NPN,
310 0105714+I_EMR, 0105715+I_EG2,
311 0105720+I_NPN, 0105721+I_NPN, 0105722+I_NPN,
312 0105724+I_EMR, 0105725+I_EMR, 0105726+I_EMR, 0105727+I_NPN,
313 0105730+I_NPN, 0105731+I_NPN, 0105732+I_EMR, 0105733+I_EMR,
314 0105734+I_EMR, 0105735+I_EMR, 0105736+I_EMR, 0105737+I_EMR,
315 0101740+I_EMR, 0105740+I_EMR, 0101741+I_NPN, 0105741+I_NPN,
316 0101742+I_EMR, 0105742+I_EMR, 0105743+I_EMR,
317 0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMR,
318 0105746+I_EMR, 0101747+I_NPN, 0105747+I_NPN,
319 0101750+I_EMR, 0105750+I_EMR, 0101751+I_NPN, 0105751+I_NPN,
320 0101752+I_EMR, 0105752+I_EMR, 0105753+I_EMR,
321 0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMR,
322 0105756+I_EMR, 0101757+I_NPN, 0105757+I_NPN,
323 0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMR, 0105763+I_NPN,
324 0105764+I_NPN, 0105765+I_EGZ, 0105766+I_EGZ, 0105767+I_NPN,
325 0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMR, 0105773+I_EG2,
326 0105774+I_EG2, 0105775+I_EG2, 0105776+I_EGZ, 0105777+I_EGZ,
327 0000000+I_ASH, /* decode only */
328 -1
329 };
330
331 /* Decode tables for shift and alter/skip groups */
332
333 static const char *stab[] = {
334 "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF",
335 "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF",
336 "CLA", "CMA", "CCA", "CLB", "CMB", "CCB",
337 "SEZ", "CLE", "CLE", "CME", "CCE",
338 "SSA", "SSB", "SLA", "SLB",
339 "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF",
340 "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF",
341 "INA", "INB", "SZA", "SZB", "RSS",
342 NULL
343 };
344
345 static const int32 mtab[] = {
346 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
347 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
348 0007400, 0007400, 0007400, 0007400, 0007400, 0007400,
349 0002040, 0002040, 0002300, 0002300, 0002300,
350 0006020, 0006020, 0004010, 0004010,
351 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,
352 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,
353 0006004, 0006004, 0006002, 0006002, 0002001,
354 0
355 };
356
357 static const int32 vtab[] = {
358 0001000, 0001100, 0001200, 0001300, 0001400, 0001500, 0001600, 0001700,
359 0005000, 0005100, 0005200, 0005300, 0005400, 0005500, 0005600, 0005700,
360 0002400, 0003000, 0003400, 0006400, 0007000, 0007400,
361 0002040, 0000040, 0002100, 0002200, 0002300,
362 0002020, 0006020, 0000010, 0004010,
363 0000020, 0000021, 0000022, 0000023, 0000024, 0000025, 0000026, 0000027,
364 0004020, 0004021, 0004022, 0004023, 0004024, 0004025, 0004026, 0004027,
365 0002004, 0006004, 0002002, 0006002, 0002001,
366 -1
367 };
368
369 /* Symbolic decode
370
371 Inputs:
372 *of = output stream
373 addr = current PC
374 *val = pointer to data
375 *uptr = pointer to unit
376 sw = switches
377 Outputs:
378 return = status code
379 */
380
381 #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
382
383 t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
384 UNIT *uptr, int32 sw)
385 {
386 int32 cflag, cm, i, j, inst, disp;
387 uint32 irq;
388
389 cflag = (uptr == NULL) || (uptr == &cpu_unit);
390 inst = val[0];
391 if (sw & SWMASK ('A')) { /* ASCII? */
392 if (inst > 0377) return SCPE_ARG;
393 fprintf (of, FMTASC (inst & 0177));
394 return SCPE_OK;
395 }
396 if (sw & SWMASK ('C')) { /* characters? */
397 fprintf (of, FMTASC ((inst >> 8) & 0177));
398 fprintf (of, FMTASC (inst & 0177));
399 return SCPE_OK;
400 }
401 if (!(sw & SWMASK ('M'))) return SCPE_ARG;
402
403 /* If we are being called as a result of a VM stop to display the next
404 instruction to be executed, check to see if an interrupt is pending and not
405 deferred. If so, then display the interrupt source and the trap cell
406 instruction as the instruction to be executed, rather than the instruction at
407 the current PC.
408 */
409
410 if (sw & SIM_SW_STOP) { /* simulator stop? */
411 irq = calc_int (); /* check interrupt */
412
413 if (irq && (!ion_defer || !calc_defer())) { /* pending interrupt and not deferred? */
414 inst = val[0] = ReadIO (irq, SMAP); /* load trap cell instruction */
415 val[1] = ReadIO (irq + 1, SMAP); /* might be multi-word */
416 val[2] = ReadIO (irq + 2, SMAP); /* although it's unlikely */
417 fprintf (of, "IAK %2o: ", irq); /* report acknowledged interrupt */
418 }
419 }
420
421 for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
422 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
423 if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */
424 switch (j) { /* case on class */
425
426 case I_V_NPN: /* no operands */
427 fprintf (of, "%s", opcode[i]); /* opcode */
428 break;
429
430 case I_V_NPC: /* no operands + C */
431 fprintf (of, "%s", opcode[i]);
432 if (inst & I_HC) fprintf (of, " C");
433 break;
434
435 case I_V_MRF: /* mem ref */
436 disp = inst & I_DISP; /* displacement */
437 fprintf (of, "%s ", opcode[i]); /* opcode */
438 if (inst & I_CP) { /* current page? */
439 if (cflag) fprintf (of, "%-o", (addr & I_PAGENO) | disp);
440 else fprintf (of, "C %-o", disp);
441 }
442 else fprintf (of, "%-o", disp); /* page zero */
443 if (inst & I_IA) fprintf (of, ",I");
444 break;
445
446 case I_V_ASH: /* shift, alter-skip */
447 cm = FALSE;
448 for (i = 0; mtab[i] != 0; i++) {
449 if ((inst & mtab[i]) == vtab[i]) {
450 inst = inst & ~(vtab[i] & 01777);
451 if (cm) fprintf (of, ",");
452 cm = TRUE;
453 fprintf (of, "%s", stab[i]);
454 }
455 }
456 if (!cm) return SCPE_ARG; /* nothing decoded? */
457 break;
458
459 case I_V_ESH: /* extended shift */
460 disp = inst & 017; /* shift count */
461 if (disp == 0) disp = 16;
462 fprintf (of, "%s %d", opcode[i], disp);
463 break;
464
465 case I_V_EMR: /* extended mem ref */
466 fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
467 if (val[1] & I_IA) fprintf (of, ",I");
468 return -1; /* extra word */
469
470 case I_V_IO1: /* IOT with H/C */
471 fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK);
472 if (inst & I_HC) fprintf (of, ",C");
473 break;
474
475 case I_V_IO2: /* IOT */
476 fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK);
477 break;
478
479 case I_V_EGZ: /* ext grp 1 op + 0 */
480 fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
481 if (val[1] & I_IA) fprintf (of, ",I");
482 return -2; /* extra words */
483
484 case I_V_EG2: /* ext grp 2 op */
485 fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
486 if (val[1] & I_IA) fprintf (of, ",I");
487 fprintf (of, " %-o", val[2] & VAMASK);
488 if (val[2] & I_IA) fprintf (of, ",I");
489 return -2; /* extra words */
490
491 case I_V_ALT: /* alternate use instr */
492 if ((inst >= 0105354) &&
493 (inst <= 0105357) && /* RTE-6/VM OS range? */
494 (addr >= 2) &&
495 (addr <= 077)) /* in trap cell? */
496 continue; /* use alternate mnemonic */
497
498 else if ((inst >= 0105240) && /* RTE-6/VM VMA range? */
499 (inst <= 0105257) &&
500 (cpu_unit.flags & UNIT_EMA)) /* EMA enabled? */
501 continue; /* use EMA mnemonics */
502
503 else
504 fprintf (of, "%s", opcode[i]); /* print opcode */
505 break;
506 }
507
508 return SCPE_OK;
509 } /* end if */
510 } /* end for */
511 return SCPE_ARG;
512 }
513
514 /* Get address with indirection
515
516 Inputs:
517 *cptr = pointer to input string
518 Outputs:
519 val = address
520 -1 if error
521 */
522
523 int32 get_addr (char *cptr)
524 {
525 int32 d;
526 t_stat r;
527 char gbuf[CBUFSIZE];
528
529 cptr = get_glyph (cptr, gbuf, ','); /* get next field */
530 d = get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */
531 if (r != SCPE_OK) return -1;
532 if (*cptr != 0) { /* more? */
533 cptr = get_glyph (cptr, gbuf, 0); /* look for indirect */
534 if (*cptr != 0) return -1; /* should be done */
535 if (strcmp (gbuf, "I")) return -1; /* I? */
536 d = d | I_IA;
537 }
538 return d;
539 }
540
541 /* Symbolic input
542
543 Inputs:
544 *iptr = pointer to input string
545 addr = current PC
546 *uptr = pointer to unit
547 *val = pointer to output values
548 sw = switches
549 Outputs:
550 status = error status
551 */
552
553 t_stat parse_sym (char *iptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
554 {
555 int32 cflag, d, i, j, k, clef, tbits;
556 t_stat r, ret;
557 char *cptr, gbuf[CBUFSIZE];
558
559 cflag = (uptr == NULL) || (uptr == &cpu_unit);
560 while (isspace (*iptr)) iptr++; /* absorb spaces */
561 if ((sw & SWMASK ('A')) || ((*iptr == '\'') && iptr++)) { /* ASCII char? */
562 if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */
563 val[0] = (t_value) iptr[0] & 0177;
564 return SCPE_OK;
565 }
566 if ((sw & SWMASK ('C')) || ((*iptr == '"') && iptr++)) { /* char string? */
567 if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */
568 val[0] = (((t_value) iptr[0] & 0177) << 8) |
569 ((t_value) iptr[1] & 0177);
570 return SCPE_OK;
571 }
572
573 ret = SCPE_OK;
574 cptr = get_glyph (iptr, gbuf, 0); /* get opcode */
575 for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
576 if (opcode[i]) { /* found opcode? */
577 val[0] = opc_val[i] & DMASK; /* get value */
578 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
579 switch (j) { /* case on class */
580
581 case I_V_NPN: /* no operand */
582 break;
583
584 case I_V_NPC: /* no operand + C */
585 if (*cptr != 0) {
586 cptr = get_glyph (cptr, gbuf, 0);
587 if (strcmp (gbuf, "C")) return SCPE_ARG;
588 val[0] = val[0] | I_HC;
589 }
590 break;
591
592 case I_V_MRF: /* mem ref */
593 cptr = get_glyph (cptr, gbuf, 0); /* get next field */
594 if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */
595 val[0] = val[0] | I_CP;
596 cptr = get_glyph (cptr, gbuf, 0);
597 }
598 else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */
599 cptr = get_glyph (cptr, gbuf, ',');
600 }
601 if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
602 if ((d & VAMASK) <= I_DISP) val[0] = val[0] | d;
603 else if (cflag && !k && (((addr ^ d) & I_PAGENO) == 0))
604 val[0] = val[0] | (d & (I_IA | I_DISP)) | I_CP;
605 else return SCPE_ARG;
606 break;
607
608 case I_V_ESH: /* extended shift */
609 cptr = get_glyph (cptr, gbuf, 0);
610 d = get_uint (gbuf, 10, 16, &r);
611 if ((r != SCPE_OK) || (d == 0)) return SCPE_ARG;
612 val[0] = val[0] | (d & 017);
613 break;
614
615 case I_V_EMR: /* extended mem ref */
616 cptr = get_glyph (cptr, gbuf, 0); /* get next field */
617 if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
618 val[1] = d;
619 ret = -1;
620 break;
621
622 case I_V_IO1: /* IOT + optional C */
623 cptr = get_glyph (cptr, gbuf, ','); /* get device */
624 d = get_uint (gbuf, 8, I_DEVMASK, &r);
625 if (r != SCPE_OK) return SCPE_ARG;
626 val[0] = val[0] | d;
627 if (*cptr != 0) {
628 cptr = get_glyph (cptr, gbuf, 0);
629 if (strcmp (gbuf, "C")) return SCPE_ARG;
630 val[0] = val[0] | I_HC;
631 }
632 break;
633
634 case I_V_IO2: /* IOT */
635 cptr = get_glyph (cptr, gbuf, 0); /* get device */
636 d = get_uint (gbuf, 8, I_DEVMASK, &r);
637 if (r != SCPE_OK) return SCPE_ARG;
638 val[0] = val[0] | d;
639 break;
640
641 case I_V_EGZ: /* ext grp 1 op + 0 */
642 cptr = get_glyph (cptr, gbuf, 0); /* get next field */
643 if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
644 val[1] = d;
645 val[2] = 0;
646 ret = -2;
647 break;
648
649 case I_V_EG2: /* ext grp 2 op */
650 cptr = get_glyph (cptr, gbuf, 0); /* get next field */
651 if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
652 cptr = get_glyph (cptr, gbuf, 0); /* get next field */
653 if ((k = get_addr (gbuf)) < 0) return SCPE_ARG;
654 val[1] = d;
655 val[2] = k;
656 ret = -2;
657 break;
658 } /* end case */
659
660 if (*cptr != 0) return SCPE_ARG; /* junk at end? */
661 return ret;
662 } /* end if opcode */
663
664 /* Shift or alter-skip
665
666 Each opcode is matched by a mask, specifiying the bits affected, and
667 the value, specifying the value. As opcodes are processed, the mask
668 values are used to specify which fields have already been filled in.
669
670 The mask has two subfields, the type bits (A/B and A/S), and the field
671 bits. The type bits, once specified by any instruction, must be
672 consistent in all other instructions. The mask bits assure that no
673 field is filled in twice.
674
675 Two special cases:
676
677 1. The dual shift field in shift requires checking how much of the
678 target word has been filled in before assigning the shift value.
679 To implement this, shifts are listed twice is the decode table.
680 If the current subopcode is a shift in the first part of the table
681 (entries 0..15), and CLE has been seen or the first shift field is
682 filled in, the code forces a mismatch. The glyph will match in
683 the second part of the table.
684
685 2. CLE processing must be deferred until the instruction can be
686 classified as shift or alter-skip, since it has two different
687 bit values in the two classes. To implement this, CLE seen is
688 recorded as a flag and processed after all other subopcodes.
689 */
690
691 clef = FALSE;
692 tbits = 0;
693 val[0] = 0;
694 for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0;
695 cptr = get_glyph (cptr, gbuf, ',')) { /* loop thru glyphs */
696 if (strcmp (gbuf, "CLE") == 0) { /* CLE? */
697 if (clef) return SCPE_ARG; /* already seen? */
698 clef = TRUE; /* set flag */
699 continue;
700 }
701 for (i = 0; stab[i] != NULL; i++) { /* find subopcode */
702 if ((strcmp (gbuf, stab[i]) == 0) &&
703 ((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break;
704 }
705 if (stab[i] == NULL) return SCPE_ARG;
706 if (tbits & mtab[i] & (I_AB | I_ASKP) & (vtab[i] ^ val[0]))
707 return SCPE_ARG;
708 if (tbits & mtab[i] & ~(I_AB | I_ASKP)) return SCPE_ARG;
709 tbits = tbits | mtab[i]; /* fill type+mask */
710 val[0] = val[0] | vtab[i]; /* fill value */
711 }
712 if (clef) { /* CLE seen? */
713 if (val[0] & I_ASKP) { /* alter-skip? */
714 if (tbits & 0100) return SCPE_ARG; /* already filled in? */
715 else val[0] = val[0] | 0100;
716 }
717 else val[0] = val[0] | 040; /* fill in shift */
718 }
719 return ret;
720 }