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