1 /* pdp11_sys.c: PDP-11 simulator interface
2
3 Copyright (c) 1993-1997,
4 Robert M Supnik, Digital Equipment Corporation
5 Commercial use prohibited
6 */
7
8 #include "pdp11_defs.h"
9 #include <ctype.h>
10
11 #ifdef SUNOS
12 /* XXX Not sure if this is always ok, but old SunOS does not have strtoul
13 * so using signed instead.
14 */
15 #define strtoul (unsigned)strtol
16 #endif
17
18 extern DEVICE cpu_dev;
19 extern DEVICE ptr_dev, ptp_dev;
20 extern DEVICE tti_dev, tto_dev;
21 extern DEVICE lpt_dev, clk_dev;
22 extern DEVICE rk_dev, rx_dev;
23 extern DEVICE rl_dev, rp_dev;
24 extern DEVICE tm_dev;
25 extern UNIT cpu_unit;
26 extern REG cpu_reg[];
27 extern unsigned int16 *M;
28 extern int32 saved_PC;
29
30 /* SCP data structures and interface routines
31
32 sim_name simulator name string
33 sim_PC pointer to saved PC register descriptor
34 sim_emax number of words for examine
35 sim_devices array of pointers to simulated devices
36 sim_stop_messages array of pointers to stop messages
37 sim_load binary loader
38 */
39
40 char sim_name[] = "PDP-11";
41
42 REG *sim_PC = &cpu_reg[0];
43
44 int32 sim_emax = 4;
45
46 DEVICE *sim_devices[] = { &cpu_dev,
47 #ifndef PRO
48 &ptr_dev, &ptp_dev, &tti_dev, &tto_dev,
49 &lpt_dev, &clk_dev, &rk_dev, &rl_dev,
50 &rp_dev, &rx_dev, &tm_dev,
51 #endif
52 NULL };
53
54 const char *sim_stop_messages[] = {
55 "Unknown error",
56 "Red stack trap",
57 "Odd address trap",
58 "Memory management trap",
59 "Non-existent memory trap",
60 "Parity error trap",
61 "Privilege trap",
62 "Illegal instruction trap",
63 "BPT trap",
64 "IOT trap",
65 "EMT trap",
66 "TRAP trap",
67 "Trace trap",
68 "Yellow stack trap",
69 "Powerfail trap",
70 "Floating point exception",
71 "HALT instruction",
72 "Breakpoint",
73 "Wait state",
74 "Trap vector fetch abort",
75 "Trap stack push abort" };
76
77 /* Binary loader.
78
79 Loader format consists of blocks, optionally preceded, separated, and
80 followed by zeroes. Each block consists of:
81
82 001 ---
83 xxx |
84 lo_count |
85 hi_count |
86 lo_origin > count bytes
87 hi_origin |
88 data byte |
89 : |
90 data byte ---
91 checksum
92
93 If the byte count is exactly six, the block is the last on the tape, and
94 there is no checksum. If the origin is not 000001, then the origin is
95 the PC at which to start the program.
96 */
97
sim_load(FILE * fileref)98 t_stat sim_load (FILE *fileref)
99 {
100 int32 origin, csum, count, state, i;
101
102 origin = count = 0; /* (to keep gcc happy) */
103 state = csum = 0;
104 while ((i = getc (fileref)) != EOF) {
105 csum = csum + i; /* add into chksum */
106 switch (state) {
107 case 0: /* leader */
108 if (i == 1) state = 1;
109 else csum = 0;
110 break;
111 case 1: /* ignore after 001 */
112 state = 2;
113 break;
114 case 2: /* low count */
115 count = i;
116 state = 3;
117 break;
118 case 3: /* high count */
119 count = (i << 8) | count;
120 state = 4;
121 break;
122 case 4: /* low origin */
123 origin = i;
124 state = 5;
125 break;
126 case 5: /* high origin */
127 origin = (i << 8) | origin;
128 if (count == 6) {
129 if (origin != 1) saved_PC = origin & 0177776;
130 return SCPE_OK; }
131 count = count - 6;
132 state = 6;
133 break;
134 case 6: /* data */
135 if (origin >= MEMSIZE) return SCPE_NXM;
136 M[origin >> 1] = (origin & 1)?
137 (M[origin >> 1] & 0377) | (i << 8):
138 (M[origin >> 1] & 0177400) | i;
139 origin = origin + 1;
140 count = count - 1;
141 state = state + (count == 0);
142 break;
143 case 7: /* checksum */
144 if (csum & 0377) return SCPE_CSUM;
145 csum = state = 0;
146 break; } /* end switch */
147 } /* end while */
148 return SCPE_FMT; /* unexpected eof */
149 }
150
151 /* Symbol tables */
152
153 #define I_V_L 16 /* long mode */
154 #define I_V_D 17 /* double mode */
155 #define I_L (1 << I_V_L)
156 #define I_D (1 << I_V_D)
157
158 /* Warning: for literals, the class number MUST equal the field width!! */
159
160 #define I_V_CL 18 /* class bits */
161 #define I_M_CL 017 /* class mask */
162 #define I_V_NPN 0 /* no operands */
163 #define I_V_REG 1 /* reg */
164 #define I_V_SOP 2 /* operand */
165 #define I_V_3B 3 /* 3b literal */
166 #define I_V_FOP 4 /* flt operand */
167 #define I_V_AFOP 5 /* fac, flt operand */
168 #define I_V_6B 6 /* 6b literal */
169 #define I_V_BR 7 /* cond branch */
170 #define I_V_8B 8 /* 8b literal */
171 #define I_V_SOB 9 /* reg, disp */
172 #define I_V_RSOP 10 /* reg, operand */
173 #define I_V_ASOP 11 /* fac, operand */
174 #define I_V_ASMD 12 /* fac, moded int op */
175 #define I_V_DOP 13 /* double operand */
176 #define I_V_CCC 14 /* CC clear */
177 #define I_V_CCS 15 /* CC set */
178 #define I_NPN (I_V_NPN << I_V_CL)
179 #define I_REG (I_V_REG << I_V_CL)
180 #define I_3B (I_V_3B << I_V_CL)
181 #define I_SOP (I_V_SOP << I_V_CL)
182 #define I_FOP (I_V_FOP << I_V_CL)
183 #define I_6B (I_V_6B << I_V_CL)
184 #define I_BR (I_V_BR << I_V_CL)
185 #define I_8B (I_V_8B << I_V_CL)
186 #define I_AFOP (I_V_AFOP << I_V_CL)
187 #define I_ASOP (I_V_ASOP << I_V_CL)
188 #define I_RSOP (I_V_RSOP << I_V_CL)
189 #define I_SOB (I_V_SOB << I_V_CL)
190 #define I_ASMD (I_V_ASMD << I_V_CL)
191 #define I_DOP (I_V_DOP << I_V_CL)
192 #define I_CCC (I_V_CCC << I_V_CL)
193 #define I_CCS (I_V_CCS << I_V_CL)
194
195 static const int32 masks[] = {
196 0177777, 0177770, 0177700, 0177770,
197 0177700+I_D, 0177400+I_D, 0177700, 0177400,
198 0177400, 0177000, 0177000, 0177400,
199 0177400+I_D+I_L, 0170000, 0177777, 0177777 };
200
201 static const char *opcode[] = {
202 "HALT","WAIT","RTI","BPT",
203 "IOT","RESET","RTT","MFPT",
204 "JMP","RTS","SPL",
205 "NOP","CLC","CLV","CLV CLC",
206 "CLZ","CLZ CLC","CLZ CLV","CLZ CLV CLC",
207 "CLN","CLN CLC","CLN CLV","CLN CLV CLC",
208 "CLN CLZ","CLN CLZ CLC","CLN CLZ CLC","CCC",
209 "NOP","SEC","SEV","SEV SEC",
210 "SEZ","SEZ SEC","SEZ SEV","SEZ SEV SEC",
211 "SEN","SEN SEC","SEN SEV","SEN SEV SEC",
212 "SEN SEZ","SEN SEZ SEC","SEN SEZ SEC","SCC",
213 "SWAB","BR","BNE","BEQ",
214 "BGE","BLT","BGT","BLE",
215 "JSR",
216 "CLR","COM","INC","DEC",
217 "NEG","ADC","SBC","TST",
218 "ROL","ROR","ASR","ASL",
219 "MARK","MFPI","MTPI","SXT",
220 "CSM", "TSTSET","WRTLCK",
221 "MOV","CMP","BIT","BIC",
222 "BIS","ADD",
223 "MUL","DIV","ASH","ASHC",
224 "XOR",
225 "FADD","FSUB","FMUL","FDIV",
226 "L2DR",
227 "MOVC","MOVRC","MOVTC",
228 "LOCC","SKPC","SCANC","SPANC",
229 "CMPC","MATC",
230 "ADDN","SUBN","CMPN","CVTNL",
231 "CVTPN","CVTNP","ASHN","CVTLN",
232 "L3DR",
233 "ADDP","SUBP","CMPP","CVTPL",
234 "MULP","DIVP","ASHP","CVTLP",
235 "MOVCI","MOVRCI","MOVTCI",
236 "LOCCI","SKPCI","SCANCI","SPANCI",
237 "CMPCI","MATCI",
238 "ADDNI","SUBNI","CMPNI","CVTNLI",
239 "CVTPNI","CVTNPI","ASHNI","CVTLNI",
240 "ADDPI","SUBPI","CMPPI","CVTPLI",
241 "MULPI","DIVPI","ASHPI","CVTLPI",
242 "SOB",
243 "BPL","BMI","BHI","BLOS",
244 "BVC","BVS","BCC","BCS",
245 "BHIS","BLO", /* encode only */
246 "EMT","TRAP",
247 "CLRB","COMB","INCB","DECB",
248 "NEGB","ADCB","SBCB","TSTB",
249 "ROLB","RORB","ASRB","ASLB",
250 "MTPS","MFPD","MTPD","MFPS",
251 "MOVB","CMPB","BITB","BICB",
252 "BISB","SUB",
253 "CFCC","SETF","SETI","SETD","SETL",
254 "LDFPS","STFPS","STST",
255 "CLRF","CLRD","TSTF","TSTD",
256 "ABSF","ABSD","NEGF","NEGD",
257 "MULF","MULD","MODF","MODD",
258 "ADDF","ADDD","LDF","LDD",
259 "SUBF","SUBD","CMPF","CMPD",
260 "STF","STD","DIVF","DIVD",
261 "STEXP",
262 "STCFI","STCDI","STCFL","STCDL",
263 "STCFD","STCDF",
264 "LDEXP",
265 "LDCIF","LDCID","LDCLF","LDCLD",
266 "LDCFD","LDCDF",
267 NULL };
268
269 static const int32 opc_val[] = {
270 0000000+I_NPN, 0000001+I_NPN, 0000002+I_NPN, 0000003+I_NPN,
271 0000004+I_NPN, 0000005+I_NPN, 0000006+I_NPN, 0000007+I_NPN,
272 0000100+I_SOP, 0000200+I_REG, 0000230+I_3B,
273 0000240+I_CCC, 0000241+I_CCC, 0000242+I_CCC, 0000243+I_NPN,
274 0000244+I_CCC, 0000245+I_NPN, 0000246+I_NPN, 0000247+I_NPN,
275 0000250+I_CCC, 0000251+I_NPN, 0000252+I_NPN, 0000253+I_NPN,
276 0000254+I_NPN, 0000255+I_NPN, 0000256+I_NPN, 0000257+I_CCC,
277 0000260+I_CCS, 0000261+I_CCS, 0000262+I_CCS, 0000263+I_NPN,
278 0000264+I_CCS, 0000265+I_NPN, 0000266+I_NPN, 0000267+I_NPN,
279 0000270+I_CCS, 0000271+I_NPN, 0000272+I_NPN, 0000273+I_NPN,
280 0000274+I_NPN, 0000275+I_NPN, 0000276+I_NPN, 0000277+I_CCS,
281 0000300+I_SOP, 0000400+I_BR, 0001000+I_BR, 0001400+I_BR,
282 0002000+I_BR, 0002400+I_BR, 0003000+I_BR, 0003400+I_BR,
283 0004000+I_RSOP,
284 0005000+I_SOP, 0005100+I_SOP, 0005200+I_SOP, 0005300+I_SOP,
285 0005400+I_SOP, 0005500+I_SOP, 0005600+I_SOP, 0005700+I_SOP,
286 0006000+I_SOP, 0006100+I_SOP, 0006200+I_SOP, 0006300+I_SOP,
287 0006400+I_6B, 0006500+I_SOP, 0006600+I_SOP, 0006700+I_SOP,
288 0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP,
289 0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP,
290 0050000+I_DOP, 0060000+I_DOP,
291 0070000+I_RSOP, 0071000+I_RSOP, 0072000+I_RSOP, 0073000+I_RSOP,
292 0074000+I_RSOP,
293 0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG,
294 0076020+I_REG,
295 0076030+I_NPN, 0076031+I_NPN, 0076032+I_NPN,
296 0076040+I_NPN, 0076041+I_NPN, 0076042+I_NPN, 0076043+I_NPN,
297 0076044+I_NPN, 0076045+I_NPN,
298 0076050+I_NPN, 0076051+I_NPN, 0076052+I_NPN, 0076053+I_NPN,
299 0076054+I_NPN, 0076055+I_NPN, 0076056+I_NPN, 0076057+I_NPN,
300 0076060+I_REG,
301 0076070+I_NPN, 0076071+I_NPN, 0076072+I_NPN, 0076073+I_NPN,
302 0076074+I_NPN, 0076075+I_NPN, 0076076+I_NPN, 0076077+I_NPN,
303 0076130+I_NPN, 0076131+I_NPN, 0076132+I_NPN,
304 0076140+I_NPN, 0076141+I_NPN, 0076142+I_NPN, 0076143+I_NPN,
305 0076144+I_NPN, 0076145+I_NPN,
306 0076150+I_NPN, 0076151+I_NPN, 0076152+I_NPN, 0076153+I_NPN,
307 0076154+I_NPN, 0076155+I_NPN, 0076156+I_NPN, 0076157+I_NPN,
308 0076170+I_NPN, 0076171+I_NPN, 0076172+I_NPN, 0076173+I_NPN,
309 0076174+I_NPN, 0076175+I_NPN, 0076176+I_NPN, 0076177+I_NPN,
310 0077000+I_SOB,
311 0100000+I_BR, 0100400+I_BR, 0101000+I_BR, 0101400+I_BR,
312 0102000+I_BR, 0102400+I_BR, 0103000+I_BR, 0103400+I_BR,
313 0103000+I_BR, 0103400+I_BR,
314 0104000+I_8B, 0104400+I_8B,
315 0105000+I_SOP, 0105100+I_SOP, 0105200+I_SOP, 0105300+I_SOP,
316 0105400+I_SOP, 0105500+I_SOP, 0105600+I_SOP, 0105700+I_SOP,
317 0106000+I_SOP, 0106100+I_SOP, 0106200+I_SOP, 0106300+I_SOP,
318 0106400+I_SOP, 0106500+I_SOP, 0106600+I_SOP, 0106700+I_SOP,
319 0110000+I_DOP, 0120000+I_DOP, 0130000+I_DOP, 0140000+I_DOP,
320 0150000+I_DOP, 0160000+I_DOP,
321 0170000+I_NPN, 0170001+I_NPN, 0170002+I_NPN, 0170011+I_NPN, 0170012+I_NPN,
322 0170100+I_SOP, 0170200+I_SOP, 0170300+I_SOP,
323 0170400+I_FOP, 0170400+I_FOP+I_D, 0170500+I_FOP, 0170500+I_FOP+I_D,
324 0170600+I_FOP, 0170600+I_FOP+I_D, 0170700+I_FOP, 0170700+I_FOP+I_D,
325 0171000+I_AFOP, 0171000+I_AFOP+I_D, 0171400+I_AFOP, 0171400+I_AFOP+I_D,
326 0172000+I_AFOP, 0172000+I_AFOP+I_D, 0172400+I_AFOP, 0172400+I_AFOP+I_D,
327 0173000+I_AFOP, 0173000+I_AFOP+I_D, 0173400+I_AFOP, 0173400+I_AFOP+I_D,
328 0174000+I_AFOP, 0174000+I_AFOP+I_D, 0174400+I_AFOP, 0174400+I_AFOP+I_D,
329 0175000+I_ASOP,
330 0175400+I_ASMD, 0175400+I_ASMD+I_D, 0175400+I_ASMD+I_L, 0175400+I_ASMD+I_D+I_L,
331 0176000+I_AFOP, 0176000+I_AFOP+I_D,
332 0176400+I_ASOP,
333 0177000+I_ASMD, 0177000+I_ASMD+I_D, 0177000+I_ASMD+I_L, 0177000+I_ASMD+I_D+I_L,
334 0177400+I_AFOP, 0177400+I_AFOP+I_D,
335 -1 };
336
337 static const char *rname [] =
338 { "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC" };
339
340 static const char *fname [] =
341 { "F0", "F1", "F2", "F3", "F4", "F5", "?6", "?7" };
342
343 /* Specifier decode
344
345 Inputs:
346 addr = current PC
347 spec = specifier
348 nval = next word
349 flag = TRUE if decoding for CPU
350 iflag = TRUE if decoding integer instruction
351 Outputs:
352 count = -number of extra words retired
353 */
354
specf(t_addr addr,int32 spec,t_value nval,int32 flag,int32 iflag)355 int32 specf (t_addr addr, int32 spec, t_value nval, int32 flag, int32 iflag)
356 {
357 int32 reg;
358
359 reg = spec & 07;
360 switch ((spec >> 3) & 07) {
361 case 0:
362 if (iflag) printf ("%s", rname[reg]);
363 else printf ("%s", fname[reg]);
364 return 0;
365 case 1:
366 printf ("(%s)", rname[reg]);
367 return 0;
368 case 2:
369 if (reg != 7) {
370 printf ("(%s)+", rname[reg]);
371 return 0; }
372 else { printf ("#%-o", nval);
373 return -1; }
374 case 3:
375 if (reg != 7) {
376 printf ("@(%s)+", rname[reg]);
377 return 0; }
378 else { printf ("@#%-o", nval);
379 return -1; }
380 case 4:
381 printf ("-(%s)", rname[reg]);
382 return 0;
383 case 5:
384 printf ("@-(%s)", rname[reg]);
385 return 0;
386 case 6:
387 if ((reg != 7) || !flag) printf ("%-o(%s)", nval, rname[reg]);
388 else printf ("%-o", (nval + addr + 4) & 0177777);
389 return -1;
390 case 7:
391 default: /* (to keep gcc happy) */
392 if ((reg != 7) || !flag) printf ("@%-o(%s)", nval, rname[reg]);
393 else printf ("@%-o", (nval + addr + 4) & 0177777);
394 return -1; } /* end case */
395 }
396
397 /* Symbolic decode
398
399 Inputs:
400 addr = current PC
401 *val = values to decode
402 *uptr = pointer to unit
403 sw = switches
404 Outputs:
405 return = if >= 0, error code
406 if < 0, number of extra words retired
407 */
408
print_sym(t_addr addr,t_value * val,UNIT * uptr,int32 sw)409 t_stat print_sym (t_addr addr, t_value *val, UNIT *uptr, int32 sw)
410 {
411 int32 cflag, i, j, c1, c2, inst, fac, srcm, srcr, dstm, dstr;
412 int32 l8b, brdisp, wd1, wd2;
413 extern int32 FPS;
414
415 cflag = (uptr == NULL) || (uptr == &cpu_unit);
416 c1 = val[0] & 0177;
417 c2 = (val[0] >> 8) & 0177;
418 if (sw & SWMASK ('A')) { /* ASCII? */
419 printf ((c1 < 040)? "<%03o>": "%c", c1);
420 return SCPE_OK; }
421 if (sw & SWMASK ('C')) { /* character? */
422 printf ((c1 < 040)? "<%03o>": "%c", c1);
423 printf ((c2 < 040)? "<%03o>": "%c", c2);
424 return SCPE_OK; }
425 if (!(sw & SWMASK ('M'))) return SCPE_ARG;
426
427 inst = val[0] | ((FPS << (I_V_L - FPS_V_L)) & I_L) |
428 ((FPS << (I_V_D - FPS_V_D)) & I_D); /* inst + fp mode */
429 for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
430 j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */
431 if ((opc_val[i] & 0777777) == (inst & masks[j])) { /* match? */
432 srcm = (inst >> 6) & 077; /* opr fields */
433 srcr = srcm & 07;
434 fac = srcm & 03;
435 dstm = inst & 077;
436 dstr = dstm & 07;
437 l8b = inst & 0377;
438
439 /* Instruction decode */
440
441 switch (j) { /* case on class */
442 case I_V_NPN: case I_V_CCC: case I_V_CCS: /* no operands */
443 printf ("%s", opcode[i]);
444 return SCPE_OK;
445 case I_V_REG: /* reg */
446 printf ("%s %-s", opcode[i], rname[dstr]);
447 return SCPE_OK;
448 case I_V_SOP: /* sop */
449 printf ("%s ", opcode[i]);
450 return specf (addr, dstm, val[1], cflag, TRUE);
451 case I_V_3B: /* 3b */
452 printf ("%s %-o", opcode[i], dstr);
453 return SCPE_OK;
454 case I_V_FOP: /* fop */
455 printf ("%s ", opcode[i]);
456 return specf (addr, dstm, val[1], cflag, FALSE);
457 case I_V_AFOP: /* afop */
458 printf ("%s %s,", opcode[i], fname[fac]);
459 return specf (addr, dstm, val[1], cflag, FALSE);
460 case I_V_6B: /* 6b */
461 printf ("%s %-o", opcode[i], dstm);
462 return SCPE_OK;
463 case I_V_BR: /* cond branch */
464 printf ("%s ", opcode[i]);
465 brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777;
466 if (cflag) printf ("%-o", (addr + brdisp) & 0177777);
467 else if (brdisp < 01000) printf (".+%-o", brdisp);
468 else printf (".-%-o", 0200000 - brdisp);
469 return SCPE_OK;
470 case I_V_8B: /* 8b */
471 printf ("%s %-o", opcode[i], l8b);
472 return SCPE_OK;
473 case I_V_SOB: /* sob */
474 printf ("%s %s,", opcode[i], rname[srcr]);
475 brdisp = (dstm * 2) - 2;
476 if (cflag) printf ("%-o", (addr - brdisp) & 0177777);
477 else if (brdisp <= 0) printf (".+%-o", -brdisp);
478 else printf (".-%-o", brdisp);
479 return SCPE_OK;
480 case I_V_RSOP: /* rsop */
481 printf ("%s %s,", opcode[i], rname[srcr]);
482 return specf (addr, dstm, val[1], cflag, TRUE);
483 case I_V_ASOP: case I_V_ASMD: /* asop, asmd */
484 printf ("%s %s,", opcode[i], fname[fac]);
485 return specf (addr, dstm, val[2], cflag, TRUE);
486 case I_V_DOP: /* dop */
487 printf ("%s ", opcode[i]);
488 wd1 = specf (addr, srcm, val[1], cflag, TRUE);
489 printf (",");
490 wd2 = specf (addr - wd1 - wd1, dstm, val[1 - wd1], cflag, TRUE);
491 return wd1 + wd2; } /* end case */
492 } /* end if */
493 } /* end for */
494 return SCPE_ARG; /* no match */
495 }
496
497 #define A_PND 100 /* # seen */
498 #define A_MIN 040 /* -( seen */
499 #define A_PAR 020 /* (Rn) seen */
500 #define A_REG 010 /* Rn seen */
501 #define A_PLS 004 /* + seen */
502 #define A_NUM 002 /* number seen */
503 #define A_REL 001 /* relative addr seen */
504
505 /* Register number
506
507 Inputs:
508 *cptr = pointer to input string
509 *strings = pointer to register names
510 mchar = character to match after register name
511 Outputs:
512 rnum = 0..7 if a legitimate register
513 < 0 if error
514 */
515
get_reg(char * cptr,const char * strings[],char mchar)516 int32 get_reg (char *cptr, const char *strings[], char mchar)
517 {
518 int32 i;
519
520 if (*(cptr + 2) != mchar) return -1;
521 for (i = 0; i < 8; i++) {
522 if (strncmp (cptr, strings[i], 2) == 0) return i; }
523 return -1;
524 }
525
526 /* Number or memory address
527
528 Inputs:
529 *cptr = pointer to input string
530 *dptr = pointer to output displacement
531 *pflag = pointer to accumulating flags
532 Outputs:
533 cptr = pointer to next character in input string
534 NULL if parsing error
535
536 Flags: 0 (no result), A_NUM (number), A_REL (relative)
537 */
538
get_addr(char * cptr,int32 * dptr,int32 * pflag)539 char *get_addr (char *cptr, int32 *dptr, int32 *pflag)
540 {
541 int32 val, minus;
542 char *tptr;
543
544 minus = 0;
545
546 if (*cptr == '.') { /* relative? */
547 *pflag = *pflag | A_REL;
548 cptr++; }
549 if (*cptr == '+') { /* +? */
550 *pflag = *pflag | A_NUM;
551 cptr++; }
552 if (*cptr == '-') { /* -? */
553 *pflag = *pflag | A_NUM;
554 minus = 1;
555 cptr++; }
556 errno = 0;
557 val = strtoul (cptr, &tptr, 8);
558 if (cptr == tptr) { /* no number? */
559 if (*pflag != (A_REL + A_NUM)) return cptr;
560 else return NULL; }
561 if (errno || (*pflag == A_REL)) return NULL; /* .n? */
562 *dptr = (minus? -val: val) & 0177777;
563 *pflag = *pflag | A_NUM;
564 return tptr;
565 }
566
567 /* Specifier decode
568
569 Inputs:
570 *cptr = pointer to input string
571 addr = current PC
572 n1 = 0 if no extra word used
573 -1 if extra word used in prior decode
574 *sptr = pointer to output specifier
575 *dptr = pointer to output displacement
576 cflag = true if parsing for the CPU
577 iflag = true if integer specifier
578 Outputs:
579 status = = -1 extra word decoded
580 = 0 ok
581 = +1 error
582 */
583
get_spec(char * cptr,t_addr addr,int32 n1,int32 * sptr,t_value * dptr,int32 cflag,int32 iflag)584 t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr,
585 int32 cflag, int32 iflag)
586 {
587 int32 reg, indir, pflag, disp;
588
589 indir = 0; /* no indirect */
590 pflag = 0;
591
592 if (*cptr == '@') { /* indirect? */
593 indir = 010;
594 cptr++; }
595 if (*cptr == '#') { /* literal? */
596 pflag = pflag | A_PND;
597 cptr++; }
598 if (strncmp (cptr, "-(", 2) == 0) { /* autodecrement? */
599 pflag = pflag | A_MIN;
600 cptr++; }
601 else if ((cptr = get_addr (cptr, &disp, &pflag)) == NULL) return 1;
602 if (*cptr == '(') { /* register index? */
603 pflag = pflag | A_PAR;
604 if ((reg = get_reg (cptr + 1, rname, ')')) < 0) return 1;
605 cptr = cptr + 4;
606 if (*cptr == '+') { /* autoincrement? */
607 pflag = pflag | A_PLS;
608 cptr++; } }
609 else if ((reg = get_reg (cptr, iflag? rname: fname, 0)) >= 0) {
610 pflag = pflag | A_REG;
611 cptr = cptr + 2; }
612 if (*cptr != 0) return 1; /* all done? */
613
614 /* Specifier decode, continued */
615
616 switch (pflag) { /* case on syntax */
617 case A_REG: /* Rn, @Rn */
618 *sptr = indir + reg;
619 return 0;
620 case A_PAR: /* (Rn), @(Rn) */
621 if (indir) { /* @(Rn) = @0(Rn) */
622 *sptr = 070 + reg;
623 *dptr = 0;
624 return -1; }
625 else *sptr = 010 + reg;
626 return 0;
627 case A_PAR+A_PLS: /* (Rn)+, @(Rn)+ */
628 *sptr = 020 + indir + reg;
629 return 0;
630 case A_MIN+A_PAR: /* -(Rn), @-(Rn) */
631 *sptr = 040 + indir + reg;
632 return 0;
633 case A_NUM+A_PAR: /* d(Rn), @d(Rn) */
634 *sptr = 060 + indir + reg;
635 *dptr = disp;
636 return -1;
637 case A_PND+A_REL: case A_PND+A_REL+A_NUM: /* #.+n, @#.+n */
638 if (!cflag) return 1;
639 disp = (disp + addr) & 0177777; /* fall through */
640 case A_PND+A_NUM: /* #n, @#n */
641 *sptr = 027 + indir;
642 *dptr = disp;
643 return -1;
644 case A_REL: case A_REL+A_NUM: /* .+n, @.+n */
645 *sptr = 067 + indir;
646 *dptr = (disp - 4 + (2 * n1)) & 0177777;
647 return -1;
648 case A_NUM: /* n, @n */
649 if (cflag) { /* CPU - use rel */
650 *sptr = 067 + indir;
651 *dptr = (disp - addr - 4 + (2 * n1)) & 0177777; }
652 else { if (indir) return 1; /* other - use abs */
653 *sptr = 037;
654 *dptr = disp; }
655 return -1;
656 default:
657 return 1; } /* end case */
658 }
659
660 /* Symbolic input
661
662 Inputs:
663 *cptr = pointer to input string
664 addr = current PC
665 *uptr = pointer to unit
666 *val = pointer to output values
667 sw = switches
668 Outputs:
669 status = > 0 error code
670 <= 0 -number of extra words
671 */
672
parse_sym(char * cptr,t_addr addr,UNIT * uptr,t_value * val,int32 sw)673 t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
674 {
675 int32 cflag, d, i, j, reg, spec, n1, n2, disp, pflag;
676 t_stat r;
677 char gbuf[CBUFSIZE];
678
679 cflag = (uptr == NULL) || (uptr == &cpu_unit);
680 while (isspace (*cptr)) cptr++; /* absorb spaces */
681 if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
682 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
683 val[0] = (t_value) cptr[0];
684 return SCPE_OK; }
685 if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
686 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
687 val[0] = ((t_value) cptr[1] << 8) + (t_value) cptr[0];
688 return SCPE_OK; }
689
690 cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
691 n1 = n2 = pflag = 0;
692 for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
693 if (opcode[i] == NULL) return SCPE_ARG;
694 val[0] = opc_val[i] & 0177777; /* get value */
695 j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */
696
697 switch (j) { /* case on class */
698 case I_V_NPN: /* no operand */
699 break;
700 case I_V_REG: /* register */
701 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
702 if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
703 val[0] = val[0] | reg;
704 break;
705 case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */
706 cptr = get_glyph (cptr, gbuf, 0); /* get literal */
707 d = get_uint (gbuf, 8, (1 << j) - 1, &r);
708 if (r != SCPE_OK) return SCPE_ARG;
709 val[0] = val[0] | d; /* put in place */
710 break;
711 case I_V_BR: /* cond br */
712 cptr = get_glyph (cptr, gbuf, 0); /* get address */
713 if ((cptr = get_addr (gbuf, &disp, &pflag)) == NULL) return SCPE_ARG;
714 if ((pflag & A_REL) == 0) {
715 if (cflag) disp = (disp - addr) & 0177777;
716 else return SCPE_ARG; }
717 if ((disp & 1) || ((disp > 0400) && (disp < 0177402))) return SCPE_ARG;
718 val[0] = val[0] | (((disp - 2) >> 1) & 0377);
719 break;
720 case I_V_SOB: /* sob */
721 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
722 if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
723 val[0] = val[0] | (reg << 6);
724 cptr = get_glyph (cptr, gbuf, 0); /* get address */
725 if ((cptr = get_addr (gbuf, &disp, &pflag)) == NULL) return SCPE_ARG;
726 if ((pflag & A_REL) == 0) {
727 if (cflag) disp = (disp - addr) & 0177777;
728 else return SCPE_ARG; }
729 if ((disp & 1) || ((disp > 2) && (disp < 0177604))) return SCPE_ARG;
730 val[0] = val[0] | (((2 - disp) >> 1) & 077);
731 break;
732 case I_V_RSOP: /* reg, sop */
733 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
734 if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
735 val[0] = val[0] | (reg << 6); /* fall through */
736 case I_V_SOP: /* sop */
737 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
738 if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
739 return SCPE_ARG;
740 val[0] = val[0] | spec;
741 break;
742 case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */
743 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
744 if ((reg = get_reg (gbuf, fname, 0)) < 0) return SCPE_ARG;
745 if (reg > 3) return SCPE_ARG;
746 val[0] = val[0] | (reg << 6); /* fall through */
747 case I_V_FOP: /* fop */
748 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
749 if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag,
750 (j == I_V_ASOP) || (j == I_V_ASMD))) > 0) return SCPE_ARG;
751 val[0] = val[0] | spec;
752 break;
753 case I_V_DOP: /* double op */
754 cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
755 if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
756 return SCPE_ARG;
757 val[0] = val[0] | (spec << 6);
758 cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
759 if ((n2 = get_spec (gbuf, addr, n1, &spec, &val[1 - n1],
760 cflag, TRUE)) > 0) return SCPE_ARG;
761 val[0] = val[0] | spec;
762 break;
763 case I_V_CCC: case I_V_CCS: /* cond code oper */
764 for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
765 cptr = get_glyph (cptr, gbuf, 0)) {
766 for (i = 0; (opcode[i] != NULL) &&
767 (strcmp (opcode[i], gbuf) != 0) ; i++) ;
768 if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) ||
769 (opcode[i] == NULL)) return SCPE_ARG;
770 val[0] = val[0] | (opc_val[i] & 0177777); }
771 break;
772 default:
773 return SCPE_ARG; }
774 if (*cptr != 0) return SCPE_ARG; /* junk at end? */
775 return n1 + n2;
776 }
777