1 /* pdp11_sys.c: PDP-11 simulator interface
3 Copyright (c) 1993-2008, 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 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.
26 15-May-08 RMS Added KE11-A, DC11 support
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
64 #include "pdp11_defs.h"
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
;
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
;
91 extern DEVICE mba_dev
[];
93 extern DEVICE rq_dev
, rqb_dev
, rqc_dev
, rqd_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
[];
106 extern int32 saved_PC
;
108 /* SCP data structures and interface routines
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
118 char sim_name
[] = "PDP-11";
120 REG
*sim_PC
= &cpu_reg
[0];
124 DEVICE
*sim_devices
[] = {
170 const char *sim_stop_messages
[] = {
174 "Memory management trap",
175 "Non-existent memory trap",
178 "Illegal instruction trap",
186 "Floating point exception",
190 "Trap vector fetch abort",
191 "Trap stack push abort",
192 "RQDX3 consistency error",
193 "Sanity timer expired",
199 Loader format consists of blocks, optionally preceded, separated, and
200 followed by zeroes. Each block consists of:
206 lo_origin > count bytes
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.
218 t_stat
sim_load (FILE *fileref
, char *cptr
, char *fnam
, int flag
)
220 int32 c
[6], d
, i
, cnt
, csum
;
223 if ((*cptr
!= 0) || (flag
!= 0))
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
)
230 if ((i
!= 0) || (c
[i
] == 1)) /* 1st must be 1 */
231 csum
= csum
+ c
[i
++]; /* add into csum */
233 cnt
= (c
[3] << 8) | c
[2]; /* count */
234 org
= (c
[5] << 8) | c
[4]; /* origin */
235 if (cnt
< 6) /* invalid? */
237 if (cnt
== 6) { /* end block? */
238 if (org
!= 1) /* set PC? */
239 saved_PC
= org
& 0177776;
242 for (i
= 6; i
< cnt
; i
++) { /* exclude hdr */
243 if ((d
= getc (fileref
)) == EOF
) /* data char */
245 csum
= csum
+ d
; /* add into csum */
246 if (org
>= MEMSIZE
) /* invalid addr? */
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 */
253 if ((d
= getc (fileref
)) == EOF
) /* get csum */
255 csum
= csum
+ d
; /* add in */
256 } while ((csum
& 0377) == 0); /* result mbz */
260 /* Factory bad block table creation routine
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:
266 words 0-1 pack id number
267 words 2-3 cylinder/sector/surface specifications
269 words n-n+1 end of table (-1,-1)
272 uptr = pointer to unit
273 sec = number of sectors per surface
274 wds = number of words per sector
279 t_stat
pdp11_bad_block (UNIT
*uptr
, int32 sec
, int32 wds
)
284 if ((sec
< 2) || (wds
< 16))
286 if ((uptr
->flags
& UNIT_ATT
) == 0)
288 if (uptr
->flags
& UNIT_RO
)
290 if (!get_yn ("Create bad block table on last track? [N]", FALSE
))
292 da
= (uptr
->capac
- (sec
* wds
)) * sizeof (uint16
);
293 if (fseek (uptr
->fileref
, da
, SEEK_SET
))
295 if ((buf
= (uint16
*) malloc (wds
* sizeof (uint16
))) == NULL
)
297 buf
[0] = buf
[1] = 012345u;
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
);
303 if (ferror (uptr
->fileref
))
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)
315 /* Warning: for literals, the class number MUST equal the field width!! */
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)
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,
362 static const char *opcode
[] = {
363 "HALT","WAIT","RTI","BPT",
364 "IOT","RESET","RTT","MFPT",
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",
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",
384 "MUL","DIV","ASH","ASHC",
386 "FADD","FSUB","FMUL","FDIV",
388 "MOVC","MOVRC","MOVTC",
389 "LOCC","SKPC","SCANC","SPANC",
391 "ADDN","SUBN","CMPN","CVTNL",
392 "CVTPN","CVTNP","ASHN","CVTLN",
394 "ADDP","SUBP","CMPP","CVTPL",
395 "MULP","DIVP","ASHP","CVTLP",
396 "MOVCI","MOVRCI","MOVTCI",
397 "LOCCI","SKPCI","SCANCI","SPANCI",
399 "ADDNI","SUBNI","CMPNI","CVTNLI",
400 "CVTPNI","CVTNPI","ASHNI","CVTLNI",
401 "ADDPI","SUBPI","CMPPI","CVTPLI",
402 "MULPI","DIVPI","ASHPI","CVTLPI",
404 "BPL","BMI","BHI","BLOS",
405 "BVC","BVS","BCC","BCS",
406 "BHIS","BLO", /* encode only */
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",
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",
423 "STCFI","STCDI","STCFL","STCDL",
426 "LDCIF","LDCID","LDCLF","LDCLD",
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
,
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
,
455 0075000+I_REG
, 0075010+I_REG
, 0075020+I_REG
, 0075030+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
,
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
,
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
,
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
,
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
,
500 static const char *rname
[] = {
501 "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC"
504 static const char *fname
[] = {
505 "F0", "F1", "F2", "F3", "F4", "F5", "?6", "?7"
508 static const char r50_to_asc
[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
517 flag = TRUE if decoding for CPU
518 iflag = TRUE if decoding integer instruction
520 count = -number of extra words retired
523 int32
fprint_spec (FILE *of
, t_addr addr
, int32 spec
, t_value nval
,
524 int32 flag
, int32 iflag
)
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 };
531 mode
= ((spec
>> 3) & 07);
536 fprintf (of
, "%s", rname
[reg
]);
537 else fprintf (of
, "%s", fname
[reg
]);
541 fprintf (of
, "(%s)", rname
[reg
]);
546 fprintf (of
, "(%s)+", rname
[reg
]);
547 else fprintf (of
, "#%-o", nval
);
552 fprintf (of
, "@(%s)+", rname
[reg
]);
553 else fprintf (of
, "@#%-o", nval
);
557 fprintf (of
, "-(%s)", rname
[reg
]);
561 fprintf (of
, "@-(%s)", rname
[reg
]);
565 if ((reg
!= 7) || !flag
)
566 fprintf (of
, "%-o(%s)", nval
, rname
[reg
]);
567 else fprintf (of
, "%-o", (nval
+ addr
+ 4) & 0177777);
571 if ((reg
!= 7) || !flag
)
572 fprintf (of
, "@%-o(%s)", nval
, rname
[reg
]);
573 else fprintf (of
, "@%-o", (nval
+ addr
+ 4) & 0177777);
577 return ((reg
== 07)? pcwd
[mode
]: rgwd
[mode
]);
585 *val = values to decode
586 *uptr = pointer to unit
589 return = if >= 0, error code
590 if < 0, number of extra words retired
593 t_stat
fprint_sym (FILE *of
, t_addr addr
, t_value
*val
,
594 UNIT
*uptr
, int32 sw
)
596 int32 cflag
, i
, j
, c1
, c2
, c3
, inst
, fac
, srcm
, srcr
, dstm
, dstr
;
597 int32 bflag
, l8b
, brdisp
, wd1
, wd2
;
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
);
606 if (dptr
->dwidth
< 16)
610 if (sw
& SWMASK ('A')) { /* ASCII? */
613 else c1
= (val
[0] >> ((addr
& 1)? 8: 0)) & 0177;
614 fprintf (of
, (c1
< 040)? "<%03o>": "%c", c1
);
617 if (sw
& SWMASK ('B')) { /* byte? */
620 else c1
= (val
[0] >> ((addr
& 1)? 8: 0)) & 0377;
621 fprintf (of
, "%o", c1
);
624 if (bflag
) return SCPE_ARG
; /* 16b only */
626 if (sw
& SWMASK ('C')) { /* character? */
628 c2
= (val
[0] >> 8) & 0177;
629 fprintf (of
, (c1
< 040)? "<%03o>": "%c", c1
);
630 fprintf (of
, (c2
< 040)? "<%03o>": "%c", c2
);
633 if (sw
& SWMASK ('R')) { /* radix 50? */
634 if (val
[0] > 0174777) return SCPE_ARG
; /* max value */
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
]);
642 if (!(sw
& SWMASK ('M'))) return SCPE_ARG
;
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 */
656 switch (j
) { /* case on class */
658 case I_V_NPN
: case I_V_CCC
: case I_V_CCS
: /* no operands */
659 fprintf (of
, "%s", opcode
[i
]);
662 case I_V_REG
: /* reg */
663 fprintf (of
, "%s %-s", opcode
[i
], rname
[dstr
]);
666 case I_V_SOP
: /* sop */
667 fprintf (of
, "%s ", opcode
[i
]);
668 wd1
= fprint_spec (of
, addr
, dstm
, val
[1], cflag
, TRUE
);
671 case I_V_3B
: /* 3b */
672 fprintf (of
, "%s %-o", opcode
[i
], dstr
);
675 case I_V_FOP
: /* fop */
676 fprintf (of
, "%s ", opcode
[i
]);
677 wd1
= fprint_spec (of
, addr
, dstm
, val
[1], cflag
, FALSE
);
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
);
685 case I_V_6B
: /* 6b */
686 fprintf (of
, "%s %-o", opcode
[i
], dstm
);
689 case I_V_BR
: /* cond branch */
690 fprintf (of
, "%s ", opcode
[i
]);
691 brdisp
= (l8b
+ l8b
+ ((l8b
& 0200)? 0177002: 2)) & 0177777;
693 fprintf (of
, "%-o", (addr
+ brdisp
) & 0177777);
694 else if (brdisp
< 01000)
695 fprintf (of
, ".+%-o", brdisp
);
696 else fprintf (of
, ".-%-o", 0200000 - brdisp
);
699 case I_V_8B
: /* 8b */
700 fprintf (of
, "%s %-o", opcode
[i
], l8b
);
703 case I_V_SOB
: /* sob */
704 fprintf (of
, "%s %s,", opcode
[i
], rname
[srcr
]);
705 brdisp
= (dstm
* 2) - 2;
707 fprintf (of
, "%-o", (addr
- brdisp
) & 0177777);
708 else if (brdisp
<= 0)
709 fprintf (of
, ".+%-o", -brdisp
);
710 else fprintf (of
, ".-%-o", brdisp
);
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
);
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
]);
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
);
729 case I_V_DOP
: /* dop */
730 fprintf (of
, "%s ", opcode
[i
]);
731 wd1
= fprint_spec (of
, addr
, srcm
, val
[1], cflag
, TRUE
);
733 wd2
= fprint_spec (of
, addr
- wd1
- wd1
, dstm
,
734 val
[1 - wd1
], cflag
, TRUE
);
737 return ((wd1
+ wd2
) * 2) - 1;
740 return SCPE_ARG
; /* no match */
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 */
754 *cptr = pointer to input string
755 *strings = pointer to register names
756 mchar = character to match after register name
758 rnum = 0..7 if a legitimate register
762 int32
get_reg (char *cptr
, const char *strings
[], char mchar
)
766 if (*(cptr
+ 2) != mchar
) return -1;
767 for (i
= 0; i
< 8; i
++) {
768 if (strncmp (cptr
, strings
[i
], 2) == 0)
774 /* Number or memory address
777 *cptr = pointer to input string
778 *dptr = pointer to output displacement
779 *pflag = pointer to accumulating flags
781 cptr = pointer to next character in input string
782 NULL if parsing error
784 Flags: 0 (no result), A_NUM (number), A_REL (relative)
787 char *get_addr (char *cptr
, int32
*dptr
, int32
*pflag
)
794 if (*cptr
== '.') { /* relative? */
795 *pflag
= *pflag
| A_REL
;
798 if (*cptr
== '+') { /* +? */
799 *pflag
= *pflag
| A_NUM
;
802 if (*cptr
== '-') { /* -? */
803 *pflag
= *pflag
| A_NUM
;
808 val
= strtoul (cptr
, &tptr
, 8);
809 if (cptr
== tptr
) { /* no number? */
810 if (*pflag
== (A_REL
+ A_NUM
)) /* .+, .-? */
815 if (errno
|| (*pflag
== A_REL
)) /* .n? */
817 *dptr
= (minus
? -val
: val
) & 0177777;
818 *pflag
= *pflag
| A_NUM
;
825 *cptr = pointer to input string
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
834 status = = -1 extra word decoded
839 t_stat
get_spec (char *cptr
, t_addr addr
, int32 n1
, int32
*sptr
, t_value
*dptr
,
840 int32 cflag
, int32 iflag
)
842 int32 reg
, indir
, pflag
, disp
;
844 indir
= 0; /* no indirect */
847 if (*cptr
== '@') { /* indirect? */
851 if (*cptr
== '#') { /* literal? */
852 pflag
= pflag
| A_PND
;
855 if (strncmp (cptr
, "-(", 2) == 0) { /* autodecrement? */
856 pflag
= pflag
| A_MIN
;
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)
865 if (*cptr
== '+') { /* autoincrement? */
866 pflag
= pflag
| A_PLS
;
870 else if ((reg
= get_reg (cptr
, iflag
? rname
: fname
, 0)) >= 0) {
871 pflag
= pflag
| A_REG
;
874 if (*cptr
!= 0) /* all done? */
876 switch (pflag
) { /* case on syntax */
878 case A_REG
: /* Rn, @Rn */
882 case A_PAR
: /* (Rn), @(Rn) */
883 if (indir
) { /* @(Rn) = @0(Rn) */
888 else *sptr
= 010 + reg
;
891 case A_PAR
+A_PLS
: /* (Rn)+, @(Rn)+ */
892 *sptr
= 020 + indir
+ reg
;
895 case A_MIN
+A_PAR
: /* -(Rn), @-(Rn) */
896 *sptr
= 040 + indir
+ reg
;
899 case A_NUM
+A_PAR
: /* d(Rn), @d(Rn) */
900 *sptr
= 060 + indir
+ reg
;
904 case A_PND
+A_REL
: case A_PND
+A_REL
+A_NUM
: /* #.+n, @#.+n */
907 disp
= (disp
+ addr
) & 0177777; /* fall through */
908 case A_PND
+A_NUM
: /* #n, @#n */
913 case A_REL
: case A_REL
+A_NUM
: /* .+n, @.+n */
915 *dptr
= (disp
- 4 + (2 * n1
)) & 0177777;
918 case A_NUM
: /* n, @n */
919 if (cflag
) { /* CPU - use rel */
921 *dptr
= (disp
- addr
- 4 + (2 * n1
)) & 0177777;
924 if (indir
) return 1; /* other - use abs */
938 *cptr = pointer to input string
940 *uptr = pointer to unit
941 *val = pointer to output values
944 status = > 0 error code
945 <= 0 -number of extra words
948 t_stat
parse_sym (char *cptr
, t_addr addr
, UNIT
*uptr
, t_value
*val
, int32 sw
)
950 int32 bflag
, cflag
, d
, i
, j
, reg
, spec
, n1
, n2
, disp
, pflag
;
953 char *tptr
, gbuf
[CBUFSIZE
];
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
);
961 if (dptr
->dwidth
< 16)
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 */
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]);
976 if (sw
& SWMASK ('B')) { /* byte? */
977 by
= get_uint (cptr
, 8, 0377, &r
); /* get byte */
982 else val
[0] = (addr
& 1)?
983 (val
[0] & 0377) | (by
<< 8):
984 (val
[0] & ~0377) | by
;
987 if (bflag
) return SCPE_ARG
;
989 if ((sw
& SWMASK ('C')) || ((*cptr
== '"') && cptr
++)) { /* ASCII string? */
990 if (cptr
[0] == 0) /* must have 1 char */
992 val
[0] = ((t_value
) cptr
[1] << 8) | (t_value
) cptr
[0];
995 if (sw
& SWMASK ('R')) /* radix 50 */
998 cptr
= get_glyph (cptr
, gbuf
, 0); /* get opcode */
1000 for (i
= 0; (opcode
[i
] != NULL
) && (strcmp (opcode
[i
], gbuf
) != 0) ; i
++) ;
1001 if (opcode
[i
] == NULL
)
1003 val
[0] = opc_val
[i
] & 0177777; /* get value */
1004 j
= (opc_val
[i
] >> I_V_CL
) & I_M_CL
; /* get class */
1006 switch (j
) { /* case on class */
1008 case I_V_NPN
: /* no operand */
1011 case I_V_REG
: /* register */
1012 cptr
= get_glyph (cptr
, gbuf
, 0); /* get glyph */
1013 if ((reg
= get_reg (gbuf
, rname
, 0)) < 0)
1015 val
[0] = val
[0] | reg
;
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
);
1023 val
[0] = val
[0] | d
; /* put in place */
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))
1031 if ((pflag
& A_REL
) == 0) {
1032 if (cflag
) disp
= (disp
- addr
) & 0177777;
1033 else return SCPE_ARG
;
1035 if ((disp
& 1) || (disp
> 0400) && (disp
< 0177402))
1037 val
[0] = val
[0] | (((disp
- 2) >> 1) & 0377);
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))
1048 if ((pflag
& A_REL
) == 0) {
1049 if (cflag
) disp
= (disp
- addr
) & 0177777;
1050 else return SCPE_ARG
;
1052 if ((disp
& 1) || ((disp
> 2) && (disp
< 0177604)))
1054 val
[0] = val
[0] | (((2 - disp
) >> 1) & 077);
1057 case I_V_RSOP
: /* reg, sop */
1058 cptr
= get_glyph (cptr
, gbuf
, ','); /* get glyph */
1059 if ((reg
= get_reg (gbuf
, rname
, 0)) < 0)
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)
1066 val
[0] = val
[0] | spec
;
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)
1073 val
[0] = val
[0] | spec
;
1074 cptr
= get_glyph (cptr
, gbuf
, 0); /* get glyph */
1075 if ((reg
= get_reg (gbuf
, rname
, 0)) < 0)
1077 val
[0] = val
[0] | (reg
<< 6);
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)
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)
1092 val
[0] = val
[0] | spec
;
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)
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
],
1104 val
[0] = val
[0] | spec
;
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
))
1115 val
[0] = val
[0] | (opc_val
[i
] & 0177777);
1123 if (*cptr
!= 0) /* junk at end? */
1125 return ((n1
+ n2
) * 2) - 1;