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