Commit | Line | Data |
---|---|---|
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 | |
52 | extern DEVICE cpu_dev;\r | |
53 | extern UNIT cpu_unit;\r | |
54 | extern DEVICE mp_dev;\r | |
55 | extern DEVICE dma0_dev, dma1_dev;\r | |
56 | extern DEVICE ptr_dev, ptp_dev;\r | |
57 | extern DEVICE tty_dev, clk_dev;\r | |
58 | extern DEVICE lps_dev, lpt_dev;\r | |
59 | extern DEVICE baci_dev;\r | |
60 | extern DEVICE mtd_dev, mtc_dev;\r | |
61 | extern DEVICE msd_dev, msc_dev;\r | |
62 | extern DEVICE dpd_dev, dpc_dev;\r | |
63 | extern DEVICE dqd_dev, dqc_dev;\r | |
64 | extern DEVICE drd_dev, drc_dev;\r | |
65 | extern DEVICE ds_dev;\r | |
66 | extern DEVICE muxl_dev, muxu_dev, muxc_dev;\r | |
67 | extern DEVICE ipli_dev, iplo_dev;\r | |
68 | extern REG cpu_reg[];\r | |
69 | extern uint16 *M;\r | |
70 | extern 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 | |
82 | char sim_name[] = "HP 2100";\r | |
83 | \r | |
84 | char halt_msg[] = "HALT instruction xxxxxx";\r | |
85 | \r | |
86 | REG *sim_PC = &cpu_reg[0];\r | |
87 | \r | |
88 | int32 sim_emax = 3;\r | |
89 | \r | |
90 | DEVICE *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 | |
113 | const 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 | |
141 | int32 fgetw (FILE *fileref)\r | |
142 | {\r | |
143 | int c1, c2;\r | |
144 | \r | |
145 | if ((c1 = fgetc (fileref)) == EOF) return -1;\r | |
146 | if ((c2 = fgetc (fileref)) == EOF) return -1;\r | |
147 | return ((c1 & 0377) << 8) | (c2 & 0377);\r | |
148 | }\r | |
149 | \r | |
150 | t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r | |
151 | {\r | |
152 | int32 origin, csum, zerocnt, count, word, i;\r | |
153 | \r | |
154 | if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;\r | |
155 | for (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 | |
202 | static 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 | |
208 | static 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 | |
272 | static 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 | |
333 | static 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 | |
345 | static 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 | |
357 | static 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 | |
383 | t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r | |
384 | UNIT *uptr, int32 sw)\r | |
385 | {\r | |
386 | int32 cflag, cm, i, j, inst, disp;\r | |
387 | uint32 irq;\r | |
388 | \r | |
389 | cflag = (uptr == NULL) || (uptr == &cpu_unit);\r | |
390 | inst = val[0];\r | |
391 | if (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 | |
396 | if (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 | |
401 | if (!(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 | |
410 | if (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 | |
421 | for (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 | |
511 | return 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 | |
523 | int32 get_addr (char *cptr)\r | |
524 | {\r | |
525 | int32 d;\r | |
526 | t_stat r;\r | |
527 | char gbuf[CBUFSIZE];\r | |
528 | \r | |
529 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r | |
530 | d = get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */\r | |
531 | if (r != SCPE_OK) return -1;\r | |
532 | if (*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 | |
538 | return 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 | |
553 | t_stat parse_sym (char *iptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r | |
554 | {\r | |
555 | int32 cflag, d, i, j, k, clef, tbits;\r | |
556 | t_stat r, ret;\r | |
557 | char *cptr, gbuf[CBUFSIZE];\r | |
558 | \r | |
559 | cflag = (uptr == NULL) || (uptr == &cpu_unit);\r | |
560 | while (isspace (*iptr)) iptr++; /* absorb spaces */\r | |
561 | if ((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 | |
566 | if ((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 | |
573 | ret = SCPE_OK;\r | |
574 | cptr = get_glyph (iptr, gbuf, 0); /* get opcode */\r | |
575 | for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r | |
576 | if (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 | |
691 | clef = FALSE;\r | |
692 | tbits = 0;\r | |
693 | val[0] = 0;\r | |
694 | for (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 | |
712 | if (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 | |
719 | return ret;\r | |
720 | }\r |