First Commit of my working state
[simh.git] / PDP8 / pdp8_sys.c
1 /* pdp8_sys.c: PDP-8 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-Jun-08 RMS Fixed bug in new rim loader (found by Don North)
27 24-May-08 RMS Fixed signed/unsigned declaration inconsistency
28 03-Sep-07 RMS Added FPP8 support
29 Rewrote rim and binary loaders
30 15-Dec-06 RMS Added TA8E support, IOT disambiguation
31 30-Oct-06 RMS Added infinite loop stop
32 18-Oct-06 RMS Re-ordered device list
33 17-Oct-03 RMS Added TSC8-75, TD8E support, DECtape off reel message
34 25-Apr-03 RMS Revised for extended file support
35 30-Dec-01 RMS Revised for new TTX
36 26-Nov-01 RMS Added RL8A support
37 17-Sep-01 RMS Removed multiconsole support
38 16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support
39 27-May-01 RMS Added multiconsole support
40 18-Mar-01 RMS Added DF32 support
41 14-Mar-01 RMS Added extension detection of RIM binary tapes
42 15-Feb-01 RMS Added DECtape support
43 30-Oct-00 RMS Added support for examine to file
44 27-Oct-98 RMS V2.4 load interface
45 10-Apr-98 RMS Added RIM loader support
46 17-Feb-97 RMS Fixed bug in handling of bin loader fields
47 */
48
49 #include "pdp8_defs.h"
50 #include <ctype.h>
51
52 extern DEVICE cpu_dev;
53 extern UNIT cpu_unit;
54 extern DEVICE tsc_dev;
55 extern DEVICE ptr_dev, ptp_dev;
56 extern DEVICE tti_dev, tto_dev;
57 extern DEVICE clk_dev, lpt_dev;
58 extern DEVICE rk_dev, rl_dev;
59 extern DEVICE rx_dev;
60 extern DEVICE df_dev, rf_dev;
61 extern DEVICE dt_dev, td_dev;
62 extern DEVICE mt_dev, ct_dev;
63 extern DEVICE ttix_dev, ttox_dev;
64 extern REG cpu_reg[];
65 extern uint16 M[];
66 extern int32 sim_switches;
67
68 t_stat fprint_sym_fpp (FILE *of, t_value *val);
69 t_stat parse_sym_fpp (char *cptr, t_value *val);
70 char *parse_field (char *cptr, uint32 max, uint32 *val, uint32 c);
71 char *parse_fpp_xr (char *cptr, uint32 *xr, t_bool inc);
72 int32 test_fpp_addr (uint32 ad, uint32 max);
73
74 /* SCP data structures and interface routines
75
76 sim_name simulator name string
77 sim_PC pointer to saved PC register descriptor
78 sim_emax maximum number of words for examine/deposit
79 sim_devices array of pointers to simulated devices
80 sim_consoles array of pointers to consoles (if more than one)
81 sim_stop_messages array of pointers to stop messages
82 sim_load binary loader
83 */
84
85 char sim_name[] = "PDP-8";
86
87 REG *sim_PC = &cpu_reg[0];
88
89 int32 sim_emax = 4;
90
91 DEVICE *sim_devices[] = {
92 &cpu_dev,
93 &tsc_dev,
94 &clk_dev,
95 &ptr_dev,
96 &ptp_dev,
97 &tti_dev,
98 &tto_dev,
99 &ttix_dev,
100 &ttox_dev,
101 &lpt_dev,
102 &rk_dev,
103 &rl_dev,
104 &rx_dev,
105 &df_dev,
106 &rf_dev,
107 &dt_dev,
108 &td_dev,
109 &mt_dev,
110 &ct_dev,
111 NULL
112 };
113
114 const char *sim_stop_messages[] = {
115 "Unknown error",
116 "Unimplemented instruction",
117 "HALT instruction",
118 "Breakpoint",
119 "Non-standard device number",
120 "DECtape off reel",
121 "Infinite loop"
122 };
123
124 /* Ambiguous device list - these devices have overlapped IOT codes */
125
126 DEVICE *amb_dev[] = {
127 &rl_dev,
128 &ct_dev,
129 &td_dev,
130 NULL
131 };
132
133 #define AMB_RL (1 << 12)
134 #define AMB_CT (2 << 12)
135 #define AMB_TD (3 << 12)
136
137 /* RIM loader format consists of alternating pairs of addresses and 12-bit
138 words. It can only operate in field 0 and is not checksummed.
139 */
140
141 t_stat sim_load_rim (FILE *fi)
142 {
143 int32 origin, hi, lo, wd;
144
145 origin = 0200;
146 do { /* skip leader */
147 if ((hi = getc (fi)) == EOF)
148 return SCPE_FMT;
149 } while ((hi == 0) || (hi >= 0200));
150 do { /* data block */
151 if ((lo = getc (fi)) == EOF)
152 return SCPE_FMT;
153 wd = (hi << 6) | lo;
154 if (wd > 07777) origin = wd & 07777;
155 else M[origin++ & 07777] = wd;
156 if ((hi = getc (fi)) == EOF)
157 return SCPE_FMT;
158 } while (hi < 0200); /* until trailer */
159 return SCPE_OK;
160 }
161
162 /* BIN loader format consists of a string of 12-bit words (made up from
163 7-bit characters) between leader and trailer (200). The last word on
164 tape is the checksum. A word with the "link" bit set is a new origin;
165 a character > 0200 indicates a change of field.
166 */
167
168 int32 sim_bin_getc (FILE *fi, uint32 *newf)
169 {
170 int32 c, rubout;
171
172 rubout = 0; /* clear toggle */
173 while ((c = getc (fi)) != EOF) { /* read char */
174 if (rubout) /* toggle set? */
175 rubout = 0; /* clr, skip */
176 else if (c == 0377) /* rubout? */
177 rubout = 1; /* set, skip */
178 else if (c > 0200) /* channel 8 set? */
179 *newf = (c & 070) << 9; /* change field */
180 else return c; /* otherwise ok */
181 }
182 return EOF;
183 }
184
185 t_stat sim_load_bin (FILE *fi)
186 {
187 int32 hi, lo, wd, csum, t;
188 uint32 field, newf, origin;
189
190 do { /* skip leader */
191 if ((hi = sim_bin_getc (fi, &newf)) == EOF)
192 return SCPE_FMT;
193 } while ((hi == 0) || (hi >= 0200));
194 csum = origin = field = newf = 0; /* init */
195 for (;;) { /* data blocks */
196 if ((lo = sim_bin_getc (fi, &newf)) == EOF) /* low char */
197 return SCPE_FMT;
198 wd = (hi << 6) | lo; /* form word */
199 t = hi; /* save for csum */
200 if ((hi = sim_bin_getc (fi, &newf)) == EOF) /* next char */
201 return SCPE_FMT;
202 if (hi == 0200) { /* end of tape? */
203 if ((csum - wd) & 07777) /* valid csum? */
204 return SCPE_CSUM;
205 return SCPE_OK;
206 }
207 csum = csum + t + lo; /* add to csum */
208 if (wd > 07777) /* chan 7 set? */
209 origin = wd & 07777; /* new origin */
210 else { /* no, data */
211 if ((field | origin) >= MEMSIZE)
212 return SCPE_NXM;
213 M[field | origin] = wd;
214 origin = (origin + 1) & 07777;
215 }
216 field = newf; /* update field */
217 }
218 return SCPE_IERR;
219 }
220
221 /* Binary loader
222 Two loader formats are supported: RIM loader (-r) and BIN (-b) loader. */
223
224 t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
225 {
226 if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
227 if ((sim_switches & SWMASK ('R')) || /* RIM format? */
228 (match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B'))))
229 return sim_load_rim (fileref);
230 else return sim_load_bin (fileref); /* no, BIN */
231 }
232
233 /* Symbol tables */
234
235 #define I_V_FL 18 /* flag start */
236 #define I_M_FL 07 /* flag mask */
237 #define I_V_NPN 0 /* no operand */
238 #define I_V_FLD 1 /* field change */
239 #define I_V_MRF 2 /* mem ref */
240 #define I_V_IOT 3 /* general IOT */
241 #define I_V_OP1 4 /* operate 1 */
242 #define I_V_OP2 5 /* operate 2 */
243 #define I_V_OP3 6 /* operate 3 */
244 #define I_V_IOA 7 /* ambiguous IOT */
245 #define I_NPN (I_V_NPN << I_V_FL)
246 #define I_FLD (I_V_FLD << I_V_FL)
247 #define I_MRF (I_V_MRF << I_V_FL)
248 #define I_IOT (I_V_IOT << I_V_FL)
249 #define I_OP1 (I_V_OP1 << I_V_FL)
250 #define I_OP2 (I_V_OP2 << I_V_FL)
251 #define I_OP3 (I_V_OP3 << I_V_FL)
252 #define I_IOA (I_V_IOA << I_V_FL)
253
254 static const int32 masks[] = {
255 07777, 07707, 07000, 07000,
256 07416, 07571, 017457, 077777,
257 };
258
259 /* Ambiguous device mnemonics must precede default mnemonics */
260
261 static const char *opcode[] = {
262 "SKON", "ION", "IOF", "SRQ", /* std IOTs */
263 "GTF", "RTF", "SGT", "CAF",
264 "RPE", "RSF", "RRB", "RFC", "RFC RRB", /* reader/punch */
265 "PCE", "PSF", "PCF", "PPC", "PLS",
266 "KCF", "KSF", "KCC", "KRS", "KIE", "KRB", /* console */
267 "TLF", "TSF", "TCF", "TPC", "SPI", "TLS",
268 "SBE", "SPL", "CAL", /* power fail */
269 "CLEI", "CLDI", "CLSC", "CLLE", "CLCL", "CLSK", /* clock */
270 "CINT", "RDF", "RIF", "RIB", /* mem mmgt */
271 "RMF", "SINT", "CUF", "SUF",
272 "RLDC", "RLSD", "RLMA", "RLCA", /* RL - ambiguous */
273 "RLCB", "RLSA", "RLWC",
274 "RRER", "RRWC", "RRCA", "RRCB",
275 "RRSA", "RRSI", "RLSE",
276 "KCLR", "KSDR", "KSEN", "KSBF", /* CT - ambiguous */
277 "KLSA", "KSAF", "KGOA", "KRSB",
278 "SDSS", "SDST", "SDSQ", /* TD - ambiguous */
279 "SDLC", "SDLD", "SDRC", "SDRD",
280 "ADCL", "ADLM", "ADST", "ADRB", /* A/D */
281 "ADSK", "ADSE", "ADLE", "ADRS",
282 "DCMA", "DMAR", "DMAW", /* DF/RF */
283 "DCIM", "DSAC", "DIML", "DIMA",
284 "DCEA", "DEAL", "DEAC",
285 "DFSE", "DFSC", "DISK", "DMAC",
286 "DCXA", "DXAL", "DXAC",
287 "PSKF", "PCLF", "PSKE", /* LPT */
288 "PSTB", "PSIE", "PCLF PSTB", "PCIE",
289 "LWCR", "CWCR", "LCAR", /* MT */
290 "CCAR", "LCMR", "LFGR", "LDBR",
291 "RWCR", "CLT", "RCAR",
292 "RMSR", "RCMR", "RFSR", "RDBR",
293 "SKEF", "SKCB", "SKJD", "SKTR", "CLF",
294 "DSKP", "DCLR", "DLAG", /* RK */
295 "DLCA", "DRST", "DLDC", "DMAN",
296 "LCD", "XDR", "STR", /* RX */
297 "SER", "SDN", "INTR", "INIT",
298 "DTRA", "DTCA", "DTXA", "DTLA", /* DT */
299 "DTSF", "DTRB", "DTLB",
300 "ETDS", "ESKP", "ECTF", "ECDF", /* TSC75 */
301 "ERTB", "ESME", "ERIOT", "ETEN",
302 "FFST", "FPINT", "FPICL", "FPCOM", /* FPP8 */
303 "FPHLT", "FPST", "FPRST", "FPIST",
304 "FMODE", "FMRB",
305 "FMRP", "FMDO", "FPEP",
306
307 "CDF", "CIF", "CIF CDF",
308 "AND", "TAD", "ISZ", "DCA", "JMS", "JMP", "IOT",
309 "NOP", "NOP2", "NOP3", "SWAB", "SWBA",
310 "STL", "GLK", "STA", "LAS", "CIA",
311 "BSW", "RAL", "RTL", "RAR", "RTR", "RAL RAR", "RTL RTR",
312 "SKP", "SNL", "SZL",
313 "SZA", "SNA", "SZA SNL", "SNA SZL",
314 "SMA", "SPA", "SMA SNL", "SPA SZL",
315 "SMA SZA", "SPA SNA", "SMA SZA SNL", "SPA SNA SZL",
316 "SCL", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",
317 "SCA", "SCA SCL", "SCA MUY", "SCA DVI",
318 "SCA NMI", "SCA SHL", "SCA ASR", "SCA LSR",
319 "ACS", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",
320 "SCA", "DAD", "DST", "SWBA",
321 "DPSZ", "DPIC", "DCIM", "SAM",
322 "CLA", "CLL", "CMA", "CML", "IAC", /* encode only */
323 "CLA", "OAS", "HLT",
324 "CLA", "MQA", "MQL",
325 NULL, NULL, NULL, NULL, /* decode only */
326 NULL
327 };
328
329 static const int32 opc_val[] = {
330 06000+I_NPN, 06001+I_NPN, 06002+I_NPN, 06003+I_NPN,
331 06004+I_NPN, 06005+I_NPN, 06006+I_NPN, 06007+I_NPN,
332 06010+I_NPN, 06011+I_NPN, 06012+I_NPN, 06014+I_NPN, 06016+I_NPN,
333 06020+I_NPN, 06021+I_NPN, 06022+I_NPN, 06024+I_NPN, 06026+I_NPN,
334 06030+I_NPN, 06031+I_NPN, 06032+I_NPN, 06034+I_NPN, 06035+I_NPN, 06036+I_NPN,
335 06040+I_NPN, 06041+I_NPN, 06042+I_NPN, 06044+I_NPN, 06045+I_NPN, 06046+I_NPN,
336 06101+I_NPN, 06102+I_NPN, 06103+I_NPN,
337 06131+I_NPN, 06132+I_NPN, 06133+I_NPN, 06135+I_NPN, 06136+I_NPN, 06137+I_NPN,
338 06204+I_NPN, 06214+I_NPN, 06224+I_NPN, 06234+I_NPN,
339 06244+I_NPN, 06254+I_NPN, 06264+I_NPN, 06274+I_NPN,
340 06600+I_IOA+AMB_RL, 06601+I_IOA+AMB_RL, 06602+I_IOA+AMB_RL, 06603+I_IOA+AMB_RL,
341 06604+I_IOA+AMB_RL, 06605+I_IOA+AMB_RL, 06607+I_IOA+AMB_RL,
342 06610+I_IOA+AMB_RL, 06611+I_IOA+AMB_RL, 06612+I_IOA+AMB_RL, 06613+I_IOA+AMB_RL,
343 06614+I_IOA+AMB_RL, 06615+I_IOA+AMB_RL, 06617+I_IOA+AMB_RL,
344 06700+I_IOA+AMB_CT, 06701+I_IOA+AMB_CT, 06702+I_IOA+AMB_CT, 06703+I_IOA+AMB_CT,
345 06704+I_IOA+AMB_CT, 06705+I_IOA+AMB_CT, 06706+I_IOA+AMB_CT, 06707+I_IOA+AMB_CT,
346 06771+I_IOA+AMB_TD, 06772+I_IOA+AMB_TD, 06773+I_IOA+AMB_TD,
347 06774+I_IOA+AMB_TD, 06775+I_IOA+AMB_TD, 06776+I_IOA+AMB_TD, 06777+I_IOA+AMB_TD,
348 06530+I_NPN, 06531+I_NPN, 06532+I_NPN, 06533+I_NPN, /* AD */
349 06534+I_NPN, 06535+I_NPN, 06536+I_NPN, 06537+I_NPN,
350 06601+I_NPN, 06603+I_NPN, 06605+I_NPN, /* DF/RF */
351 06611+I_NPN, 06612+I_NPN, 06615+I_NPN, 06616+I_NPN,
352 06611+I_NPN, 06615+I_NPN, 06616+I_NPN,
353 06621+I_NPN, 06622+I_NPN, 06623+I_NPN, 06626+I_NPN,
354 06641+I_NPN, 06643+I_NPN, 06645+I_NPN,
355 06661+I_NPN, 06662+I_NPN, 06663+I_NPN, /* LPT */
356 06664+I_NPN, 06665+I_NPN, 06666+I_NPN, 06667+I_NPN,
357 06701+I_NPN, 06702+I_NPN, 06703+I_NPN, /* MT */
358 06704+I_NPN, 06705+I_NPN, 06706+I_NPN, 06707+I_NPN,
359 06711+I_NPN, 06712+I_NPN, 06713+I_NPN,
360 06714+I_NPN, 06715+I_NPN, 06716+I_NPN, 06717+I_NPN,
361 06721+I_NPN, 06722+I_NPN, 06723+I_NPN, 06724+I_NPN, 06725+I_NPN,
362 06741+I_NPN, 06742+I_NPN, 06743+I_NPN, /* RK */
363 06744+I_NPN, 06745+I_NPN, 06746+I_NPN, 06747+I_NPN,
364 06751+I_NPN, 06752+I_NPN, 06753+I_NPN, /* RX */
365 06754+I_NPN, 06755+I_NPN, 06756+I_NPN, 06757+I_NPN,
366 06761+I_NPN, 06762+I_NPN, 06764+I_NPN, 06766+I_NPN, /* DT */
367 06771+I_NPN, 06772+I_NPN, 06774+I_NPN,
368 06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN, /* TSC */
369 06364+I_NPN, 06365+I_NPN, 06366+I_NPN, 06367+I_NPN,
370 06550+I_NPN, 06551+I_NPN, 06552+I_NPN, 06553+I_NPN, /* FPP8 */
371 06554+I_NPN, 06555+I_NPN, 06556+I_NPN, 06557+I_NPN,
372 06561+I_NPN, 06563+I_NPN,
373 06564+I_NPN, 06565+I_NPN, 06567+I_NPN,
374
375 06201+I_FLD, 06202+I_FLD, 06203+I_FLD,
376 00000+I_MRF, 01000+I_MRF, 02000+I_MRF, 03000+I_MRF,
377 04000+I_MRF, 05000+I_MRF, 06000+I_IOT,
378 07000+I_NPN, 07400+I_NPN, 07401+I_NPN, 07431+I_NPN, 07447+I_NPN,
379 07120+I_NPN, 07204+I_NPN, 07240+I_NPN, 07604+I_NPN, 07041+I_NPN,
380 07002+I_OP1, 07004+I_OP1, 07006+I_OP1,
381 07010+I_OP1, 07012+I_OP1, 07014+I_OP1, 07016+I_OP1,
382 07410+I_OP2, 07420+I_OP2, 07430+I_OP2,
383 07440+I_OP2, 07450+I_OP2, 07460+I_OP2, 07470+I_OP2,
384 07500+I_OP2, 07510+I_OP2, 07520+I_OP2, 07530+I_OP2,
385 07540+I_OP2, 07550+I_OP2, 07560+I_OP2, 07570+I_OP2,
386 07403+I_OP3, 07405+I_OP3, 07407+I_OP3,
387 07411+I_OP3, 07413+I_OP3, 07415+I_OP3, 07417+I_OP3,
388 07441+I_OP3, 07443+I_OP3, 07445+I_OP3, 07447+I_OP3,
389 07451+I_OP3, 07453+I_OP3, 07455+I_OP3, 07457+I_OP3,
390 017403+I_OP3, 017405+I_OP3, 0174017+I_OP3,
391 017411+I_OP3, 017413+I_OP3, 017415+I_OP3, 017417+I_OP3,
392 017441+I_OP3, 017443+I_OP3, 017445+I_OP3, 017447+I_OP3,
393 017451+I_OP3, 017453+I_OP3, 017455+I_OP3, 017457+I_OP3,
394 07200+I_OP1, 07100+I_OP1, 07040+I_OP1, 07020+I_OP1, 07001+I_OP1,
395 07600+I_OP2, 07404+I_OP2, 07402+I_OP2,
396 07601+I_OP3, 07501+I_OP3, 07421+I_OP3,
397 07000+I_OP1, 07400+I_OP2, 07401+I_OP3, 017401+I_OP3,
398 -1
399 };
400
401 /* Symbol tables for FPP-8 */
402
403 #define F_V_FL 18 /* flag start */
404 #define F_M_FL 017 /* flag mask */
405 #define F_V_NOP12 0 /* no opnd 12b */
406 #define F_V_NOP9 1 /* no opnd 9b */
407 #define F_V_AD15 2 /* 15b dir addr */
408 #define F_V_AD15X 3 /* 15b dir addr indx */
409 #define F_V_IMMX 4 /* 12b immm indx */
410 #define F_V_X 5 /* index */
411 #define F_V_MRI 6 /* mem ref ind */
412 #define F_V_MR1D 7 /* mem ref dir 1 word */
413 #define F_V_MR2D 8 /* mem ref dir 2 word */
414 #define F_V_LEMU 9 /* LEA/IMUL */
415 #define F_V_LEMUI 10 /* LEAI/IMULI */
416 #define F_V_LTR 11 /* LTR */
417 #define F_V_MRD 12 /* mem ref direct (enc) */
418 #define F_NOP12 (F_V_NOP12 << F_V_FL)
419 #define F_NOP9 (F_V_NOP9 << F_V_FL)
420 #define F_AD15 (F_V_AD15 << F_V_FL)
421 #define F_AD15X (F_V_AD15X << F_V_FL)
422 #define F_IMMX (F_V_IMMX << F_V_FL)
423 #define F_X (F_V_X << F_V_FL)
424 #define F_MRI (F_V_MRI << F_V_FL)
425 #define F_MR1D (F_V_MR1D << F_V_FL)
426 #define F_MR2D (F_V_MR2D << F_V_FL)
427 #define F_LEMU (F_V_LEMU << F_V_FL)
428 #define F_LEMUI (F_V_LEMUI << F_V_FL)
429 #define F_LTR (F_V_LTR << F_V_FL)
430 #define F_MRD (F_V_MRD << F_V_FL)
431
432 static const uint32 fmasks[] = {
433 07777, 07770, 07770, 07600,
434 07770, 07770, 07600, 07600,
435 07600, 017600, 017600, 07670,
436 07777
437 };
438
439 /* Memory references are encode dir / decode 1D / decode 2D / indirect */
440
441 static const char *fopcode[] = {
442 "FEXIT", "FPAUSE", "FCLA", "FNEG",
443 "FNORM", "STARTF", "STARTD", "JAC",
444 "ALN", "ATX", "XTA",
445 "FNOP", "STARTE",
446 "LDX", "ADDX",
447 "FLDA", "FLDA", "FLDA", "FLDAI",
448 "JEQ", "JGE", "JLE", "JA",
449 "JNE", "JLT", "JGT", "JAL",
450 "SETX", "SETB", "JSA", "JSR",
451 "FADD", "FADD", "FADD", "FADDI",
452 "JNX",
453 "FSUB", "FSUB", "FSUB", "FSUBI",
454 "TRAP3",
455 "FDIV", "FDIV", "FDIV", "FDIVI",
456 "TRAP4",
457 "FMUL", "FMUL", "FMUL", "FMULI",
458 "LTREQ", "LTRGE", "LTRLE", "LTRA",
459 "LTRNE", "LTRLT", "LTRGT", "LTRAL",
460 "FADDM", "FADDM", "FADDM", "FADDMI",
461 "IMUL", "LEA",
462 "FSTA", "FSTA", "FSTA", "FSTAI",
463 "IMULI", "LEAI",
464 "FMULM", "FMULM", "FMULM", "FMULMI",
465 NULL
466 };
467
468 static const int32 fop_val[] = {
469 00000+F_NOP12, 00001+F_NOP12, 00002+F_NOP12, 00003+F_NOP12,
470 00004+F_NOP12, 00005+F_NOP12, 00006+F_NOP12, 00007+F_NOP12,
471 00010+F_X, 00020+F_X, 00030+F_X,
472 00040+F_NOP9, 00050+F_NOP9,
473 00100+F_IMMX, 00110+F_IMMX,
474 00000+F_MRD, 00200+F_MR1D, 00400+F_MR2D, 00600+F_MRI,
475 01000+F_AD15, 01010+F_AD15, 01020+F_AD15, 01030+F_AD15,
476 01040+F_AD15, 01050+F_AD15, 01060+F_AD15, 01070+F_AD15,
477 01100+F_AD15, 01110+F_AD15, 01120+F_AD15, 01130+F_AD15,
478 01000+F_MRD, 01200+F_MR1D, 01400+F_MR2D, 01600+F_MRI,
479 02000+F_AD15X,
480 02000+F_MRD, 02200+F_MR1D, 02400+F_MR2D, 02600+F_MRI,
481 03000+F_AD15,
482 03000+F_MRD, 03200+F_MR1D, 03400+F_MR2D, 03600+F_MRI,
483 04000+F_AD15,
484 04000+F_MRD, 04200+F_MR1D, 04400+F_MR2D, 04600+F_MRI,
485 05000+F_LTR, 05010+F_LTR, 05020+F_LTR, 05030+F_LTR,
486 05040+F_LTR, 05050+F_LTR, 05060+F_LTR, 05070+F_LTR,
487 05000+F_MRD, 05200+F_MR1D, 05400+F_MR2D, 05600+F_MRI,
488 016000+F_LEMU, 006000+F_LEMU,
489 06000+F_MRD, 06200+F_MR1D, 06400+F_MR2D, 06600+F_MRI,
490 017000+F_LEMUI, 007000+F_LEMUI,
491 07000+F_MRD, 07200+F_MR1D, 07400+F_MR2D, 07600+F_MRI,
492 -1
493 };
494
495 /* Operate decode
496
497 Inputs:
498 *of = output stream
499 inst = mask bits
500 class = instruction class code
501 sp = space needed?
502 Outputs:
503 status = space needed
504 */
505
506 int32 fprint_opr (FILE *of, int32 inst, int32 class, int32 sp)
507 {
508 int32 i, j;
509
510 for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
511 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
512 if ((j == class) && (opc_val[i] & inst)) { /* same class? */
513 inst = inst & ~opc_val[i]; /* mask bit set? */
514 fprintf (of, (sp? " %s": "%s"), opcode[i]);
515 sp = 1;
516 }
517 }
518 return sp;
519 }
520
521 /* Symbolic decode
522
523 Inputs:
524 *of = output stream
525 addr = current PC
526 *val = pointer to data
527 *uptr = pointer to unit
528 sw = switches
529 Outputs:
530 return = status code
531 */
532
533 #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
534 #define SIXTOASC(x) (((x) >= 040)? (x): (x) + 0100)
535 #define TSSTOASC(x) ((x) + 040)
536
537 t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
538 UNIT *uptr, int32 sw)
539 {
540 int32 cflag, i, j, sp, inst, disp, opc;
541 extern int32 emode;
542 t_stat r;
543
544 cflag = (uptr == NULL) || (uptr == &cpu_unit);
545 inst = val[0];
546 if (sw & SWMASK ('A')) { /* ASCII? */
547 if (inst > 0377) return SCPE_ARG;
548 fprintf (of, FMTASC (inst & 0177));
549 return SCPE_OK;
550 }
551 if (sw & SWMASK ('C')) { /* characters? */
552 fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077));
553 fprintf (of, "%c", SIXTOASC (inst & 077));
554 return SCPE_OK;
555 }
556 if (sw & SWMASK ('T')) { /* TSS8 packed? */
557 fprintf (of, "%c", TSSTOASC ((inst >> 6) & 077));
558 fprintf (of, "%c", TSSTOASC (inst & 077));
559 return SCPE_OK;
560 }
561 if ((sw & SWMASK ('F')) && /* FPP8? */
562 ((r = fprint_sym_fpp (of, val)) != SCPE_ARG))
563 return r;
564 if (!(sw & SWMASK ('M'))) return SCPE_ARG;
565
566 /* Instruction decode */
567
568 opc = (inst >> 9) & 07; /* get major opcode */
569 if (opc == 07) /* operate? */
570 inst = inst | ((emode & 1) << 12); /* include EAE mode */
571 if (opc == 06) { /* IOT? */
572 DEVICE *dptr;
573 DIB *dibp;
574 uint32 dno = (inst >> 3) & 077;
575 for (i = 0; (dptr = amb_dev[i]) != NULL; i++) { /* check amb devices */
576 if ((dptr->ctxt == NULL) || /* no DIB or */
577 (dptr->flags & DEV_DIS)) continue; /* disabled? skip */
578 dibp = (DIB *) dptr->ctxt; /* get DIB */
579 if ((dno >= dibp->dev) || /* IOT for this dev? */
580 (dno < (dibp->dev + dibp->num))) {
581 inst = inst | ((i + 1) << 12); /* disambiguate */
582 break; /* done */
583 }
584 }
585 }
586
587 for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
588 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
589 if ((opc_val[i] & 077777) == (inst & masks[j])) { /* match? */
590
591 switch (j) { /* case on class */
592
593 case I_V_NPN: case I_V_IOA: /* no operands */
594 fprintf (of, "%s", opcode[i]); /* opcode */
595 break;
596
597 case I_V_FLD: /* field change */
598 fprintf (of, "%s %-o", opcode[i], (inst >> 3) & 07);
599 break;
600
601 case I_V_MRF: /* mem ref */
602 disp = inst & 0177; /* displacement */
603 fprintf (of, "%s%s", opcode[i], ((inst & 00400)? " I ": " "));
604 if (inst & 0200) { /* current page? */
605 if (cflag) fprintf (of, "%-o", (addr & 07600) | disp);
606 else fprintf (of, "C %-o", disp);
607 }
608 else fprintf (of, "%-o", disp); /* page zero */
609 break;
610
611 case I_V_IOT: /* IOT */
612 fprintf (of, "%s %-o", opcode[i], inst & 0777);
613 break;
614
615 case I_V_OP1: /* operate group 1 */
616 sp = fprint_opr (of, inst & 0361, j, 0);
617 if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
618 break;
619
620 case I_V_OP2: /* operate group 2 */
621 if (opcode[i]) fprintf (of, "%s", opcode[i]); /* skips */
622 fprint_opr (of, inst & 0206, j, opcode[i] != NULL);
623 break;
624
625 case I_V_OP3: /* operate group 3 */
626 sp = fprint_opr (of, inst & 0320, j, 0);
627 if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
628 break;
629 } /* end case */
630
631 return SCPE_OK;
632 } /* end if */
633 } /* end for */
634 return SCPE_ARG;
635 }
636
637 /* Symbolic input
638
639 Inputs:
640 *cptr = pointer to input string
641 addr = current PC
642 *uptr = pointer to unit
643 *val = pointer to output values
644 sw = switches
645 Outputs:
646 status = error status
647 */
648
649 t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
650 {
651 uint32 cflag, d, i, j, k;
652 t_stat r;
653 char gbuf[CBUFSIZE];
654
655 cflag = (uptr == NULL) || (uptr == &cpu_unit);
656 while (isspace (*cptr)) cptr++; /* absorb spaces */
657 if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
658 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
659 val[0] = (t_value) cptr[0] | 0200;
660 return SCPE_OK;
661 }
662 if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
663 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
664 val[0] = (((t_value) cptr[0] & 077) << 6) |
665 ((t_value) cptr[1] & 077);
666 return SCPE_OK;
667 }
668 if ((sw & SWMASK ('T')) || ((*cptr == '"') && cptr++)) { /* TSS8 string? */
669 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
670 val[0] = (((t_value) (cptr[0] - 040) & 077) << 6) |
671 ((t_value) (cptr[1] - 040) & 077);
672 return SCPE_OK;
673 }
674 if ((r = parse_sym_fpp (cptr, val)) != SCPE_ARG) /* FPP8 inst? */
675 return r;
676
677 /* Instruction parse */
678
679 cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
680 for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
681 if (opcode[i] == NULL) return SCPE_ARG;
682 val[0] = opc_val[i] & 07777; /* get value */
683 j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
684
685 switch (j) { /* case on class */
686
687 case I_V_IOT: /* IOT */
688 if ((cptr = parse_field (cptr, 0777, &d, 0)) == NULL)
689 return SCPE_ARG; /* get dev+pulse */
690 val[0] = val[0] | d;
691 break;
692
693 case I_V_FLD: /* field */
694 for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
695 cptr = get_glyph (cptr, gbuf, 0)) {
696 for (i = 0; (opcode[i] != NULL) &&
697 (strcmp (opcode[i], gbuf) != 0) ; i++) ;
698 if (opcode[i] != NULL) {
699 k = (opc_val[i] >> I_V_FL) & I_M_FL;
700 if (k != j) return SCPE_ARG;
701 val[0] = val[0] | (opc_val[i] & 07777);
702 }
703 else {
704 d = get_uint (gbuf, 8, 07, &r);
705 if (r != SCPE_OK) return SCPE_ARG;
706 val[0] = val[0] | (d << 3);
707 break;
708 }
709 }
710 break;
711
712 case I_V_MRF: /* mem ref */
713 cptr = get_glyph (cptr, gbuf, 0); /* get next field */
714 if (strcmp (gbuf, "I") == 0) { /* indirect? */
715 val[0] = val[0] | 0400;
716 cptr = get_glyph (cptr, gbuf, 0);
717 }
718 if ((k = (strcmp (gbuf, "C") == 0)) || (strcmp (gbuf, "Z") == 0)) {
719 if ((cptr = parse_field (cptr, 0177, &d, 0)) == NULL)
720 return SCPE_ARG;
721 val[0] = val[0] | d | (k? 0200: 0);
722 }
723 else {
724 d = get_uint (gbuf, 8, 07777, &r);
725 if (r != SCPE_OK) return SCPE_ARG;
726 if (d <= 0177) val[0] = val[0] | d;
727 else if (cflag && (((addr ^ d) & 07600) == 0))
728 val[0] = val[0] | (d & 0177) | 0200;
729 else return SCPE_ARG;
730 }
731 break;
732
733 case I_V_OP1: case I_V_OP2: case I_V_OP3: /* operates */
734 case I_V_NPN: case I_V_IOA:
735 for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
736 cptr = get_glyph (cptr, gbuf, 0)) {
737 for (i = 0; (opcode[i] != NULL) &&
738 (strcmp (opcode[i], gbuf) != 0) ; i++) ;
739 k = opc_val[i] & 07777;
740 if ((opcode[i] == NULL) || (((k ^ val[0]) & 07000) != 0))
741 return SCPE_ARG;
742 val[0] = val[0] | k;
743 }
744 break;
745 } /* end case */
746
747 if (*cptr != 0) return SCPE_ARG; /* junk at end? */
748 return SCPE_OK;
749 }
750
751 /* FPP8 instruction decode */
752
753 t_stat fprint_sym_fpp (FILE *of, t_value *val)
754 {
755 uint32 wd1, wd2, xr4b, xr3b, ad15;
756 uint32 i, j;
757 extern uint32 fpp_bra, fpp_cmd;
758
759 wd1 = (uint32) val[0] | ((fpp_cmd & 04000) << 1);
760 wd2 = (uint32) val[1];
761 xr4b = (wd1 >> 3) & 017;
762 xr3b = wd1 & 07;
763 ad15 = (xr3b << 12) | wd2;
764
765 for (i = 0; fop_val[i] >= 0; i++) { /* loop thru ops */
766 j = (fop_val[i] >> F_V_FL) & F_M_FL; /* get class */
767 if ((fop_val[i] & 017777) == (wd1 & fmasks[j])) { /* match? */
768
769 switch (j) { /* case on class */
770 case F_V_NOP12:
771 case F_V_NOP9:
772 case F_V_LTR: /* no operands */
773 fprintf (of, "%s", fopcode[i]);
774 break;
775
776 case F_V_X: /* index */
777 fprintf (of, "%s %o", fopcode[i], xr3b);
778 break;
779
780 case F_V_IMMX: /* index imm */
781 fprintf (of, "%s %-o,%o", fopcode[i], wd2, xr3b);
782 return -1; /* extra word */
783
784 case F_V_AD15: /* 15b address */
785 fprintf (of, "%s %-o", fopcode[i], ad15);
786 return -1; /* extra word */
787
788 case F_V_AD15X: /* 15b addr, indx */
789 fprintf (of, "%s %-o", fopcode[i], ad15);
790 if (xr4b >= 010)
791 fprintf (of, ",%o+", xr4b & 7);
792 else fprintf (of, ",%o", xr4b);
793 return -1; /* extra word */
794
795 case F_V_MR1D: /* 1 word direct */
796 ad15 = (fpp_bra + (3 * (wd1 & 0177))) & ADDRMASK;
797 fprintf (of, "%s %-o", fopcode[i], ad15);
798 break;
799
800 case F_V_LEMU:
801 case F_V_MR2D: /* 2 word direct */
802 fprintf (of, "%s %-o", fopcode[i], ad15);
803 if (xr4b >= 010)
804 fprintf (of, ",%o+", xr4b & 7);
805 else if (xr4b != 0)
806 fprintf (of, ",%o", xr4b);
807 return -1; /* extra word */
808
809 case F_V_LEMUI:
810 case F_V_MRI: /* indirect */
811 ad15 = (fpp_bra + (3 * xr3b)) & ADDRMASK;
812 fprintf (of, "%s %-o", fopcode[i], ad15);
813 if (xr4b >= 010)
814 fprintf (of, ",%o+", xr4b & 7);
815 else if (xr4b != 0)
816 fprintf (of, ",%o", xr4b);
817 break;
818
819 case F_V_MRD: /* encode only */
820 return SCPE_IERR;
821 }
822
823 return SCPE_OK;
824 } /* end if */
825 } /* end for */
826 return SCPE_ARG;
827 }
828
829 /* FPP8 instruction parse */
830
831 t_stat parse_sym_fpp (char *cptr, t_value *val)
832 {
833 uint32 i, j, ad, xr;
834 int32 broff, nwd;
835 char gbuf[CBUFSIZE];
836
837 cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
838 for (i = 0; (fopcode[i] != NULL) && (strcmp (fopcode[i], gbuf) != 0) ; i++) ;
839 if (fopcode[i] == NULL) return SCPE_ARG;
840 val[0] = fop_val[i] & 07777; /* get value */
841 j = (fop_val[i] >> F_V_FL) & F_M_FL; /* get class */
842 xr = 0;
843 nwd = 0;
844
845 switch (j) { /* case on class */
846
847 case F_V_NOP12:
848 case F_V_NOP9:
849 case F_V_LTR: /* no operands */
850 break;
851
852 case F_V_X: /* 3b XR */
853 if ((cptr = parse_field (cptr, 07, &xr, 0)) == NULL)
854 return SCPE_ARG;
855 val[0] |= xr;
856 break;
857
858 case F_V_IMMX: /* 12b, XR */
859 if ((cptr = parse_field (cptr, 07777, &ad, ',')) == NULL)
860 return SCPE_ARG;
861 if ((*cptr == 0) ||
862 ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL))
863 return SCPE_ARG;
864 val[0] |= xr;
865 val[++nwd] = ad;
866 break;
867
868 case F_V_AD15: /* 15b addr */
869 if ((cptr = parse_field (cptr, 077777, &ad, 0)) == NULL)
870 return SCPE_ARG;
871 val[0] |= (ad >> 12) & 07;
872 val[++nwd] = ad & 07777;
873 break;
874
875 case F_V_AD15X: /* 15b addr, idx */
876 if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
877 return SCPE_ARG;
878 if ((*cptr == 0) ||
879 ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL))
880 return SCPE_ARG;
881 val[0] |= ((xr << 3) | ((ad >> 12) & 07));
882 val[++nwd] = ad & 07777;
883 break;
884
885 case F_V_LEMUI:
886 case F_V_MRI: /* indirect */
887 if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
888 return SCPE_ARG;
889 if ((*cptr != 0) &&
890 ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))
891 return SCPE_ARG;
892 if ((broff = test_fpp_addr (ad, 07)) < 0)
893 return SCPE_ARG;
894 val[0] |= ((xr << 3) | broff);
895 break;
896
897 case F_V_MRD: /* direct */
898 if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
899 return SCPE_ARG;
900 if (((broff = test_fpp_addr (ad, 0177)) < 0) ||
901 (*cptr != 0)) {
902 if ((*cptr != 0) &&
903 ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))
904 return SCPE_ARG;
905 val[0] |= (00400 | (xr << 3) | ((ad >> 12) & 07));
906 val[++nwd] = ad & 07777;
907 }
908 else val[0] |= (00200 | broff);
909 break;
910
911 case F_V_LEMU:
912 if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
913 return SCPE_ARG;
914 if ((*cptr != 0) &&
915 ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))
916 return SCPE_ARG;
917 val[0] |= ((xr << 3) | ((ad >> 12) & 07));
918 val[++nwd] = ad & 07777;
919 break;
920
921 case F_V_MR1D:
922 case F_V_MR2D:
923 return SCPE_IERR;
924 } /* end case */
925
926 if (*cptr != 0) return SCPE_ARG; /* junk at end? */
927 return -nwd;
928 }
929
930 /* Parse field */
931
932 char *parse_field (char *cptr, uint32 max, uint32 *val, uint32 c)
933 {
934 char gbuf[CBUFSIZE];
935 t_stat r;
936
937 cptr = get_glyph (cptr, gbuf, c); /* get field */
938 *val = get_uint (gbuf, 8, max, &r);
939 if (r != SCPE_OK)
940 return NULL;
941 return cptr;
942 }
943
944 /* Parse index register */
945
946 char *parse_fpp_xr (char *cptr, uint32 *xr, t_bool inc)
947 {
948 char gbuf[CBUFSIZE];
949 uint32 len;
950 t_stat r;
951
952 cptr = get_glyph (cptr, gbuf, 0); /* get field */
953 len = strlen (gbuf);
954 if (gbuf[len - 1] == '+') {
955 if (!inc)
956 return NULL;
957 gbuf[len - 1] = 0;
958 *xr = 010;
959 }
960 else *xr = 0;
961 *xr += get_uint (gbuf, 8, 7, &r);
962 if (r != SCPE_OK)
963 return NULL;
964 return cptr;
965 }
966
967 /* Test address in range of base register */
968
969 int32 test_fpp_addr (uint32 ad, uint32 max)
970 {
971 uint32 off;
972 extern uint32 fpp_bra;
973
974 off = ad - fpp_bra;
975 if (((off % 3) != 0) ||
976 (off > (max * 3)))
977 return -1;
978 return ((int32) off / 3);
979 }