First Commit of my working state
[simh.git] / Ibm1130 / ibm1130_sys.c
1 /* ibm1130_sys.c: IBM 1130 simulator interface
2
3 Based on PDP-11 simulator written by Robert M Supnik
4
5 Revision History
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
14 bugs
15 0.01 2001Jul31 - Derived from pdp11_sys.c, which carries this disclaimer:
16
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
21 * or modifications.
22 *
23 * This is not a supported product, but I welcome bug reports and fixes.
24 * Mail to simh@ibm1130.org
25 */
26
27 #include "ibm1130_defs.h"
28 #include <ctype.h>
29 #include <stdarg.h>
30
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;
34
35 extern UNIT cpu_unit;
36 extern REG cpu_reg[];
37 extern int32 saved_PC;
38
39 /* SCP data structures and interface routines
40
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
47 */
48
49 char sim_name[] = "IBM 1130";
50
51 REG *sim_PC = &cpu_reg[0];
52
53 int32 sim_emax = 4;
54
55 DEVICE *sim_devices[] = {
56 &cpu_dev, /* the cpu */
57 &dsk_dev, /* disk drive(s) */
58 &cr_dev, /* card reader/punch */
59 &cp_dev,
60 &tti_dev, /* console keyboard, selectric printer */
61 &tto_dev,
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 */
70 NULL
71 };
72
73 const char *sim_stop_messages[] = {
74 "Unknown error",
75 "Wait",
76 "Invalid command",
77 "Simulator breakpoint",
78 "Use of incomplete simulator function",
79 "Power off",
80 "!BREAK in card deck file",
81 "Phase load break",
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",
87 "Simulator IO error",
88 };
89
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:
92 *
93 * blank lines or lines starting with ; / or # are ignored as comments
94 *
95 * @XXXX set load addresss to hex value XXXX
96 * XXXX store hex word value XXXX at current load address and increment address
97 * ...
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.
102 *
103 * Multiple @ and data sections may be entered. If more than one = or S value is specified
104 * the last one wins.
105 *
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.
109 */
110
111 t_stat my_load (FILE *fileref, char *cptr, char *fnam)
112 {
113 char line[150], *c;
114 int iaddr = -1, runaddr = -1, val, nwords;
115
116 while (fgets(line, sizeof(line), fileref) != NULL) {
117 for (c = line; *c && *c <= ' '; c++) /* find first nonblank */
118 ;
119
120 if (*c == '\0' || *c == '#' || *c == '/' || *c == ';')
121 continue; /* empty line or comment */
122
123 if (*c == '@') { /* set load address */
124 if (sscanf(c+1, "%x", &iaddr) != 1)
125 return SCPE_FMT;
126 }
127 else if (*c == '=') {
128 if (sscanf(c+1, "%x", &runaddr) != 1)
129 return SCPE_FMT;
130 }
131 else if (*c == 's' || *c == 'S') {
132 if (sscanf(c+1, "%x", &val) != 1)
133 return SCPE_FMT;
134
135 CES = val & 0xFFFF; /*preload console entry switches */
136 }
137 else if (*c == 'z' || *c == 'Z') {
138 if (sscanf(c+1, "%x", &nwords) != 1)
139 return SCPE_FMT;
140
141 if (iaddr == -1)
142 return SCPE_FMT;
143
144 while (--nwords >= 0) {
145 WriteW(iaddr, 0);
146 iaddr++;
147 }
148 }
149 else if (strchr("0123456789abcdefABCDEF", *c) != NULL) {
150 if (sscanf(c, "%x", &val) != 1)
151 return SCPE_FMT;
152
153 if (iaddr == -1)
154 return SCPE_FMT;
155
156 WriteW(iaddr, val); /*store data */
157 iaddr++;
158 }
159 else
160 return SCPE_FMT; /*unexpected data */
161 }
162
163 if (runaddr != -1)
164 IAR = runaddr;
165
166 return SCPE_OK;
167 }
168
169 t_stat my_save (FILE *fileref, char *cptr, char *fnam)
170 {
171 int iaddr, nzeroes = 0, nwords = (int) (MEMSIZE/2), val;
172
173 fprintf(fileref, "=%04x\r\n", IAR);
174 fprintf(fileref, "@0000\r\n");
175 for (iaddr = 0; iaddr < nwords; iaddr++) {
176 val = ReadW(iaddr);
177 if (val == 0) /*queue up zeroes */
178 nzeroes++;
179 else {
180 if (nzeroes >= 4) { /*spit out a Z directive */
181 fprintf(fileref, "Z%04x\r\n", nzeroes);
182 nzeroes = 0;
183 }
184 else { /*write queued zeroes literally */
185 while (nzeroes > 0) {
186 fprintf(fileref, " 0000\r\n");
187 nzeroes--;
188 }
189 }
190 fprintf(fileref, " %04x\r\n", val);
191 }
192 }
193 if (nzeroes >= 4) { /*emit any queued zeroes */
194 fprintf(fileref, "Z%04x\r\n", nzeroes);
195 nzeroes = 0;
196 }
197 else {
198 while (nzeroes > 0) {
199 fprintf(fileref, " 0000\r\n");
200 nzeroes--;
201 }
202 }
203
204 return SCPE_OK;
205 }
206
207 t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
208 {
209 if (flag)
210 return my_save(fileref, cptr, fnam);
211 else
212 return my_load(fileref, cptr, fnam);
213 }
214
215 /* Specifier decode
216
217 Inputs:
218 *of = output stream
219 addr = current PC
220 spec = specifier
221 nval = next word
222 flag = TRUE if decoding for CPU
223 iflag = TRUE if decoding integer instruction
224 Outputs:
225 count = -number of extra words retired
226 */
227
228 /* Symbolic decode
229
230 Inputs:
231 *of = output stream
232 addr = current PC
233 *val = values to decode
234 *uptr = pointer to unit
235 sw = switches
236 Outputs:
237 return = if >= 0, error code
238 if < 0, number of extra words retired
239 */
240
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 ",
250 };
251
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
261 };
262
263 static char *lsopcode[] = {"SLA ", "SLCA ", "SLT ", "SLC "};
264 static char *rsopcode[] = {"SRA ", "?188 ", "SRT ", "RTE "};
265 static char tagc[] = " 123";
266
267 static int ascii_to_ebcdic_table[128] =
268 {
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,
273
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,
278 };
279
280 static int ebcdic_to_ascii (int ch)
281 {
282 int j;
283
284 for (j = 32; j < 128; j++)
285 if (ascii_to_ebcdic_table[j] == ch)
286 return j;
287
288 return '?';
289 }
290
291 t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
292 {
293 int32 cflag, ch, OP, F, TAG, INDIR, DSPLC, IR, eaddr;
294 char *mnem, tst[12];
295
296 cflag = (uptr == NULL) || (uptr == &cpu_unit);
297
298 /* if (sw & SWMASK ('A')) { // ASCII? not useful
299 fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
300 return SCPE_OK;
301 }
302 */
303
304 if (sw & SWMASK ('C')) /* character? not useful -- make it EBCDIC */
305 sw |= SWMASK('E');
306
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);
312 return SCPE_OK;
313 }
314
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);
318 return SCPE_OK;
319 }
320
321 if (! (sw & SWMASK ('M')))
322 return SCPE_ARG;
323
324 IR = val[0];
325 OP = (IR >> 11) & 0x1F; /* opcode */
326 F = IR & 0x0400; /* format bit: 1 = long instr */
327 TAG = IR & 0x0300; /* tag bits: index reg select */
328 if (TAG)
329 TAG >>= 8;
330
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 */
334 if (DSPLC & 0x0040)
335 DSPLC |= ~ 0x7F; /* sign extend */
336
337 eaddr = val[1]; /* get reference address */
338 }
339 else { /* short instruction, use displacement */
340 INDIR = 0; /* never indirect */
341 DSPLC = IR & 0x00FF; /* get displacement */
342 if (DSPLC & 0x0080)
343 DSPLC |= ~ 0xFF;
344
345 eaddr = DSPLC;
346 if (relative[OP] && ! TAG)
347 eaddr += addr+1; /* turn displacement into address */
348 }
349
350 mnem = opcode[OP]; /* get mnemonic */
351 if (OP == 0x02) { /* left shifts are special */
352 mnem = lsopcode[(DSPLC >> 6) & 0x0003];
353 DSPLC &= 0x003F;
354 eaddr = DSPLC;
355 }
356 else if (OP == 0x03) { /* right shifts too */
357 mnem = rsopcode[(DSPLC >> 6) & 0x0003];
358 DSPLC &= 0x003F;
359 eaddr = DSPLC;
360 }
361 else if ((OP == 0x08 && F)|| OP == 0x09) { /* BSI L and BSC any */
362 if (OP == 0x09 && (IR & 0x40))
363 mnem = "BOSC";
364
365 tst[0] = '\0';
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");
372
373 if (F) {
374 fprintf(of, "%04x %s %c%c %s,%04x ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst, eaddr & 0xFFFF);
375 return -1;
376 }
377 fprintf(of, "%04x %s %c%c %s ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst);
378 return SCPE_OK;
379 }
380 else if (OP == 0x0e && TAG == 0) { /* MDX with no tag => MDM or jump */
381 if (F) {
382 fprintf(of, "%04x %s %c%c %04x,%x (%d) ", IR & 0xFFFF, "MDM ", (INDIR ? 'I' : 'L'), tagc[TAG], eaddr & 0xFFFF, DSPLC & 0xFFFF, DSPLC);
383 return -1;
384 }
385 mnem = "JMP ";
386 }
387
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 */
390 }
391
392 int32 get_reg (char *cptr, const char *strings[], char mchar)
393 {
394 return -1;
395 }
396
397 /* Number or memory address
398
399 Inputs:
400 *cptr = pointer to input string
401 *dptr = pointer to output displacement
402 *pflag = pointer to accumulating flags
403 Outputs:
404 cptr = pointer to next character in input string
405 NULL if parsing error
406
407 Flags: 0 (no result), A_NUM (number), A_REL (relative)
408 */
409
410 char *get_addr (char *cptr, int32 *dptr, int32 *pflag)
411 {
412 return 0;
413 }
414 \f
415 /* Specifier decode
416
417 Inputs:
418 *cptr = pointer to input string
419 addr = current PC
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
426 Outputs:
427 status = = -1 extra word decoded
428 = 0 ok
429 = +1 error
430 */
431
432 t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr,
433 int32 cflag, int32 iflag)
434 {
435 return -1;
436 }
437
438 /* Symbolic input
439
440 Inputs:
441 *cptr = pointer to input string
442 addr = current PC
443 *uptr = pointer to unit
444 *val = pointer to output values
445 sw = switches
446 Outputs:
447 status = > 0 error code
448 <= 0 -number of extra words
449 */
450
451 t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
452 {
453 return SCPE_ARG;
454 }
455
456 #ifndef _WIN32
457
458 int strnicmp (const char *a, const char *b, int n)
459 {
460 int ca, cb;
461
462 for (;;) {
463 if (--n < 0) /* still equal after n characters? quit now */
464 return 0;
465
466 if ((ca = *a) == 0) /* get character, stop on null terminator */
467 return *b ? -1 : 0;
468
469 if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */
470 ca -= 32;
471
472 cb = *b;
473 if (cb >= 'a' && cb <= 'z')
474 cb -= 32;
475
476 if ((ca -= cb) != 0) /* if different, return comparison */
477 return ca;
478
479 a++, b++;
480 }
481 }
482
483 int strcmpi (const char *a, const char *b)
484 {
485 int ca, cb;
486
487 for (;;) {
488 if ((ca = *a) == 0) /* get character, stop on null terminator */
489 return *b ? -1 : 0;
490
491 if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */
492 ca -= 32;
493
494 cb = *b;
495 if (cb >= 'a' && cb <= 'z')
496 cb -= 32;
497
498 if ((ca -= cb) != 0) /* if different, return comparison */
499 return ca;
500
501 a++, b++;
502 }
503 }
504
505 #endif