1
/* pdp11_sys.c: PDP-11 simulator interface
3
Copyright (c) 1993-2004, Robert M Supnik
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:
12
The above copyright notice and this permission notice shall be included in
13
all copies or substantial portions of the Software.
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.
22
Except as contained in this notice, the name of Robert M Supnik shall not
23
be 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.
26
22-Dec-03 RMS Added second DEUNA/DELUA support
27
18-Oct-03 RMS Added DECtape off reel message
28
06-May-03 RMS Added support for second DEQNA/DELQA
29
09-Jan-03 RMS Added DELUA/DEUNA support
30
17-Oct-02 RMS Fixed bugs in branch, SOB address parsing
31
09-Oct-02 RMS Added DELQA support
32
12-Sep-02 RMS Added TMSCP, KW11P, RX211 support, RAD50 examine
33
29-Nov-01 RMS Added read only unit support
34
17-Sep-01 RMS Removed multiconsole support
35
26-Aug-01 RMS Added DZ11
36
20-Aug-01 RMS Updated bad block inquiry
37
17-Jul-01 RMS Fixed warning from VC++ 6.0
38
27-May-01 RMS Added multiconsole support
39
05-Apr-01 RMS Added support for TS11/TSV05
40
14-Mar-01 RMS Revised load/dump interface (again)
41
11-Feb-01 RMS Added DECtape support
42
30-Oct-00 RMS Added support for examine to file
43
14-Apr-99 RMS Changed t_addr to unsigned
44
09-Nov-98 RMS Fixed assignments of ROR/ROL (John Wilson)
45
27-Oct-98 RMS V2.4 load interface
46
08-Oct-98 RMS Fixed bug in bad block routine
47
30-Mar-98 RMS Fixed bug in floating point display
48
12-Nov-97 RMS Added bad block table routine
51
#include "pdp11_defs.h"
54
extern DEVICE cpu_dev;
55
extern DEVICE ptr_dev, ptp_dev;
56
extern DEVICE tti_dev, tto_dev;
57
extern DEVICE lpt_dev;
58
extern DEVICE clk_dev, pclk_dev;
60
extern DEVICE rk_dev, rl_dev;
62
extern DEVICE rx_dev, ry_dev;
64
extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev;
66
extern DEVICE tm_dev, ts_dev;
68
extern DEVICE xq_dev, xqb_dev;
69
extern DEVICE xu_dev, xub_dev;
73
extern int32 saved_PC;
75
/* SCP data structures and interface routines
77
sim_name simulator name string
78
sim_PC pointer to saved PC register descriptor
79
sim_emax number of words for examine
80
sim_devices array of pointers to simulated devices
81
sim_stop_messages array of pointers to stop messages
82
sim_load binary loader
85
char sim_name[] = "PDP-11";
87
REG *sim_PC = &cpu_reg[0];
91
DEVICE *sim_devices[] = {
121
const char *sim_stop_messages[] = {
125
"Memory management trap",
126
"Non-existent memory trap",
129
"Illegal instruction trap",
137
"Floating point exception",
141
"Trap vector fetch abort",
142
"Trap stack push abort",
143
"RQDX3 consistency error",
144
"Sanity timer expired"
145
"DECtape off reel" };
149
Loader format consists of blocks, optionally preceded, separated, and
150
followed by zeroes. Each block consists of:
156
lo_origin > count bytes
163
If the byte count is exactly six, the block is the last on the tape, and
164
there is no checksum. If the origin is not 000001, then the origin is
165
the PC at which to start the program.
168
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
170
int32 csum, count, state, i;
173
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
175
while ((i = getc (fileref)) != EOF) {
176
csum = csum + i; /* add into chksum */
179
if (i == 1) state = 1;
182
case 1: /* ignore after 001 */
185
case 2: /* low count */
189
case 3: /* high count */
190
count = (i << 8) | count;
193
case 4: /* low origin */
197
case 5: /* high origin */
198
origin = (i << 8) | origin;
200
if (origin != 1) saved_PC = origin & 0177776;
206
if (origin >= MEMSIZE) return SCPE_NXM;
207
M[origin >> 1] = (origin & 1)?
208
(M[origin >> 1] & 0377) | (i << 8):
209
(M[origin >> 1] & 0177400) | i;
212
state = state + (count == 0);
214
case 7: /* checksum */
215
if (csum & 0377) return SCPE_CSUM;
217
break; } /* end switch */
219
return SCPE_FMT; /* unexpected eof */
222
/* Factory bad block table creation routine
224
This routine writes a DEC standard 044 compliant bad block table on the
225
last track of the specified unit. The bad block table consists of 10
226
repetitions of the same table, formatted as follows:
228
words 0-1 pack id number
229
words 2-3 cylinder/sector/surface specifications
231
words n-n+1 end of table (-1,-1)
234
uptr = pointer to unit
235
sec = number of sectors per surface
236
wds = number of words per sector
241
t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds)
246
if ((sec < 2) || (wds < 16)) return SCPE_ARG;
247
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
248
if (uptr->flags & UNIT_RO) return SCPE_RO;
249
if (!get_yn ("Create bad block table on last track? [N]", FALSE)) return SCPE_OK;
250
da = (uptr->capac - (sec * wds)) * sizeof (int16);
251
if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR;
252
if ((buf = malloc (wds * sizeof (int16))) == NULL) return SCPE_MEM;
253
buf[0] = buf[1] = 012345u;
255
for (i = 4; i < wds; i++) buf[i] = 0177777u;
256
for (i = 0; (i < sec) && (i < 10); i++)
257
fxwrite (buf, sizeof (int16), wds, uptr->fileref);
259
if (ferror (uptr->fileref)) return SCPE_IOERR;
265
#define I_V_L 16 /* long mode */
266
#define I_V_D 17 /* double mode */
267
#define I_L (1 << I_V_L)
268
#define I_D (1 << I_V_D)
270
/* Warning: for literals, the class number MUST equal the field width!! */
272
#define I_V_CL 18 /* class bits */
273
#define I_M_CL 017 /* class mask */
274
#define I_V_NPN 0 /* no operands */
275
#define I_V_REG 1 /* reg */
276
#define I_V_SOP 2 /* operand */
277
#define I_V_3B 3 /* 3b literal */
278
#define I_V_FOP 4 /* flt operand */
279
#define I_V_AFOP 5 /* fac, flt operand */
280
#define I_V_6B 6 /* 6b literal */
281
#define I_V_BR 7 /* cond branch */
282
#define I_V_8B 8 /* 8b literal */
283
#define I_V_SOB 9 /* reg, disp */
284
#define I_V_RSOP 10 /* reg, operand */
285
#define I_V_ASOP 11 /* fac, operand */
286
#define I_V_ASMD 12 /* fac, moded int op */
287
#define I_V_DOP 13 /* double operand */
288
#define I_V_CCC 14 /* CC clear */
289
#define I_V_CCS 15 /* CC set */
290
#define I_NPN (I_V_NPN << I_V_CL)
291
#define I_REG (I_V_REG << I_V_CL)
292
#define I_3B (I_V_3B << I_V_CL)
293
#define I_SOP (I_V_SOP << I_V_CL)
294
#define I_FOP (I_V_FOP << I_V_CL)
295
#define I_6B (I_V_6B << I_V_CL)
296
#define I_BR (I_V_BR << I_V_CL)
297
#define I_8B (I_V_8B << I_V_CL)
298
#define I_AFOP (I_V_AFOP << I_V_CL)
299
#define I_ASOP (I_V_ASOP << I_V_CL)
300
#define I_RSOP (I_V_RSOP << I_V_CL)
301
#define I_SOB (I_V_SOB << I_V_CL)
302
#define I_ASMD (I_V_ASMD << I_V_CL)
303
#define I_DOP (I_V_DOP << I_V_CL)
304
#define I_CCC (I_V_CCC << I_V_CL)
305
#define I_CCS (I_V_CCS << I_V_CL)
307
static const int32 masks[] = {
308
0177777, 0177770, 0177700, 0177770,
309
0177700+I_D, 0177400+I_D, 0177700, 0177400,
310
0177400, 0177000, 0177000, 0177400,
311
0177400+I_D+I_L, 0170000, 0177777, 0177777 };
313
static const char *opcode[] = {
314
"HALT","WAIT","RTI","BPT",
315
"IOT","RESET","RTT","MFPT",
317
"NOP","CLC","CLV","CLV CLC",
318
"CLZ","CLZ CLC","CLZ CLV","CLZ CLV CLC",
319
"CLN","CLN CLC","CLN CLV","CLN CLV CLC",
320
"CLN CLZ","CLN CLZ CLC","CLN CLZ CLC","CCC",
321
"NOP","SEC","SEV","SEV SEC",
322
"SEZ","SEZ SEC","SEZ SEV","SEZ SEV SEC",
323
"SEN","SEN SEC","SEN SEV","SEN SEV SEC",
324
"SEN SEZ","SEN SEZ SEC","SEN SEZ SEC","SCC",
325
"SWAB","BR","BNE","BEQ",
326
"BGE","BLT","BGT","BLE",
328
"CLR","COM","INC","DEC",
329
"NEG","ADC","SBC","TST",
330
"ROR","ROL","ASR","ASL",
331
"MARK","MFPI","MTPI","SXT",
332
"CSM", "TSTSET","WRTLCK",
333
"MOV","CMP","BIT","BIC",
335
"MUL","DIV","ASH","ASHC",
337
"FADD","FSUB","FMUL","FDIV",
339
"MOVC","MOVRC","MOVTC",
340
"LOCC","SKPC","SCANC","SPANC",
342
"ADDN","SUBN","CMPN","CVTNL",
343
"CVTPN","CVTNP","ASHN","CVTLN",
345
"ADDP","SUBP","CMPP","CVTPL",
346
"MULP","DIVP","ASHP","CVTLP",
347
"MOVCI","MOVRCI","MOVTCI",
348
"LOCCI","SKPCI","SCANCI","SPANCI",
350
"ADDNI","SUBNI","CMPNI","CVTNLI",
351
"CVTPNI","CVTNPI","ASHNI","CVTLNI",
352
"ADDPI","SUBPI","CMPPI","CVTPLI",
353
"MULPI","DIVPI","ASHPI","CVTLPI",
355
"BPL","BMI","BHI","BLOS",
356
"BVC","BVS","BCC","BCS",
357
"BHIS","BLO", /* encode only */
359
"CLRB","COMB","INCB","DECB",
360
"NEGB","ADCB","SBCB","TSTB",
361
"RORB","ROLB","ASRB","ASLB",
362
"MTPS","MFPD","MTPD","MFPS",
363
"MOVB","CMPB","BITB","BICB",
365
"CFCC","SETF","SETI","SETD","SETL",
366
"LDFPS","STFPS","STST",
367
"CLRF","CLRD","TSTF","TSTD",
368
"ABSF","ABSD","NEGF","NEGD",
369
"MULF","MULD","MODF","MODD",
370
"ADDF","ADDD","LDF","LDD",
371
"SUBF","SUBD","CMPF","CMPD",
372
"STF","STD","DIVF","DIVD",
374
"STCFI","STCDI","STCFL","STCDL",
377
"LDCIF","LDCID","LDCLF","LDCLD",
381
static const int32 opc_val[] = {
382
0000000+I_NPN, 0000001+I_NPN, 0000002+I_NPN, 0000003+I_NPN,
383
0000004+I_NPN, 0000005+I_NPN, 0000006+I_NPN, 0000007+I_NPN,
384
0000100+I_SOP, 0000200+I_REG, 0000230+I_3B,
385
0000240+I_CCC, 0000241+I_CCC, 0000242+I_CCC, 0000243+I_NPN,
386
0000244+I_CCC, 0000245+I_NPN, 0000246+I_NPN, 0000247+I_NPN,
387
0000250+I_CCC, 0000251+I_NPN, 0000252+I_NPN, 0000253+I_NPN,
388
0000254+I_NPN, 0000255+I_NPN, 0000256+I_NPN, 0000257+I_CCC,
389
0000260+I_CCS, 0000261+I_CCS, 0000262+I_CCS, 0000263+I_NPN,
390
0000264+I_CCS, 0000265+I_NPN, 0000266+I_NPN, 0000267+I_NPN,
391
0000270+I_CCS, 0000271+I_NPN, 0000272+I_NPN, 0000273+I_NPN,
392
0000274+I_NPN, 0000275+I_NPN, 0000276+I_NPN, 0000277+I_CCS,
393
0000300+I_SOP, 0000400+I_BR, 0001000+I_BR, 0001400+I_BR,
394
0002000+I_BR, 0002400+I_BR, 0003000+I_BR, 0003400+I_BR,
396
0005000+I_SOP, 0005100+I_SOP, 0005200+I_SOP, 0005300+I_SOP,
397
0005400+I_SOP, 0005500+I_SOP, 0005600+I_SOP, 0005700+I_SOP,
398
0006000+I_SOP, 0006100+I_SOP, 0006200+I_SOP, 0006300+I_SOP,
399
0006400+I_6B, 0006500+I_SOP, 0006600+I_SOP, 0006700+I_SOP,
400
0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP,
401
0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP,
402
0050000+I_DOP, 0060000+I_DOP,
403
0070000+I_RSOP, 0071000+I_RSOP, 0072000+I_RSOP, 0073000+I_RSOP,
405
0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG,
407
0076030+I_NPN, 0076031+I_NPN, 0076032+I_NPN,
408
0076040+I_NPN, 0076041+I_NPN, 0076042+I_NPN, 0076043+I_NPN,
409
0076044+I_NPN, 0076045+I_NPN,
410
0076050+I_NPN, 0076051+I_NPN, 0076052+I_NPN, 0076053+I_NPN,
411
0076054+I_NPN, 0076055+I_NPN, 0076056+I_NPN, 0076057+I_NPN,
413
0076070+I_NPN, 0076071+I_NPN, 0076072+I_NPN, 0076073+I_NPN,
414
0076074+I_NPN, 0076075+I_NPN, 0076076+I_NPN, 0076077+I_NPN,
415
0076130+I_NPN, 0076131+I_NPN, 0076132+I_NPN,
416
0076140+I_NPN, 0076141+I_NPN, 0076142+I_NPN, 0076143+I_NPN,
417
0076144+I_NPN, 0076145+I_NPN,
418
0076150+I_NPN, 0076151+I_NPN, 0076152+I_NPN, 0076153+I_NPN,
419
0076154+I_NPN, 0076155+I_NPN, 0076156+I_NPN, 0076157+I_NPN,
420
0076170+I_NPN, 0076171+I_NPN, 0076172+I_NPN, 0076173+I_NPN,
421
0076174+I_NPN, 0076175+I_NPN, 0076176+I_NPN, 0076177+I_NPN,
423
0100000+I_BR, 0100400+I_BR, 0101000+I_BR, 0101400+I_BR,
424
0102000+I_BR, 0102400+I_BR, 0103000+I_BR, 0103400+I_BR,
425
0103000+I_BR, 0103400+I_BR,
426
0104000+I_8B, 0104400+I_8B,
427
0105000+I_SOP, 0105100+I_SOP, 0105200+I_SOP, 0105300+I_SOP,
428
0105400+I_SOP, 0105500+I_SOP, 0105600+I_SOP, 0105700+I_SOP,
429
0106000+I_SOP, 0106100+I_SOP, 0106200+I_SOP, 0106300+I_SOP,
430
0106400+I_SOP, 0106500+I_SOP, 0106600+I_SOP, 0106700+I_SOP,
431
0110000+I_DOP, 0120000+I_DOP, 0130000+I_DOP, 0140000+I_DOP,
432
0150000+I_DOP, 0160000+I_DOP,
433
0170000+I_NPN, 0170001+I_NPN, 0170002+I_NPN, 0170011+I_NPN, 0170012+I_NPN,
434
0170100+I_SOP, 0170200+I_SOP, 0170300+I_SOP,
435
0170400+I_FOP, 0170400+I_FOP+I_D, 0170500+I_FOP, 0170500+I_FOP+I_D,
436
0170600+I_FOP, 0170600+I_FOP+I_D, 0170700+I_FOP, 0170700+I_FOP+I_D,
437
0171000+I_AFOP, 0171000+I_AFOP+I_D, 0171400+I_AFOP, 0171400+I_AFOP+I_D,
438
0172000+I_AFOP, 0172000+I_AFOP+I_D, 0172400+I_AFOP, 0172400+I_AFOP+I_D,
439
0173000+I_AFOP, 0173000+I_AFOP+I_D, 0173400+I_AFOP, 0173400+I_AFOP+I_D,
440
0174000+I_AFOP, 0174000+I_AFOP+I_D, 0174400+I_AFOP, 0174400+I_AFOP+I_D,
442
0175400+I_ASMD, 0175400+I_ASMD+I_D, 0175400+I_ASMD+I_L, 0175400+I_ASMD+I_D+I_L,
443
0176000+I_AFOP, 0176000+I_AFOP+I_D,
445
0177000+I_ASMD, 0177000+I_ASMD+I_D, 0177000+I_ASMD+I_L, 0177000+I_ASMD+I_D+I_L,
446
0177400+I_AFOP, 0177400+I_AFOP+I_D,
449
static const char *rname [] =
450
{ "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC" };
452
static const char *fname [] =
453
{ "F0", "F1", "F2", "F3", "F4", "F5", "?6", "?7" };
455
static const char r50_to_asc[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
464
flag = TRUE if decoding for CPU
465
iflag = TRUE if decoding integer instruction
467
count = -number of extra words retired
470
int32 fprint_spec (FILE *of, t_addr addr, int32 spec, t_value nval,
471
int32 flag, int32 iflag)
474
static const int32 rgwd[8] = { 0, 0, 0, 0, 0, 0, -1, -1 };
475
static const int32 pcwd[8] = { 0, 0, -1, -1, 0, 0, -1, -1 };
478
mode = ((spec >> 3) & 07);
481
if (iflag) fprintf (of, "%s", rname[reg]);
482
else fprintf (of, "%s", fname[reg]);
485
fprintf (of, "(%s)", rname[reg]);
488
if (reg != 7) fprintf (of, "(%s)+", rname[reg]);
489
else fprintf (of, "#%-o", nval);
492
if (reg != 7) fprintf (of, "@(%s)+", rname[reg]);
493
else fprintf (of, "@#%-o", nval);
496
fprintf (of, "-(%s)", rname[reg]);
499
fprintf (of, "@-(%s)", rname[reg]);
502
if ((reg != 7) || !flag) fprintf (of, "%-o(%s)", nval, rname[reg]);
503
else fprintf (of, "%-o", (nval + addr + 4) & 0177777);
506
if ((reg != 7) || !flag) fprintf (of, "@%-o(%s)", nval, rname[reg]);
507
else fprintf (of, "@%-o", (nval + addr + 4) & 0177777);
508
break; } /* end case */
509
return ((reg == 07)? pcwd[mode]: rgwd[mode]);
517
*val = values to decode
518
*uptr = pointer to unit
521
return = if >= 0, error code
522
if < 0, number of extra words retired
525
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
526
UNIT *uptr, int32 sw)
528
int32 cflag, i, j, c1, c2, c3, inst, fac, srcm, srcr, dstm, dstr;
529
int32 l8b, brdisp, wd1, wd2;
532
cflag = (uptr == NULL) || (uptr == &cpu_unit);
534
c2 = (val[0] >> 8) & 0177;
535
if (sw & SWMASK ('A')) { /* ASCII? */
536
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
538
if (sw & SWMASK ('C')) { /* character? */
539
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
540
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
542
if (sw & SWMASK ('R')) { /* radix 50? */
543
if (val[0] > 0174777) return SCPE_ARG; /* max value */
545
c2 = (val[0] / 050) % 050;
546
c1 = val[0] / (050 * 050);
547
fprintf (of, "%c%c%c", r50_to_asc[c1],
548
r50_to_asc[c2], r50_to_asc[c3]);
550
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
552
inst = val[0] | ((FPS << (I_V_L - FPS_V_L)) & I_L) |
553
((FPS << (I_V_D - FPS_V_D)) & I_D); /* inst + fp mode */
554
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
555
j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */
556
if ((opc_val[i] & 0777777) == (inst & masks[j])) { /* match? */
557
srcm = (inst >> 6) & 077; /* opr fields */
564
/* Instruction decode */
566
switch (j) { /* case on class */
567
case I_V_NPN: case I_V_CCC: case I_V_CCS: /* no operands */
568
fprintf (of, "%s", opcode[i]);
570
case I_V_REG: /* reg */
571
fprintf (of, "%s %-s", opcode[i], rname[dstr]);
573
case I_V_SOP: /* sop */
574
fprintf (of, "%s ", opcode[i]);
575
return fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
576
case I_V_3B: /* 3b */
577
fprintf (of, "%s %-o", opcode[i], dstr);
579
case I_V_FOP: /* fop */
580
fprintf (of, "%s ", opcode[i]);
581
return fprint_spec (of, addr, dstm, val[1], cflag, FALSE);
582
case I_V_AFOP: /* afop */
583
fprintf (of, "%s %s,", opcode[i], fname[fac]);
584
return fprint_spec (of, addr, dstm, val[1], cflag, FALSE);
585
case I_V_6B: /* 6b */
586
fprintf (of, "%s %-o", opcode[i], dstm);
588
case I_V_BR: /* cond branch */
589
fprintf (of, "%s ", opcode[i]);
590
brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777;
591
if (cflag) fprintf (of, "%-o", (addr + brdisp) & 0177777);
592
else if (brdisp < 01000) fprintf (of, ".+%-o", brdisp);
593
else fprintf (of, ".-%-o", 0200000 - brdisp);
595
case I_V_8B: /* 8b */
596
fprintf (of, "%s %-o", opcode[i], l8b);
598
case I_V_SOB: /* sob */
599
fprintf (of, "%s %s,", opcode[i], rname[srcr]);
600
brdisp = (dstm * 2) - 2;
601
if (cflag) fprintf (of, "%-o", (addr - brdisp) & 0177777);
602
else if (brdisp <= 0) fprintf (of, ".+%-o", -brdisp);
603
else fprintf (of, ".-%-o", brdisp);
605
case I_V_RSOP: /* rsop */
606
fprintf (of, "%s %s,", opcode[i], rname[srcr]);
607
return fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
608
case I_V_ASOP: case I_V_ASMD: /* asop, asmd */
609
fprintf (of, "%s %s,", opcode[i], fname[fac]);
610
return fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
611
case I_V_DOP: /* dop */
612
fprintf (of, "%s ", opcode[i]);
613
wd1 = fprint_spec (of, addr, srcm, val[1], cflag, TRUE);
615
wd2 = fprint_spec (of, addr - wd1 - wd1, dstm,
616
val[1 - wd1], cflag, TRUE);
617
return wd1 + wd2; } /* end case */
620
return SCPE_ARG; /* no match */
623
#define A_PND 100 /* # seen */
624
#define A_MIN 040 /* -( seen */
625
#define A_PAR 020 /* (Rn) seen */
626
#define A_REG 010 /* Rn seen */
627
#define A_PLS 004 /* + seen */
628
#define A_NUM 002 /* number seen */
629
#define A_REL 001 /* relative addr seen */
634
*cptr = pointer to input string
635
*strings = pointer to register names
636
mchar = character to match after register name
638
rnum = 0..7 if a legitimate register
642
int32 get_reg (char *cptr, const char *strings[], char mchar)
646
if (*(cptr + 2) != mchar) return -1;
647
for (i = 0; i < 8; i++) {
648
if (strncmp (cptr, strings[i], 2) == 0) return i; }
652
/* Number or memory address
655
*cptr = pointer to input string
656
*dptr = pointer to output displacement
657
*pflag = pointer to accumulating flags
659
cptr = pointer to next character in input string
660
NULL if parsing error
662
Flags: 0 (no result), A_NUM (number), A_REL (relative)
665
char *get_addr (char *cptr, int32 *dptr, int32 *pflag)
672
if (*cptr == '.') { /* relative? */
673
*pflag = *pflag | A_REL;
675
if (*cptr == '+') { /* +? */
676
*pflag = *pflag | A_NUM;
678
if (*cptr == '-') { /* -? */
679
*pflag = *pflag | A_NUM;
683
val = strtoul (cptr, &tptr, 8);
684
if (cptr == tptr) { /* no number? */
685
if (*pflag == (A_REL + A_NUM)) return NULL; /* .+, .-? */
688
if (errno || (*pflag == A_REL)) return NULL; /* .n? */
689
*dptr = (minus? -val: val) & 0177777;
690
*pflag = *pflag | A_NUM;
697
*cptr = pointer to input string
699
n1 = 0 if no extra word used
700
-1 if extra word used in prior decode
701
*sptr = pointer to output specifier
702
*dptr = pointer to output displacement
703
cflag = true if parsing for the CPU
704
iflag = true if integer specifier
706
status = = -1 extra word decoded
711
t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr,
712
int32 cflag, int32 iflag)
714
int32 reg, indir, pflag, disp;
716
indir = 0; /* no indirect */
719
if (*cptr == '@') { /* indirect? */
722
if (*cptr == '#') { /* literal? */
723
pflag = pflag | A_PND;
725
if (strncmp (cptr, "-(", 2) == 0) { /* autodecrement? */
726
pflag = pflag | A_MIN;
728
else if ((cptr = get_addr (cptr, &disp, &pflag)) == NULL) return 1;
729
if (*cptr == '(') { /* register index? */
730
pflag = pflag | A_PAR;
731
if ((reg = get_reg (cptr + 1, rname, ')')) < 0) return 1;
733
if (*cptr == '+') { /* autoincrement? */
734
pflag = pflag | A_PLS;
736
else if ((reg = get_reg (cptr, iflag? rname: fname, 0)) >= 0) {
737
pflag = pflag | A_REG;
739
if (*cptr != 0) return 1; /* all done? */
741
/* Specifier decode, continued */
743
switch (pflag) { /* case on syntax */
744
case A_REG: /* Rn, @Rn */
747
case A_PAR: /* (Rn), @(Rn) */
748
if (indir) { /* @(Rn) = @0(Rn) */
752
else *sptr = 010 + reg;
754
case A_PAR+A_PLS: /* (Rn)+, @(Rn)+ */
755
*sptr = 020 + indir + reg;
757
case A_MIN+A_PAR: /* -(Rn), @-(Rn) */
758
*sptr = 040 + indir + reg;
760
case A_NUM+A_PAR: /* d(Rn), @d(Rn) */
761
*sptr = 060 + indir + reg;
764
case A_PND+A_REL: case A_PND+A_REL+A_NUM: /* #.+n, @#.+n */
765
if (!cflag) return 1;
766
disp = (disp + addr) & 0177777; /* fall through */
767
case A_PND+A_NUM: /* #n, @#n */
771
case A_REL: case A_REL+A_NUM: /* .+n, @.+n */
773
*dptr = (disp - 4 + (2 * n1)) & 0177777;
775
case A_NUM: /* n, @n */
776
if (cflag) { /* CPU - use rel */
778
*dptr = (disp - addr - 4 + (2 * n1)) & 0177777; }
779
else { if (indir) return 1; /* other - use abs */
784
return 1; } /* end case */
790
*cptr = pointer to input string
792
*uptr = pointer to unit
793
*val = pointer to output values
796
status = > 0 error code
797
<= 0 -number of extra words
800
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
802
int32 cflag, d, i, j, reg, spec, n1, n2, disp, pflag;
804
char *tptr, gbuf[CBUFSIZE];
806
cflag = (uptr == NULL) || (uptr == &cpu_unit);
807
while (isspace (*cptr)) cptr++; /* absorb spaces */
808
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
809
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
810
val[0] = (t_value) cptr[0];
812
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
813
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
814
val[0] = ((t_value) cptr[1] << 8) + (t_value) cptr[0];
816
if (sw & SWMASK ('R')) return SCPE_ARG; /* radix 50 */
818
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
820
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
821
if (opcode[i] == NULL) return SCPE_ARG;
822
val[0] = opc_val[i] & 0177777; /* get value */
823
j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */
825
switch (j) { /* case on class */
826
case I_V_NPN: /* no operand */
828
case I_V_REG: /* register */
829
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
830
if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
831
val[0] = val[0] | reg;
833
case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */
834
cptr = get_glyph (cptr, gbuf, 0); /* get literal */
835
d = get_uint (gbuf, 8, (1 << j) - 1, &r);
836
if (r != SCPE_OK) return SCPE_ARG;
837
val[0] = val[0] | d; /* put in place */
839
case I_V_BR: /* cond br */
840
cptr = get_glyph (cptr, gbuf, 0); /* get address */
841
tptr = get_addr (gbuf, &disp, &pflag); /* parse */
842
if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG;
843
if ((pflag & A_REL) == 0) {
844
if (cflag) disp = (disp - addr) & 0177777;
845
else return SCPE_ARG; }
846
if ((disp & 1) || (disp > 0400) && (disp < 0177402)) return SCPE_ARG;
847
val[0] = val[0] | (((disp - 2) >> 1) & 0377);
849
case I_V_SOB: /* sob */
850
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
851
if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
852
val[0] = val[0] | (reg << 6);
853
cptr = get_glyph (cptr, gbuf, 0); /* get address */
854
tptr = get_addr (gbuf, &disp, &pflag); /* parse */
855
if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG;
856
if ((pflag & A_REL) == 0) {
857
if (cflag) disp = (disp - addr) & 0177777;
858
else return SCPE_ARG; }
859
if ((disp & 1) || ((disp > 2) && (disp < 0177604))) return SCPE_ARG;
860
val[0] = val[0] | (((2 - disp) >> 1) & 077);
862
case I_V_RSOP: /* reg, sop */
863
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
864
if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
865
val[0] = val[0] | (reg << 6); /* fall through */
866
case I_V_SOP: /* sop */
867
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
868
if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
870
val[0] = val[0] | spec;
872
case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */
873
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
874
if ((reg = get_reg (gbuf, fname, 0)) < 0) return SCPE_ARG;
875
if (reg > 3) return SCPE_ARG;
876
val[0] = val[0] | (reg << 6); /* fall through */
877
case I_V_FOP: /* fop */
878
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
879
if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag,
880
(j == I_V_ASOP) || (j == I_V_ASMD))) > 0) return SCPE_ARG;
881
val[0] = val[0] | spec;
883
case I_V_DOP: /* double op */
884
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
885
if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
887
val[0] = val[0] | (spec << 6);
888
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
889
if ((n2 = get_spec (gbuf, addr, n1, &spec, &val[1 - n1],
890
cflag, TRUE)) > 0) return SCPE_ARG;
891
val[0] = val[0] | spec;
893
case I_V_CCC: case I_V_CCS: /* cond code oper */
894
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
895
cptr = get_glyph (cptr, gbuf, 0)) {
896
for (i = 0; (opcode[i] != NULL) &&
897
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
898
if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) ||
899
(opcode[i] == NULL)) return SCPE_ARG;
900
val[0] = val[0] | (opc_val[i] & 0177777); }
904
if (*cptr != 0) return SCPE_ARG; /* junk at end? */