First Commit of my working state
[simh.git] / PDP11 / pdp11_sys.c
1 /* pdp11_sys.c: PDP-11 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 15-May-08 RMS Added KE11-A, DC11 support
27 Renamed DL11
28 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices
29 25-Jan-08 RMS Added RC11, KG11A support from John Dundas
30 10-Sep-07 RMS Cleaned up binary loader
31 20-Dec-06 RMS Added TA11 support
32 12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller)
33 14-Jul-06 RMS Reordered device list
34 06-Jul-06 RMS Added multiple KL11/DL11 support
35 26-Jun-06 RMS Added RF11 support
36 17-May-06 RMS Added CR11/CD11 support (from John Dundas)
37 16-Aug-05 RMS Fixed C++ declaration and cast problems
38 22-Jul-05 RMS Fixed missing , in initializer (from Doug Gwyn)
39 22-Dec-03 RMS Added second DEUNA/DELUA support
40 18-Oct-03 RMS Added DECtape off reel message
41 06-May-03 RMS Added support for second DEQNA/DELQA
42 09-Jan-03 RMS Added DELUA/DEUNA support
43 17-Oct-02 RMS Fixed bugs in branch, SOB address parsing
44 09-Oct-02 RMS Added DELQA support
45 12-Sep-02 RMS Added TMSCP, KW11P, RX211 support, RAD50 examine
46 29-Nov-01 RMS Added read only unit support
47 17-Sep-01 RMS Removed multiconsole support
48 26-Aug-01 RMS Added DZ11
49 20-Aug-01 RMS Updated bad block inquiry
50 17-Jul-01 RMS Fixed warning from VC++ 6.0
51 27-May-01 RMS Added multiconsole support
52 05-Apr-01 RMS Added support for TS11/TSV05
53 14-Mar-01 RMS Revised load/dump interface (again)
54 11-Feb-01 RMS Added DECtape support
55 30-Oct-00 RMS Added support for examine to file
56 14-Apr-99 RMS Changed t_addr to unsigned
57 09-Nov-98 RMS Fixed assignments of ROR/ROL (John Wilson)
58 27-Oct-98 RMS V2.4 load interface
59 08-Oct-98 RMS Fixed bug in bad block routine
60 30-Mar-98 RMS Fixed bug in floating point display
61 12-Nov-97 RMS Added bad block table routine
62 */
63
64 #include "pdp11_defs.h"
65 #include <ctype.h>
66
67 extern DEVICE cpu_dev;
68 extern DEVICE sys_dev;
69 extern DEVICE ptr_dev;
70 extern DEVICE ptp_dev;
71 extern DEVICE tti_dev;
72 extern DEVICE tto_dev;
73 extern DEVICE lpt_dev;
74 extern DEVICE cr_dev;
75 extern DEVICE clk_dev;
76 extern DEVICE pclk_dev;
77 extern DEVICE dli_dev;
78 extern DEVICE dlo_dev;
79 extern DEVICE dci_dev;
80 extern DEVICE dco_dev;
81 extern DEVICE dz_dev;
82 extern DEVICE vh_dev;
83 extern DEVICE dt_dev;
84 extern DEVICE rc_dev;
85 extern DEVICE rf_dev;
86 extern DEVICE rk_dev;
87 extern DEVICE rl_dev;
88 extern DEVICE hk_dev;
89 extern DEVICE rx_dev;
90 extern DEVICE ry_dev;
91 extern DEVICE mba_dev[];
92 extern DEVICE rp_dev;
93 extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev;
94 extern DEVICE tm_dev;
95 extern DEVICE tq_dev;
96 extern DEVICE ts_dev;
97 extern DEVICE tu_dev;
98 extern DEVICE ta_dev;
99 extern DEVICE xq_dev, xqb_dev;
100 extern DEVICE xu_dev, xub_dev;
101 extern DEVICE ke_dev;
102 extern DEVICE kg_dev;
103 extern UNIT cpu_unit;
104 extern REG cpu_reg[];
105 extern uint16 *M;
106 extern int32 saved_PC;
107
108 /* SCP data structures and interface routines
109
110 sim_name simulator name string
111 sim_PC pointer to saved PC register descriptor
112 sim_emax number of words for examine
113 sim_devices array of pointers to simulated devices
114 sim_stop_messages array of pointers to stop messages
115 sim_load binary loader
116 */
117
118 char sim_name[] = "PDP-11";
119
120 REG *sim_PC = &cpu_reg[0];
121
122 int32 sim_emax = 4;
123
124 DEVICE *sim_devices[] = {
125 &cpu_dev,
126 &sys_dev,
127 &mba_dev[0],
128 &mba_dev[1],
129 &clk_dev,
130 &pclk_dev,
131 &ptr_dev,
132 &ptp_dev,
133 &tti_dev,
134 &tto_dev,
135 &cr_dev,
136 &lpt_dev,
137 &dli_dev,
138 &dlo_dev,
139 &dci_dev,
140 &dco_dev,
141 &dz_dev,
142 &vh_dev,
143 &rc_dev,
144 &rf_dev,
145 &rk_dev,
146 &rl_dev,
147 &hk_dev,
148 &rx_dev,
149 &ry_dev,
150 &rp_dev,
151 &rq_dev,
152 &rqb_dev,
153 &rqc_dev,
154 &rqd_dev,
155 &dt_dev,
156 &tm_dev,
157 &ts_dev,
158 &tq_dev,
159 &tu_dev,
160 &ta_dev,
161 &xq_dev,
162 &xqb_dev,
163 &xu_dev,
164 &xub_dev,
165 &ke_dev,
166 &kg_dev,
167 NULL
168 };
169
170 const char *sim_stop_messages[] = {
171 "Unknown error",
172 "Red stack trap",
173 "Odd address trap",
174 "Memory management trap",
175 "Non-existent memory trap",
176 "Parity error trap",
177 "Privilege trap",
178 "Illegal instruction trap",
179 "BPT trap",
180 "IOT trap",
181 "EMT trap",
182 "TRAP trap",
183 "Trace trap",
184 "Yellow stack trap",
185 "Powerfail trap",
186 "Floating point exception",
187 "HALT instruction",
188 "Breakpoint",
189 "Wait state",
190 "Trap vector fetch abort",
191 "Trap stack push abort",
192 "RQDX3 consistency error",
193 "Sanity timer expired",
194 "DECtape off reel"
195 };
196
197 /* Binary loader.
198
199 Loader format consists of blocks, optionally preceded, separated, and
200 followed by zeroes. Each block consists of:
201
202 001 ---
203 xxx |
204 lo_count |
205 hi_count |
206 lo_origin > count bytes
207 hi_origin |
208 data byte |
209 : |
210 data byte ---
211 checksum
212
213 If the byte count is exactly six, the block is the last on the tape, and
214 there is no checksum. If the origin is not 000001, then the origin is
215 the PC at which to start the program.
216 */
217
218 t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
219 {
220 int32 c[6], d, i, cnt, csum;
221 uint32 org;
222
223 if ((*cptr != 0) || (flag != 0))
224 return SCPE_ARG;
225 do { /* block loop */
226 csum = 0; /* init checksum */
227 for (i = 0; i < 6; ) { /* 6 char header */
228 if ((c[i] = getc (fileref)) == EOF)
229 return SCPE_FMT;
230 if ((i != 0) || (c[i] == 1)) /* 1st must be 1 */
231 csum = csum + c[i++]; /* add into csum */
232 }
233 cnt = (c[3] << 8) | c[2]; /* count */
234 org = (c[5] << 8) | c[4]; /* origin */
235 if (cnt < 6) /* invalid? */
236 return SCPE_FMT;
237 if (cnt == 6) { /* end block? */
238 if (org != 1) /* set PC? */
239 saved_PC = org & 0177776;
240 return SCPE_OK;
241 }
242 for (i = 6; i < cnt; i++) { /* exclude hdr */
243 if ((d = getc (fileref)) == EOF) /* data char */
244 return SCPE_FMT;
245 csum = csum + d; /* add into csum */
246 if (org >= MEMSIZE) /* invalid addr? */
247 return SCPE_NXM;
248 M[org >> 1] = (org & 1)? /* store data */
249 (M[org >> 1] & 0377) | (d << 8):
250 (M[org >> 1] & 0177400) | d;
251 org = (org + 1) & 0177777; /* inc origin */
252 }
253 if ((d = getc (fileref)) == EOF) /* get csum */
254 return SCPE_FMT;
255 csum = csum + d; /* add in */
256 } while ((csum & 0377) == 0); /* result mbz */
257 return SCPE_CSUM;
258 }
259
260 /* Factory bad block table creation routine
261
262 This routine writes a DEC standard 044 compliant bad block table on the
263 last track of the specified unit. The bad block table consists of 10
264 repetitions of the same table, formatted as follows:
265
266 words 0-1 pack id number
267 words 2-3 cylinder/sector/surface specifications
268 :
269 words n-n+1 end of table (-1,-1)
270
271 Inputs:
272 uptr = pointer to unit
273 sec = number of sectors per surface
274 wds = number of words per sector
275 Outputs:
276 sta = status code
277 */
278
279 t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds)
280 {
281 int32 i, da;
282 uint16 *buf;
283
284 if ((sec < 2) || (wds < 16))
285 return SCPE_ARG;
286 if ((uptr->flags & UNIT_ATT) == 0)
287 return SCPE_UNATT;
288 if (uptr->flags & UNIT_RO)
289 return SCPE_RO;
290 if (!get_yn ("Create bad block table on last track? [N]", FALSE))
291 return SCPE_OK;
292 da = (uptr->capac - (sec * wds)) * sizeof (uint16);
293 if (fseek (uptr->fileref, da, SEEK_SET))
294 return SCPE_IOERR;
295 if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL)
296 return SCPE_MEM;
297 buf[0] = buf[1] = 012345u;
298 buf[2] = buf[3] = 0;
299 for (i = 4; i < wds; i++) buf[i] = 0177777u;
300 for (i = 0; (i < sec) && (i < 10); i++)
301 fxwrite (buf, sizeof (uint16), wds, uptr->fileref);
302 free (buf);
303 if (ferror (uptr->fileref))
304 return SCPE_IOERR;
305 return SCPE_OK;
306 }
307
308 /* Symbol tables */
309
310 #define I_V_L 16 /* long mode */
311 #define I_V_D 17 /* double mode */
312 #define I_L (1 << I_V_L)
313 #define I_D (1 << I_V_D)
314
315 /* Warning: for literals, the class number MUST equal the field width!! */
316
317 #define I_V_CL 18 /* class bits */
318 #define I_M_CL 037 /* class mask */
319 #define I_V_NPN 0 /* no operands */
320 #define I_V_REG 1 /* reg */
321 #define I_V_SOP 2 /* operand */
322 #define I_V_3B 3 /* 3b literal */
323 #define I_V_FOP 4 /* flt operand */
324 #define I_V_AFOP 5 /* fac, flt operand */
325 #define I_V_6B 6 /* 6b literal */
326 #define I_V_BR 7 /* cond branch */
327 #define I_V_8B 8 /* 8b literal */
328 #define I_V_SOB 9 /* reg, disp */
329 #define I_V_RSOP 10 /* reg, operand */
330 #define I_V_ASOP 11 /* fac, operand */
331 #define I_V_ASMD 12 /* fac, moded int op */
332 #define I_V_DOP 13 /* double operand */
333 #define I_V_CCC 14 /* CC clear */
334 #define I_V_CCS 15 /* CC set */
335 #define I_V_SOPR 16 /* operand, reg */
336 #define I_NPN (I_V_NPN << I_V_CL)
337 #define I_REG (I_V_REG << I_V_CL)
338 #define I_3B (I_V_3B << I_V_CL)
339 #define I_SOP (I_V_SOP << I_V_CL)
340 #define I_FOP (I_V_FOP << I_V_CL)
341 #define I_6B (I_V_6B << I_V_CL)
342 #define I_BR (I_V_BR << I_V_CL)
343 #define I_8B (I_V_8B << I_V_CL)
344 #define I_AFOP (I_V_AFOP << I_V_CL)
345 #define I_ASOP (I_V_ASOP << I_V_CL)
346 #define I_RSOP (I_V_RSOP << I_V_CL)
347 #define I_SOB (I_V_SOB << I_V_CL)
348 #define I_ASMD (I_V_ASMD << I_V_CL)
349 #define I_DOP (I_V_DOP << I_V_CL)
350 #define I_CCC (I_V_CCC << I_V_CL)
351 #define I_CCS (I_V_CCS << I_V_CL)
352 #define I_SOPR (I_V_SOPR << I_V_CL)
353
354 static const int32 masks[] = {
355 0177777, 0177770, 0177700, 0177770,
356 0177700+I_D, 0177400+I_D, 0177700, 0177400,
357 0177400, 0177000, 0177000, 0177400,
358 0177400+I_D+I_L, 0170000, 0177777, 0177777,
359 0177000
360 };
361
362 static const char *opcode[] = {
363 "HALT","WAIT","RTI","BPT",
364 "IOT","RESET","RTT","MFPT",
365 "JMP","RTS","SPL",
366 "NOP","CLC","CLV","CLV CLC",
367 "CLZ","CLZ CLC","CLZ CLV","CLZ CLV CLC",
368 "CLN","CLN CLC","CLN CLV","CLN CLV CLC",
369 "CLN CLZ","CLN CLZ CLC","CLN CLZ CLC","CCC",
370 "NOP","SEC","SEV","SEV SEC",
371 "SEZ","SEZ SEC","SEZ SEV","SEZ SEV SEC",
372 "SEN","SEN SEC","SEN SEV","SEN SEV SEC",
373 "SEN SEZ","SEN SEZ SEC","SEN SEZ SEC","SCC",
374 "SWAB","BR","BNE","BEQ",
375 "BGE","BLT","BGT","BLE",
376 "JSR",
377 "CLR","COM","INC","DEC",
378 "NEG","ADC","SBC","TST",
379 "ROR","ROL","ASR","ASL",
380 "MARK","MFPI","MTPI","SXT",
381 "CSM", "TSTSET","WRTLCK",
382 "MOV","CMP","BIT","BIC",
383 "BIS","ADD",
384 "MUL","DIV","ASH","ASHC",
385 "XOR",
386 "FADD","FSUB","FMUL","FDIV",
387 "L2DR",
388 "MOVC","MOVRC","MOVTC",
389 "LOCC","SKPC","SCANC","SPANC",
390 "CMPC","MATC",
391 "ADDN","SUBN","CMPN","CVTNL",
392 "CVTPN","CVTNP","ASHN","CVTLN",
393 "L3DR",
394 "ADDP","SUBP","CMPP","CVTPL",
395 "MULP","DIVP","ASHP","CVTLP",
396 "MOVCI","MOVRCI","MOVTCI",
397 "LOCCI","SKPCI","SCANCI","SPANCI",
398 "CMPCI","MATCI",
399 "ADDNI","SUBNI","CMPNI","CVTNLI",
400 "CVTPNI","CVTNPI","ASHNI","CVTLNI",
401 "ADDPI","SUBPI","CMPPI","CVTPLI",
402 "MULPI","DIVPI","ASHPI","CVTLPI",
403 "SOB",
404 "BPL","BMI","BHI","BLOS",
405 "BVC","BVS","BCC","BCS",
406 "BHIS","BLO", /* encode only */
407 "EMT","TRAP",
408 "CLRB","COMB","INCB","DECB",
409 "NEGB","ADCB","SBCB","TSTB",
410 "RORB","ROLB","ASRB","ASLB",
411 "MTPS","MFPD","MTPD","MFPS",
412 "MOVB","CMPB","BITB","BICB",
413 "BISB","SUB",
414 "CFCC","SETF","SETI","SETD","SETL",
415 "LDFPS","STFPS","STST",
416 "CLRF","CLRD","TSTF","TSTD",
417 "ABSF","ABSD","NEGF","NEGD",
418 "MULF","MULD","MODF","MODD",
419 "ADDF","ADDD","LDF","LDD",
420 "SUBF","SUBD","CMPF","CMPD",
421 "STF","STD","DIVF","DIVD",
422 "STEXP",
423 "STCFI","STCDI","STCFL","STCDL",
424 "STCFD","STCDF",
425 "LDEXP",
426 "LDCIF","LDCID","LDCLF","LDCLD",
427 "LDCFD","LDCDF",
428 NULL
429 };
430
431 static const int32 opc_val[] = {
432 0000000+I_NPN, 0000001+I_NPN, 0000002+I_NPN, 0000003+I_NPN,
433 0000004+I_NPN, 0000005+I_NPN, 0000006+I_NPN, 0000007+I_NPN,
434 0000100+I_SOP, 0000200+I_REG, 0000230+I_3B,
435 0000240+I_CCC, 0000241+I_CCC, 0000242+I_CCC, 0000243+I_NPN,
436 0000244+I_CCC, 0000245+I_NPN, 0000246+I_NPN, 0000247+I_NPN,
437 0000250+I_CCC, 0000251+I_NPN, 0000252+I_NPN, 0000253+I_NPN,
438 0000254+I_NPN, 0000255+I_NPN, 0000256+I_NPN, 0000257+I_CCC,
439 0000260+I_CCS, 0000261+I_CCS, 0000262+I_CCS, 0000263+I_NPN,
440 0000264+I_CCS, 0000265+I_NPN, 0000266+I_NPN, 0000267+I_NPN,
441 0000270+I_CCS, 0000271+I_NPN, 0000272+I_NPN, 0000273+I_NPN,
442 0000274+I_NPN, 0000275+I_NPN, 0000276+I_NPN, 0000277+I_CCS,
443 0000300+I_SOP, 0000400+I_BR, 0001000+I_BR, 0001400+I_BR,
444 0002000+I_BR, 0002400+I_BR, 0003000+I_BR, 0003400+I_BR,
445 0004000+I_RSOP,
446 0005000+I_SOP, 0005100+I_SOP, 0005200+I_SOP, 0005300+I_SOP,
447 0005400+I_SOP, 0005500+I_SOP, 0005600+I_SOP, 0005700+I_SOP,
448 0006000+I_SOP, 0006100+I_SOP, 0006200+I_SOP, 0006300+I_SOP,
449 0006400+I_6B, 0006500+I_SOP, 0006600+I_SOP, 0006700+I_SOP,
450 0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP,
451 0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP,
452 0050000+I_DOP, 0060000+I_DOP,
453 0070000+I_SOPR, 0071000+I_SOPR, 0072000+I_SOPR, 0073000+I_SOPR,
454 0074000+I_RSOP,
455 0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG,
456 0076020+I_REG,
457 0076030+I_NPN, 0076031+I_NPN, 0076032+I_NPN,
458 0076040+I_NPN, 0076041+I_NPN, 0076042+I_NPN, 0076043+I_NPN,
459 0076044+I_NPN, 0076045+I_NPN,
460 0076050+I_NPN, 0076051+I_NPN, 0076052+I_NPN, 0076053+I_NPN,
461 0076054+I_NPN, 0076055+I_NPN, 0076056+I_NPN, 0076057+I_NPN,
462 0076060+I_REG,
463 0076070+I_NPN, 0076071+I_NPN, 0076072+I_NPN, 0076073+I_NPN,
464 0076074+I_NPN, 0076075+I_NPN, 0076076+I_NPN, 0076077+I_NPN,
465 0076130+I_NPN, 0076131+I_NPN, 0076132+I_NPN,
466 0076140+I_NPN, 0076141+I_NPN, 0076142+I_NPN, 0076143+I_NPN,
467 0076144+I_NPN, 0076145+I_NPN,
468 0076150+I_NPN, 0076151+I_NPN, 0076152+I_NPN, 0076153+I_NPN,
469 0076154+I_NPN, 0076155+I_NPN, 0076156+I_NPN, 0076157+I_NPN,
470 0076170+I_NPN, 0076171+I_NPN, 0076172+I_NPN, 0076173+I_NPN,
471 0076174+I_NPN, 0076175+I_NPN, 0076176+I_NPN, 0076177+I_NPN,
472 0077000+I_SOB,
473 0100000+I_BR, 0100400+I_BR, 0101000+I_BR, 0101400+I_BR,
474 0102000+I_BR, 0102400+I_BR, 0103000+I_BR, 0103400+I_BR,
475 0103000+I_BR, 0103400+I_BR,
476 0104000+I_8B, 0104400+I_8B,
477 0105000+I_SOP, 0105100+I_SOP, 0105200+I_SOP, 0105300+I_SOP,
478 0105400+I_SOP, 0105500+I_SOP, 0105600+I_SOP, 0105700+I_SOP,
479 0106000+I_SOP, 0106100+I_SOP, 0106200+I_SOP, 0106300+I_SOP,
480 0106400+I_SOP, 0106500+I_SOP, 0106600+I_SOP, 0106700+I_SOP,
481 0110000+I_DOP, 0120000+I_DOP, 0130000+I_DOP, 0140000+I_DOP,
482 0150000+I_DOP, 0160000+I_DOP,
483 0170000+I_NPN, 0170001+I_NPN, 0170002+I_NPN, 0170011+I_NPN, 0170012+I_NPN,
484 0170100+I_SOP, 0170200+I_SOP, 0170300+I_SOP,
485 0170400+I_FOP, 0170400+I_FOP+I_D, 0170500+I_FOP, 0170500+I_FOP+I_D,
486 0170600+I_FOP, 0170600+I_FOP+I_D, 0170700+I_FOP, 0170700+I_FOP+I_D,
487 0171000+I_AFOP, 0171000+I_AFOP+I_D, 0171400+I_AFOP, 0171400+I_AFOP+I_D,
488 0172000+I_AFOP, 0172000+I_AFOP+I_D, 0172400+I_AFOP, 0172400+I_AFOP+I_D,
489 0173000+I_AFOP, 0173000+I_AFOP+I_D, 0173400+I_AFOP, 0173400+I_AFOP+I_D,
490 0174000+I_AFOP, 0174000+I_AFOP+I_D, 0174400+I_AFOP, 0174400+I_AFOP+I_D,
491 0175000+I_ASOP,
492 0175400+I_ASMD, 0175400+I_ASMD+I_D, 0175400+I_ASMD+I_L, 0175400+I_ASMD+I_D+I_L,
493 0176000+I_AFOP, 0176000+I_AFOP+I_D,
494 0176400+I_ASOP,
495 0177000+I_ASMD, 0177000+I_ASMD+I_D, 0177000+I_ASMD+I_L, 0177000+I_ASMD+I_D+I_L,
496 0177400+I_AFOP, 0177400+I_AFOP+I_D,
497 -1
498 };
499
500 static const char *rname [] = {
501 "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC"
502 };
503
504 static const char *fname [] = {
505 "F0", "F1", "F2", "F3", "F4", "F5", "?6", "?7"
506 };
507
508 static const char r50_to_asc[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
509
510 /* Specifier decode
511
512 Inputs:
513 *of = output stream
514 addr = current PC
515 spec = specifier
516 nval = next word
517 flag = TRUE if decoding for CPU
518 iflag = TRUE if decoding integer instruction
519 Outputs:
520 count = -number of extra words retired
521 */
522
523 int32 fprint_spec (FILE *of, t_addr addr, int32 spec, t_value nval,
524 int32 flag, int32 iflag)
525 {
526 int32 reg, mode;
527 static const int32 rgwd[8] = { 0, 0, 0, 0, 0, 0, -1, -1 };
528 static const int32 pcwd[8] = { 0, 0, -1, -1, 0, 0, -1, -1 };
529
530 reg = spec & 07;
531 mode = ((spec >> 3) & 07);
532 switch (mode) {
533
534 case 0:
535 if (iflag)
536 fprintf (of, "%s", rname[reg]);
537 else fprintf (of, "%s", fname[reg]);
538 break;
539
540 case 1:
541 fprintf (of, "(%s)", rname[reg]);
542 break;
543
544 case 2:
545 if (reg != 7)
546 fprintf (of, "(%s)+", rname[reg]);
547 else fprintf (of, "#%-o", nval);
548 break;
549
550 case 3:
551 if (reg != 7)
552 fprintf (of, "@(%s)+", rname[reg]);
553 else fprintf (of, "@#%-o", nval);
554 break;
555
556 case 4:
557 fprintf (of, "-(%s)", rname[reg]);
558 break;
559
560 case 5:
561 fprintf (of, "@-(%s)", rname[reg]);
562 break;
563
564 case 6:
565 if ((reg != 7) || !flag)
566 fprintf (of, "%-o(%s)", nval, rname[reg]);
567 else fprintf (of, "%-o", (nval + addr + 4) & 0177777);
568 break;
569
570 case 7:
571 if ((reg != 7) || !flag)
572 fprintf (of, "@%-o(%s)", nval, rname[reg]);
573 else fprintf (of, "@%-o", (nval + addr + 4) & 0177777);
574 break;
575 } /* end case */
576
577 return ((reg == 07)? pcwd[mode]: rgwd[mode]);
578 }
579
580 /* Symbolic decode
581
582 Inputs:
583 *of = output stream
584 addr = current PC
585 *val = values to decode
586 *uptr = pointer to unit
587 sw = switches
588 Outputs:
589 return = if >= 0, error code
590 if < 0, number of extra words retired
591 */
592
593 t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
594 UNIT *uptr, int32 sw)
595 {
596 int32 cflag, i, j, c1, c2, c3, inst, fac, srcm, srcr, dstm, dstr;
597 int32 bflag, l8b, brdisp, wd1, wd2;
598 extern int32 FPS;
599
600 bflag = 0; /* assume 16b */
601 cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */
602 if (!cflag) { /* not cpu? */
603 DEVICE *dptr = find_dev_from_unit (uptr);
604 if (dptr == NULL)
605 return SCPE_IERR;
606 if (dptr->dwidth < 16)
607 bflag = 1;
608 }
609
610 if (sw & SWMASK ('A')) { /* ASCII? */
611 if (bflag)
612 c1 = val[0] & 0177;
613 else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0177;
614 fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
615 return 0;
616 }
617 if (sw & SWMASK ('B')) { /* byte? */
618 if (bflag)
619 c1 = val[0] & 0177;
620 else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0377;
621 fprintf (of, "%o", c1);
622 return 0;
623 }
624 if (bflag) return SCPE_ARG; /* 16b only */
625
626 if (sw & SWMASK ('C')) { /* character? */
627 c1 = val[0] & 0177;
628 c2 = (val[0] >> 8) & 0177;
629 fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
630 fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
631 return -1;
632 }
633 if (sw & SWMASK ('R')) { /* radix 50? */
634 if (val[0] > 0174777) return SCPE_ARG; /* max value */
635 c3 = val[0] % 050;
636 c2 = (val[0] / 050) % 050;
637 c1 = val[0] / (050 * 050);
638 fprintf (of, "%c%c%c", r50_to_asc[c1],
639 r50_to_asc[c2], r50_to_asc[c3]);
640 return -1;
641 }
642 if (!(sw & SWMASK ('M'))) return SCPE_ARG;
643
644 inst = val[0] | ((FPS << (I_V_L - FPS_V_L)) & I_L) |
645 ((FPS << (I_V_D - FPS_V_D)) & I_D); /* inst + fp mode */
646 for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
647 j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */
648 if ((opc_val[i] & 0777777) == (inst & masks[j])) { /* match? */
649 srcm = (inst >> 6) & 077; /* opr fields */
650 srcr = srcm & 07;
651 fac = srcm & 03;
652 dstm = inst & 077;
653 dstr = dstm & 07;
654 l8b = inst & 0377;
655 wd1 = wd2 = 0;
656 switch (j) { /* case on class */
657
658 case I_V_NPN: case I_V_CCC: case I_V_CCS: /* no operands */
659 fprintf (of, "%s", opcode[i]);
660 break;
661
662 case I_V_REG: /* reg */
663 fprintf (of, "%s %-s", opcode[i], rname[dstr]);
664 break;
665
666 case I_V_SOP: /* sop */
667 fprintf (of, "%s ", opcode[i]);
668 wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
669 break;
670
671 case I_V_3B: /* 3b */
672 fprintf (of, "%s %-o", opcode[i], dstr);
673 break;
674
675 case I_V_FOP: /* fop */
676 fprintf (of, "%s ", opcode[i]);
677 wd1 = fprint_spec (of, addr, dstm, val[1], cflag, FALSE);
678 break;
679
680 case I_V_AFOP: /* afop */
681 fprintf (of, "%s %s,", opcode[i], fname[fac]);
682 wd1 = fprint_spec (of, addr, dstm, val[1], cflag, FALSE);
683 break;
684
685 case I_V_6B: /* 6b */
686 fprintf (of, "%s %-o", opcode[i], dstm);
687 break;
688
689 case I_V_BR: /* cond branch */
690 fprintf (of, "%s ", opcode[i]);
691 brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777;
692 if (cflag)
693 fprintf (of, "%-o", (addr + brdisp) & 0177777);
694 else if (brdisp < 01000)
695 fprintf (of, ".+%-o", brdisp);
696 else fprintf (of, ".-%-o", 0200000 - brdisp);
697 break;
698
699 case I_V_8B: /* 8b */
700 fprintf (of, "%s %-o", opcode[i], l8b);
701 break;
702
703 case I_V_SOB: /* sob */
704 fprintf (of, "%s %s,", opcode[i], rname[srcr]);
705 brdisp = (dstm * 2) - 2;
706 if (cflag)
707 fprintf (of, "%-o", (addr - brdisp) & 0177777);
708 else if (brdisp <= 0)
709 fprintf (of, ".+%-o", -brdisp);
710 else fprintf (of, ".-%-o", brdisp);
711 break;
712
713 case I_V_RSOP: /* rsop */
714 fprintf (of, "%s %s,", opcode[i], rname[srcr]);
715 wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
716 break;
717
718 case I_V_SOPR: /* sopr */
719 fprintf (of, "%s ", opcode[i]);
720 wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
721 fprintf (of, ",%s", rname[srcr]);
722 break;
723
724 case I_V_ASOP: case I_V_ASMD: /* asop, asmd */
725 fprintf (of, "%s %s,", opcode[i], fname[fac]);
726 wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
727 break;
728
729 case I_V_DOP: /* dop */
730 fprintf (of, "%s ", opcode[i]);
731 wd1 = fprint_spec (of, addr, srcm, val[1], cflag, TRUE);
732 fprintf (of, ",");
733 wd2 = fprint_spec (of, addr - wd1 - wd1, dstm,
734 val[1 - wd1], cflag, TRUE);
735 break;
736 } /* end case */
737 return ((wd1 + wd2) * 2) - 1;
738 } /* end if */
739 } /* end for */
740 return SCPE_ARG; /* no match */
741 }
742
743 #define A_PND 100 /* # seen */
744 #define A_MIN 040 /* -( seen */
745 #define A_PAR 020 /* (Rn) seen */
746 #define A_REG 010 /* Rn seen */
747 #define A_PLS 004 /* + seen */
748 #define A_NUM 002 /* number seen */
749 #define A_REL 001 /* relative addr seen */
750
751 /* Register number
752
753 Inputs:
754 *cptr = pointer to input string
755 *strings = pointer to register names
756 mchar = character to match after register name
757 Outputs:
758 rnum = 0..7 if a legitimate register
759 < 0 if error
760 */
761
762 int32 get_reg (char *cptr, const char *strings[], char mchar)
763 {
764 int32 i;
765
766 if (*(cptr + 2) != mchar) return -1;
767 for (i = 0; i < 8; i++) {
768 if (strncmp (cptr, strings[i], 2) == 0)
769 return i;
770 }
771 return -1;
772 }
773
774 /* Number or memory address
775
776 Inputs:
777 *cptr = pointer to input string
778 *dptr = pointer to output displacement
779 *pflag = pointer to accumulating flags
780 Outputs:
781 cptr = pointer to next character in input string
782 NULL if parsing error
783
784 Flags: 0 (no result), A_NUM (number), A_REL (relative)
785 */
786
787 char *get_addr (char *cptr, int32 *dptr, int32 *pflag)
788 {
789 int32 val, minus;
790 char *tptr;
791
792 minus = 0;
793
794 if (*cptr == '.') { /* relative? */
795 *pflag = *pflag | A_REL;
796 cptr++;
797 }
798 if (*cptr == '+') { /* +? */
799 *pflag = *pflag | A_NUM;
800 cptr++;
801 }
802 if (*cptr == '-') { /* -? */
803 *pflag = *pflag | A_NUM;
804 minus = 1;
805 cptr++;
806 }
807 errno = 0;
808 val = strtoul (cptr, &tptr, 8);
809 if (cptr == tptr) { /* no number? */
810 if (*pflag == (A_REL + A_NUM)) /* .+, .-? */
811 return NULL;
812 *dptr = 0;
813 return cptr;
814 }
815 if (errno || (*pflag == A_REL)) /* .n? */
816 return NULL;
817 *dptr = (minus? -val: val) & 0177777;
818 *pflag = *pflag | A_NUM;
819 return tptr;
820 }
821
822 /* Specifier decode
823
824 Inputs:
825 *cptr = pointer to input string
826 addr = current PC
827 n1 = 0 if no extra word used
828 -1 if extra word used in prior decode
829 *sptr = pointer to output specifier
830 *dptr = pointer to output displacement
831 cflag = true if parsing for the CPU
832 iflag = true if integer specifier
833 Outputs:
834 status = = -1 extra word decoded
835 = 0 ok
836 = +1 error
837 */
838
839 t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr,
840 int32 cflag, int32 iflag)
841 {
842 int32 reg, indir, pflag, disp;
843
844 indir = 0; /* no indirect */
845 pflag = 0;
846
847 if (*cptr == '@') { /* indirect? */
848 indir = 010;
849 cptr++;
850 }
851 if (*cptr == '#') { /* literal? */
852 pflag = pflag | A_PND;
853 cptr++;
854 }
855 if (strncmp (cptr, "-(", 2) == 0) { /* autodecrement? */
856 pflag = pflag | A_MIN;
857 cptr++;
858 }
859 else if ((cptr = get_addr (cptr, &disp, &pflag)) == NULL) return 1;
860 if (*cptr == '(') { /* register index? */
861 pflag = pflag | A_PAR;
862 if ((reg = get_reg (cptr + 1, rname, ')')) < 0)
863 return 1;
864 cptr = cptr + 4;
865 if (*cptr == '+') { /* autoincrement? */
866 pflag = pflag | A_PLS;
867 cptr++;
868 }
869 }
870 else if ((reg = get_reg (cptr, iflag? rname: fname, 0)) >= 0) {
871 pflag = pflag | A_REG;
872 cptr = cptr + 2;
873 }
874 if (*cptr != 0) /* all done? */
875 return 1;
876 switch (pflag) { /* case on syntax */
877
878 case A_REG: /* Rn, @Rn */
879 *sptr = indir + reg;
880 return 0;
881
882 case A_PAR: /* (Rn), @(Rn) */
883 if (indir) { /* @(Rn) = @0(Rn) */
884 *sptr = 070 + reg;
885 *dptr = 0;
886 return -1;
887 }
888 else *sptr = 010 + reg;
889 return 0;
890
891 case A_PAR+A_PLS: /* (Rn)+, @(Rn)+ */
892 *sptr = 020 + indir + reg;
893 return 0;
894
895 case A_MIN+A_PAR: /* -(Rn), @-(Rn) */
896 *sptr = 040 + indir + reg;
897 return 0;
898
899 case A_NUM+A_PAR: /* d(Rn), @d(Rn) */
900 *sptr = 060 + indir + reg;
901 *dptr = disp;
902 return -1;
903
904 case A_PND+A_REL: case A_PND+A_REL+A_NUM: /* #.+n, @#.+n */
905 if (!cflag)
906 return 1;
907 disp = (disp + addr) & 0177777; /* fall through */
908 case A_PND+A_NUM: /* #n, @#n */
909 *sptr = 027 + indir;
910 *dptr = disp;
911 return -1;
912
913 case A_REL: case A_REL+A_NUM: /* .+n, @.+n */
914 *sptr = 067 + indir;
915 *dptr = (disp - 4 + (2 * n1)) & 0177777;
916 return -1;
917
918 case A_NUM: /* n, @n */
919 if (cflag) { /* CPU - use rel */
920 *sptr = 067 + indir;
921 *dptr = (disp - addr - 4 + (2 * n1)) & 0177777;
922 }
923 else {
924 if (indir) return 1; /* other - use abs */
925 *sptr = 037;
926 *dptr = disp;
927 }
928 return -1;
929
930 default:
931 return 1;
932 } /* end case */
933 }
934
935 /* Symbolic input
936
937 Inputs:
938 *cptr = pointer to input string
939 addr = current PC
940 *uptr = pointer to unit
941 *val = pointer to output values
942 sw = switches
943 Outputs:
944 status = > 0 error code
945 <= 0 -number of extra words
946 */
947
948 t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
949 {
950 int32 bflag, cflag, d, i, j, reg, spec, n1, n2, disp, pflag;
951 t_value by;
952 t_stat r;
953 char *tptr, gbuf[CBUFSIZE];
954
955 bflag = 0; /* assume 16b */
956 cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */
957 if (!cflag) { /* not cpu? */
958 DEVICE *dptr = find_dev_from_unit (uptr);
959 if (dptr == NULL)
960 return SCPE_IERR;
961 if (dptr->dwidth < 16)
962 bflag = 1;
963 }
964
965 while (isspace (*cptr)) cptr++; /* absorb spaces */
966 if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
967 if (cptr[0] == 0) /* must have 1 char */
968 return SCPE_ARG;
969 if (bflag)
970 val[0] = (t_value) cptr[0];
971 else val[0] = (addr & 1)?
972 (val[0] & 0377) | (((t_value) cptr[0]) << 8):
973 (val[0] & ~0377) | ((t_value) cptr[0]);
974 return 0;
975 }
976 if (sw & SWMASK ('B')) { /* byte? */
977 by = get_uint (cptr, 8, 0377, &r); /* get byte */
978 if (r != SCPE_OK)
979 return SCPE_ARG;
980 if (bflag)
981 val[0] = by;
982 else val[0] = (addr & 1)?
983 (val[0] & 0377) | (by << 8):
984 (val[0] & ~0377) | by;
985 return 0;
986 }
987 if (bflag) return SCPE_ARG;
988
989 if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
990 if (cptr[0] == 0) /* must have 1 char */
991 return SCPE_ARG;
992 val[0] = ((t_value) cptr[1] << 8) | (t_value) cptr[0];
993 return -1;
994 }
995 if (sw & SWMASK ('R')) /* radix 50 */
996 return SCPE_ARG;
997
998 cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
999 n1 = n2 = pflag = 0;
1000 for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
1001 if (opcode[i] == NULL)
1002 return SCPE_ARG;
1003 val[0] = opc_val[i] & 0177777; /* get value */
1004 j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */
1005
1006 switch (j) { /* case on class */
1007
1008 case I_V_NPN: /* no operand */
1009 break;
1010
1011 case I_V_REG: /* register */
1012 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
1013 if ((reg = get_reg (gbuf, rname, 0)) < 0)
1014 return SCPE_ARG;
1015 val[0] = val[0] | reg;
1016 break;
1017
1018 case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */
1019 cptr = get_glyph (cptr, gbuf, 0); /* get literal */
1020 d = get_uint (gbuf, 8, (1 << j) - 1, &r);
1021 if (r != SCPE_OK)
1022 return SCPE_ARG;
1023 val[0] = val[0] | d; /* put in place */
1024 break;
1025
1026 case I_V_BR: /* cond br */
1027 cptr = get_glyph (cptr, gbuf, 0); /* get address */
1028 tptr = get_addr (gbuf, &disp, &pflag); /* parse */
1029 if ((tptr == NULL) || (*tptr != 0))
1030 return SCPE_ARG;
1031 if ((pflag & A_REL) == 0) {
1032 if (cflag) disp = (disp - addr) & 0177777;
1033 else return SCPE_ARG;
1034 }
1035 if ((disp & 1) || (disp > 0400) && (disp < 0177402))
1036 return SCPE_ARG;
1037 val[0] = val[0] | (((disp - 2) >> 1) & 0377);
1038 break;
1039
1040 case I_V_SOB: /* sob */
1041 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
1042 if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
1043 val[0] = val[0] | (reg << 6);
1044 cptr = get_glyph (cptr, gbuf, 0); /* get address */
1045 tptr = get_addr (gbuf, &disp, &pflag); /* parse */
1046 if ((tptr == NULL) || (*tptr != 0))
1047 return SCPE_ARG;
1048 if ((pflag & A_REL) == 0) {
1049 if (cflag) disp = (disp - addr) & 0177777;
1050 else return SCPE_ARG;
1051 }
1052 if ((disp & 1) || ((disp > 2) && (disp < 0177604)))
1053 return SCPE_ARG;
1054 val[0] = val[0] | (((2 - disp) >> 1) & 077);
1055 break;
1056
1057 case I_V_RSOP: /* reg, sop */
1058 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
1059 if ((reg = get_reg (gbuf, rname, 0)) < 0)
1060 return SCPE_ARG;
1061 val[0] = val[0] | (reg << 6); /* fall through */
1062 case I_V_SOP: /* sop */
1063 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
1064 if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
1065 return SCPE_ARG;
1066 val[0] = val[0] | spec;
1067 break;
1068
1069 case I_V_SOPR: /* dop, reg */
1070 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
1071 if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
1072 return SCPE_ARG;
1073 val[0] = val[0] | spec;
1074 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
1075 if ((reg = get_reg (gbuf, rname, 0)) < 0)
1076 return SCPE_ARG;
1077 val[0] = val[0] | (reg << 6);
1078 break;
1079
1080 case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */
1081 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
1082 if ((reg = get_reg (gbuf, fname, 0)) < 0)
1083 return SCPE_ARG;
1084 if (reg > 3)
1085 return SCPE_ARG;
1086 val[0] = val[0] | (reg << 6); /* fall through */
1087 case I_V_FOP: /* fop */
1088 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
1089 if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag,
1090 (j == I_V_ASOP) || (j == I_V_ASMD))) > 0)
1091 return SCPE_ARG;
1092 val[0] = val[0] | spec;
1093 break;
1094
1095 case I_V_DOP: /* double op */
1096 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
1097 if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
1098 return SCPE_ARG;
1099 val[0] = val[0] | (spec << 6);
1100 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
1101 if ((n2 = get_spec (gbuf, addr, n1, &spec, &val[1 - n1],
1102 cflag, TRUE)) > 0)
1103 return SCPE_ARG;
1104 val[0] = val[0] | spec;
1105 break;
1106
1107 case I_V_CCC: case I_V_CCS: /* cond code oper */
1108 for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
1109 cptr = get_glyph (cptr, gbuf, 0)) {
1110 for (i = 0; (opcode[i] != NULL) &&
1111 (strcmp (opcode[i], gbuf) != 0) ; i++) ;
1112 if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) ||
1113 (opcode[i] == NULL))
1114 return SCPE_ARG;
1115 val[0] = val[0] | (opc_val[i] & 0177777);
1116 }
1117 break;
1118
1119 default:
1120 return SCPE_ARG;
1121 }
1122
1123 if (*cptr != 0) /* junk at end? */
1124 return SCPE_ARG;
1125 return ((n1 + n2) * 2) - 1;
1126 }