1 /* ibm1130_sys.c: IBM 1130 simulator interface
3 Based on PDP-11 simulator written by Robert M Supnik
6 0.27 2005Mar08 - Added sca device
7 0.26 2002Apr24 - Added !BREAK in card deck file to stop simulator
8 0.25 2002Apr18 - Fixed some card reader problems. It starts the reader
9 properly if you attach a deck while it's waiting to a read.
10 0.24 2002Mar27 - Fixed BOSC bug; BOSC works in short instructions too
11 0.23 2002Feb26 - Added @decklist feature for ATTACH CR.
12 0.22 2002Feb26 - Replaced "strupr" with "upcase" for compatibility.
13 0.21 2002Feb25 - Some compiler compatibiity changes, couple of compiler-detected
15 0.01 2001Jul31 - Derived from pdp11_sys.c, which carries this disclaimer:
17 * (C) Copyright 2002, Brian Knittel.
18 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
19 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the
20 * usual yada-yada. Please keep this notice and the copyright in any distributions
23 * This is not a supported product, but I welcome bug reports and fixes.
24 * Mail to simh@ibm1130.org
27 #include "ibm1130_defs.h"
31 extern DEVICE cpu_dev
, console_dev
, dsk_dev
, cr_dev
, cp_dev
, ptr_dev
, ptp_dev
, t2741_dev
;
32 extern DEVICE tti_dev
, tto_dev
, prt_dev
, log_dev
, sca_dev
;
33 extern DEVICE gdu_dev
, console_dev
, plot_dev
;
37 extern int32 saved_PC
;
39 /* SCP data structures and interface routines
41 sim_name simulator name string
42 sim_PC pointer to saved PC register descriptor
43 sim_emax number of words for examine
44 sim_devices array of pointers to simulated devices
45 sim_stop_messages array of pointers to stop messages
46 sim_load binary loader
49 char sim_name
[] = "IBM 1130";
51 REG
*sim_PC
= &cpu_reg
[0];
55 DEVICE
*sim_devices
[] = {
56 &cpu_dev
, /* the cpu */
57 &dsk_dev
, /* disk drive(s) */
58 &cr_dev
, /* card reader/punch */
60 &tti_dev
, /* console keyboard, selectric printer */
62 &prt_dev
, /* 1132 printer */
63 &ptr_dev
, /* 1134 paper tape reader */
64 &ptp_dev
, /* 1055 paper tape punch */
65 &sca_dev
, /* Synchronous communications adapter option */
66 &console_dev
, /* console display (windows GUI) */
67 &gdu_dev
, /* 2250 display */
68 &t2741_dev
, /* nonstandard serial interface used by APL\1130 */
69 &plot_dev
, /* plotter device, in ibm1130_plot.c */
73 const char *sim_stop_messages
[] = {
77 "Simulator breakpoint",
78 "Use of incomplete simulator function",
80 "!BREAK in card deck file",
82 "Program has run amok",
83 "Run time limit exceeded",
84 "Immediate Stop key requested",
85 "Simulator break key pressed",
86 "Simulator step count expired",
90 /* Loader. IPL is normally performed by card reader (boot command). This function
91 * loads hex data from a file for testing purposes. The format is:
93 * blank lines or lines starting with ; / or # are ignored as comments
95 * @XXXX set load addresss to hex value XXXX
96 * XXXX store hex word value XXXX at current load address and increment address
98 * =XXXX set IAR to hex value XXXX
99 * ZXXXX zero XXXX words and increment load address
100 * SXXXX set console entry switches to XXXX. This lets a program specify the
101 * default value for the toggle switches.
103 * Multiple @ and data sections may be entered. If more than one = or S value is specified
106 * Note: the load address @XXXX and data values XXXX can be followed by the letter
107 * R to indicate that the values are relocatable addresses. This is ignored in this loader,
108 * but the asm1130 cross assembler may put them there.
111 t_stat
my_load (FILE *fileref
, char *cptr
, char *fnam
)
114 int iaddr
= -1, runaddr
= -1, val
, nwords
;
116 while (fgets(line
, sizeof(line
), fileref
) != NULL
) {
117 for (c
= line
; *c
&& *c
<= ' '; c
++) /* find first nonblank */
120 if (*c
== '\0' || *c
== '#' || *c
== '/' || *c
== ';')
121 continue; /* empty line or comment */
123 if (*c
== '@') { /* set load address */
124 if (sscanf(c
+1, "%x", &iaddr
) != 1)
127 else if (*c
== '=') {
128 if (sscanf(c
+1, "%x", &runaddr
) != 1)
131 else if (*c
== 's' || *c
== 'S') {
132 if (sscanf(c
+1, "%x", &val
) != 1)
135 CES
= val
& 0xFFFF; /*preload console entry switches */
137 else if (*c
== 'z' || *c
== 'Z') {
138 if (sscanf(c
+1, "%x", &nwords
) != 1)
144 while (--nwords
>= 0) {
149 else if (strchr("0123456789abcdefABCDEF", *c
) != NULL
) {
150 if (sscanf(c
, "%x", &val
) != 1)
156 WriteW(iaddr
, val
); /*store data */
160 return SCPE_FMT
; /*unexpected data */
169 t_stat
my_save (FILE *fileref
, char *cptr
, char *fnam
)
171 int iaddr
, nzeroes
= 0, nwords
= (int) (MEMSIZE
/2), val
;
173 fprintf(fileref
, "=%04x\r\n", IAR
);
174 fprintf(fileref
, "@0000\r\n");
175 for (iaddr
= 0; iaddr
< nwords
; iaddr
++) {
177 if (val
== 0) /*queue up zeroes */
180 if (nzeroes
>= 4) { /*spit out a Z directive */
181 fprintf(fileref
, "Z%04x\r\n", nzeroes
);
184 else { /*write queued zeroes literally */
185 while (nzeroes
> 0) {
186 fprintf(fileref
, " 0000\r\n");
190 fprintf(fileref
, " %04x\r\n", val
);
193 if (nzeroes
>= 4) { /*emit any queued zeroes */
194 fprintf(fileref
, "Z%04x\r\n", nzeroes
);
198 while (nzeroes
> 0) {
199 fprintf(fileref
, " 0000\r\n");
207 t_stat
sim_load (FILE *fileref
, char *cptr
, char *fnam
, int flag
)
210 return my_save(fileref
, cptr
, fnam
);
212 return my_load(fileref
, cptr
, fnam
);
222 flag = TRUE if decoding for CPU
223 iflag = TRUE if decoding integer instruction
225 count = -number of extra words retired
233 *val = values to decode
234 *uptr = pointer to unit
237 return = if >= 0, error code
238 if < 0, number of extra words retired
241 static char *opcode
[] = {
242 "?00 ", "XIO ", "SLA ", "SRA ",
243 "LDS ", "STS ", "WAIT", "?07 ",
244 "BSI ", "BSC ", "?0A ", "?0B ",
245 "LDX ", "STX ", "MDX ", "?0F ",
246 "A ", "AD ", "S ", "SD ",
247 "M ", "D ", "?16 ", "?17 ",
248 "LD ", "LDD ", "STO ", "STD ",
249 "AND ", "OR ", "EOR ", "?1F ",
252 static char relative
[] = { /*true if short mode displacements are IAR relative */
253 FALSE
, TRUE
, FALSE
, FALSE
,
254 FALSE
, TRUE
, FALSE
, FALSE
,
255 TRUE
, FALSE
, FALSE
, FALSE
,
256 TRUE
, TRUE
, TRUE
, FALSE
,
257 TRUE
, TRUE
, TRUE
, TRUE
,
258 TRUE
, TRUE
, FALSE
, FALSE
,
259 TRUE
, TRUE
, TRUE
, TRUE
,
260 TRUE
, TRUE
, TRUE
, FALSE
263 static char *lsopcode
[] = {"SLA ", "SLCA ", "SLT ", "SLC "};
264 static char *rsopcode
[] = {"SRA ", "?188 ", "SRT ", "RTE "};
265 static char tagc
[] = " 123";
267 static int ascii_to_ebcdic_table
[128] =
269 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
270 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
271 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
272 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
274 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
275 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d,
276 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
277 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
280 static int ebcdic_to_ascii (int ch
)
284 for (j
= 32; j
< 128; j
++)
285 if (ascii_to_ebcdic_table
[j
] == ch
)
291 t_stat
fprint_sym (FILE *of
, t_addr addr
, t_value
*val
, UNIT
*uptr
, int32 sw
)
293 int32 cflag
, ch
, OP
, F
, TAG
, INDIR
, DSPLC
, IR
, eaddr
;
296 cflag
= (uptr
== NULL
) || (uptr
== &cpu_unit
);
298 /* if (sw & SWMASK ('A')) { // ASCII? not useful
299 fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
304 if (sw
& SWMASK ('C')) /* character? not useful -- make it EBCDIC */
307 if (sw
& SWMASK ('E')) { /* EBCDIC! */
308 ch
= ebcdic_to_ascii((val
[0] >> 8) & 0xFF); /* take high byte first */
309 fprintf (of
, (ch
< ' ')? "<%03o>": "%c", ch
);
310 ch
= ebcdic_to_ascii(val
[0] & 0xFF);
311 fprintf (of
, (ch
< ' ')? "<%03o>": "%c", ch
);
315 if (sw
& SWMASK ('H')) { /* HOLLERITH! now THIS is useful! */
316 ch
= hollerith_to_ascii((int16
) val
[0]);
317 fprintf (of
, (ch
< ' ')? "<%03o>": "%c", ch
);
321 if (! (sw
& SWMASK ('M')))
325 OP
= (IR
>> 11) & 0x1F; /* opcode */
326 F
= IR
& 0x0400; /* format bit: 1 = long instr */
327 TAG
= IR
& 0x0300; /* tag bits: index reg select */
331 if (F
) { /* long instruction, ASSUME it's valid (have to decrement IAR if not) */
332 INDIR
= IR
& 0x0080; /* indirect bit */
333 DSPLC
= IR
& 0x007F; /* displacement or modifier */
335 DSPLC
|= ~ 0x7F; /* sign extend */
337 eaddr
= val
[1]; /* get reference address */
339 else { /* short instruction, use displacement */
340 INDIR
= 0; /* never indirect */
341 DSPLC
= IR
& 0x00FF; /* get displacement */
346 if (relative
[OP
] && ! TAG
)
347 eaddr
+= addr
+1; /* turn displacement into address */
350 mnem
= opcode
[OP
]; /* get mnemonic */
351 if (OP
== 0x02) { /* left shifts are special */
352 mnem
= lsopcode
[(DSPLC
>> 6) & 0x0003];
356 else if (OP
== 0x03) { /* right shifts too */
357 mnem
= rsopcode
[(DSPLC
>> 6) & 0x0003];
361 else if ((OP
== 0x08 && F
)|| OP
== 0x09) { /* BSI L and BSC any */
362 if (OP
== 0x09 && (IR
& 0x40))
366 if (DSPLC
& 0x20) strcat(tst
, "Z");
367 if (DSPLC
& 0x10) strcat(tst
, "-");
368 if (DSPLC
& 0x08) strcat(tst
, "+");
369 if (DSPLC
& 0x04) strcat(tst
, "E");
370 if (DSPLC
& 0x02) strcat(tst
, "C");
371 if (DSPLC
& 0x01) strcat(tst
, "O");
374 fprintf(of
, "%04x %s %c%c %s,%04x ", IR
& 0xFFFF, mnem
, F
? (INDIR
? 'I' : 'L') : ' ', tagc
[TAG
], tst
, eaddr
& 0xFFFF);
377 fprintf(of
, "%04x %s %c%c %s ", IR
& 0xFFFF, mnem
, F
? (INDIR
? 'I' : 'L') : ' ', tagc
[TAG
], tst
);
380 else if (OP
== 0x0e && TAG
== 0) { /* MDX with no tag => MDM or jump */
382 fprintf(of
, "%04x %s %c%c %04x,%x (%d) ", IR
& 0xFFFF, "MDM ", (INDIR
? 'I' : 'L'), tagc
[TAG
], eaddr
& 0xFFFF, DSPLC
& 0xFFFF, DSPLC
);
388 fprintf(of
, "%04x %s %c%c %04x ", IR
& 0xFFFF, mnem
, F
? (INDIR
? 'I' : 'L') : ' ', tagc
[TAG
], eaddr
& 0xFFFF);
389 return F
? -1 : SCPE_OK
; /* inform how many words we read */
392 int32
get_reg (char *cptr
, const char *strings
[], char mchar
)
397 /* Number or memory address
400 *cptr = pointer to input string
401 *dptr = pointer to output displacement
402 *pflag = pointer to accumulating flags
404 cptr = pointer to next character in input string
405 NULL if parsing error
407 Flags: 0 (no result), A_NUM (number), A_REL (relative)
410 char *get_addr (char *cptr
, int32
*dptr
, int32
*pflag
)
418 *cptr = pointer to input string
420 n1 = 0 if no extra word used
421 -1 if extra word used in prior decode
422 *sptr = pointer to output specifier
423 *dptr = pointer to output displacement
424 cflag = true if parsing for the CPU
425 iflag = true if integer specifier
427 status = = -1 extra word decoded
432 t_stat
get_spec (char *cptr
, t_addr addr
, int32 n1
, int32
*sptr
, t_value
*dptr
,
433 int32 cflag
, int32 iflag
)
441 *cptr = pointer to input string
443 *uptr = pointer to unit
444 *val = pointer to output values
447 status = > 0 error code
448 <= 0 -number of extra words
451 t_stat
parse_sym (char *cptr
, t_addr addr
, UNIT
*uptr
, t_value
*val
, int32 sw
)
458 int strnicmp (const char *a
, const char *b
, int n
)
463 if (--n
< 0) /* still equal after n characters? quit now */
466 if ((ca
= *a
) == 0) /* get character, stop on null terminator */
469 if (ca
>= 'a' && ca
<= 'z') /* fold lowercase to uppercase */
473 if (cb
>= 'a' && cb
<= 'z')
476 if ((ca
-= cb
) != 0) /* if different, return comparison */
483 int strcmpi (const char *a
, const char *b
)
488 if ((ca
= *a
) == 0) /* get character, stop on null terminator */
491 if (ca
>= 'a' && ca
<= 'z') /* fold lowercase to uppercase */
495 if (cb
>= 'a' && cb
<= 'z')
498 if ((ca
-= cb
) != 0) /* if different, return comparison */