First Commit of my working state
[simh.git] / Ibm1130 / ibm1130_sys.c
CommitLineData
196ba1fc
PH
1/* ibm1130_sys.c: IBM 1130 simulator interface\r
2\r
3 Based on PDP-11 simulator written by Robert M Supnik\r
4\r
5 Revision History\r
6 0.27 2005Mar08 - Added sca device\r
7 0.26 2002Apr24 - Added !BREAK in card deck file to stop simulator\r
8 0.25 2002Apr18 - Fixed some card reader problems. It starts the reader\r
9 properly if you attach a deck while it's waiting to a read.\r
10 0.24 2002Mar27 - Fixed BOSC bug; BOSC works in short instructions too\r
11 0.23 2002Feb26 - Added @decklist feature for ATTACH CR.\r
12 0.22 2002Feb26 - Replaced "strupr" with "upcase" for compatibility.\r
13 0.21 2002Feb25 - Some compiler compatibiity changes, couple of compiler-detected\r
14 bugs\r
15 0.01 2001Jul31 - Derived from pdp11_sys.c, which carries this disclaimer:\r
16\r
17 * (C) Copyright 2002, Brian Knittel.\r
18 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r
19 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r
20 * usual yada-yada. Please keep this notice and the copyright in any distributions\r
21 * or modifications.\r
22 *\r
23 * This is not a supported product, but I welcome bug reports and fixes.\r
24 * Mail to simh@ibm1130.org\r
25 */\r
26\r
27#include "ibm1130_defs.h"\r
28#include <ctype.h>\r
29#include <stdarg.h>\r
30\r
31extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev, t2741_dev;\r
32extern DEVICE tti_dev, tto_dev, prt_dev, log_dev, sca_dev;\r
33extern DEVICE gdu_dev, console_dev, plot_dev;\r
34\r
35extern UNIT cpu_unit;\r
36extern REG cpu_reg[];\r
37extern int32 saved_PC;\r
38\r
39/* SCP data structures and interface routines\r
40\r
41 sim_name simulator name string\r
42 sim_PC pointer to saved PC register descriptor\r
43 sim_emax number of words for examine\r
44 sim_devices array of pointers to simulated devices\r
45 sim_stop_messages array of pointers to stop messages\r
46 sim_load binary loader\r
47*/\r
48\r
49char sim_name[] = "IBM 1130";\r
50\r
51REG *sim_PC = &cpu_reg[0];\r
52\r
53int32 sim_emax = 4;\r
54\r
55DEVICE *sim_devices[] = {\r
56 &cpu_dev, /* the cpu */\r
57 &dsk_dev, /* disk drive(s) */\r
58 &cr_dev, /* card reader/punch */\r
59 &cp_dev,\r
60 &tti_dev, /* console keyboard, selectric printer */\r
61 &tto_dev,\r
62 &prt_dev, /* 1132 printer */\r
63 &ptr_dev, /* 1134 paper tape reader */\r
64 &ptp_dev, /* 1055 paper tape punch */\r
65 &sca_dev, /* Synchronous communications adapter option */\r
66 &console_dev, /* console display (windows GUI) */\r
67 &gdu_dev, /* 2250 display */\r
68 &t2741_dev, /* nonstandard serial interface used by APL\1130 */\r
69 &plot_dev, /* plotter device, in ibm1130_plot.c */\r
70 NULL\r
71};\r
72\r
73const char *sim_stop_messages[] = {\r
74 "Unknown error",\r
75 "Wait",\r
76 "Invalid command", \r
77 "Simulator breakpoint",\r
78 "Use of incomplete simulator function",\r
79 "Power off",\r
80 "!BREAK in card deck file",\r
81 "Phase load break",\r
82 "Program has run amok",\r
83 "Run time limit exceeded",\r
84 "Immediate Stop key requested",\r
85 "Simulator break key pressed",\r
86 "Simulator step count expired",\r
87 "Simulator IO error",\r
88};\r
89\r
90/* Loader. IPL is normally performed by card reader (boot command). This function\r
91 * loads hex data from a file for testing purposes. The format is:\r
92 *\r
93 * blank lines or lines starting with ; / or # are ignored as comments\r
94 *\r
95 * @XXXX set load addresss to hex value XXXX\r
96 * XXXX store hex word value XXXX at current load address and increment address\r
97 * ...\r
98 * =XXXX set IAR to hex value XXXX\r
99 * ZXXXX zero XXXX words and increment load address\r
100 * SXXXX set console entry switches to XXXX. This lets a program specify the\r
101 * default value for the toggle switches.\r
102 *\r
103 * Multiple @ and data sections may be entered. If more than one = or S value is specified\r
104 * the last one wins.\r
105 *\r
106 * Note: the load address @XXXX and data values XXXX can be followed by the letter\r
107 * R to indicate that the values are relocatable addresses. This is ignored in this loader,\r
108 * but the asm1130 cross assembler may put them there.\r
109 */\r
110\r
111t_stat my_load (FILE *fileref, char *cptr, char *fnam)\r
112{\r
113 char line[150], *c;\r
114 int iaddr = -1, runaddr = -1, val, nwords;\r
115\r
116 while (fgets(line, sizeof(line), fileref) != NULL) {\r
117 for (c = line; *c && *c <= ' '; c++) /* find first nonblank */\r
118 ;\r
119\r
120 if (*c == '\0' || *c == '#' || *c == '/' || *c == ';')\r
121 continue; /* empty line or comment */\r
122\r
123 if (*c == '@') { /* set load address */\r
124 if (sscanf(c+1, "%x", &iaddr) != 1)\r
125 return SCPE_FMT;\r
126 }\r
127 else if (*c == '=') {\r
128 if (sscanf(c+1, "%x", &runaddr) != 1)\r
129 return SCPE_FMT;\r
130 }\r
131 else if (*c == 's' || *c == 'S') {\r
132 if (sscanf(c+1, "%x", &val) != 1)\r
133 return SCPE_FMT;\r
134\r
135 CES = val & 0xFFFF; /*preload console entry switches */\r
136 }\r
137 else if (*c == 'z' || *c == 'Z') {\r
138 if (sscanf(c+1, "%x", &nwords) != 1)\r
139 return SCPE_FMT;\r
140\r
141 if (iaddr == -1)\r
142 return SCPE_FMT;\r
143\r
144 while (--nwords >= 0) {\r
145 WriteW(iaddr, 0);\r
146 iaddr++;\r
147 }\r
148 }\r
149 else if (strchr("0123456789abcdefABCDEF", *c) != NULL) {\r
150 if (sscanf(c, "%x", &val) != 1)\r
151 return SCPE_FMT;\r
152\r
153 if (iaddr == -1)\r
154 return SCPE_FMT;\r
155\r
156 WriteW(iaddr, val); /*store data */\r
157 iaddr++;\r
158 }\r
159 else\r
160 return SCPE_FMT; /*unexpected data */\r
161 }\r
162\r
163 if (runaddr != -1)\r
164 IAR = runaddr;\r
165\r
166 return SCPE_OK;\r
167}\r
168\r
169t_stat my_save (FILE *fileref, char *cptr, char *fnam)\r
170{\r
171 int iaddr, nzeroes = 0, nwords = (int) (MEMSIZE/2), val;\r
172\r
173 fprintf(fileref, "=%04x\r\n", IAR);\r
174 fprintf(fileref, "@0000\r\n");\r
175 for (iaddr = 0; iaddr < nwords; iaddr++) {\r
176 val = ReadW(iaddr);\r
177 if (val == 0) /*queue up zeroes */\r
178 nzeroes++;\r
179 else {\r
180 if (nzeroes >= 4) { /*spit out a Z directive */\r
181 fprintf(fileref, "Z%04x\r\n", nzeroes);\r
182 nzeroes = 0;\r
183 }\r
184 else { /*write queued zeroes literally */\r
185 while (nzeroes > 0) {\r
186 fprintf(fileref, " 0000\r\n");\r
187 nzeroes--;\r
188 }\r
189 }\r
190 fprintf(fileref, " %04x\r\n", val);\r
191 }\r
192 }\r
193 if (nzeroes >= 4) { /*emit any queued zeroes */\r
194 fprintf(fileref, "Z%04x\r\n", nzeroes);\r
195 nzeroes = 0;\r
196 }\r
197 else {\r
198 while (nzeroes > 0) {\r
199 fprintf(fileref, " 0000\r\n");\r
200 nzeroes--;\r
201 }\r
202 }\r
203\r
204 return SCPE_OK;\r
205}\r
206\r
207t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r
208{\r
209 if (flag)\r
210 return my_save(fileref, cptr, fnam);\r
211 else\r
212 return my_load(fileref, cptr, fnam);\r
213}\r
214\r
215/* Specifier decode\r
216\r
217 Inputs:\r
218 *of = output stream\r
219 addr = current PC\r
220 spec = specifier\r
221 nval = next word\r
222 flag = TRUE if decoding for CPU\r
223 iflag = TRUE if decoding integer instruction\r
224 Outputs:\r
225 count = -number of extra words retired\r
226*/\r
227\r
228/* Symbolic decode\r
229\r
230 Inputs:\r
231 *of = output stream\r
232 addr = current PC\r
233 *val = values to decode\r
234 *uptr = pointer to unit\r
235 sw = switches\r
236 Outputs:\r
237 return = if >= 0, error code\r
238 if < 0, number of extra words retired\r
239*/\r
240\r
241static char *opcode[] = {\r
242 "?00 ", "XIO ", "SLA ", "SRA ",\r
243 "LDS ", "STS ", "WAIT", "?07 ",\r
244 "BSI ", "BSC ", "?0A ", "?0B ",\r
245 "LDX ", "STX ", "MDX ", "?0F ",\r
246 "A ", "AD ", "S ", "SD ",\r
247 "M ", "D ", "?16 ", "?17 ",\r
248 "LD ", "LDD ", "STO ", "STD ",\r
249 "AND ", "OR ", "EOR ", "?1F ",\r
250};\r
251\r
252static char relative[] = { /*true if short mode displacements are IAR relative */\r
253 FALSE, TRUE, FALSE, FALSE,\r
254 FALSE, TRUE, FALSE, FALSE,\r
255 TRUE, FALSE, FALSE, FALSE,\r
256 TRUE, TRUE, TRUE, FALSE,\r
257 TRUE, TRUE, TRUE, TRUE,\r
258 TRUE, TRUE, FALSE, FALSE,\r
259 TRUE, TRUE, TRUE, TRUE,\r
260 TRUE, TRUE, TRUE, FALSE\r
261};\r
262\r
263static char *lsopcode[] = {"SLA ", "SLCA ", "SLT ", "SLC "};\r
264static char *rsopcode[] = {"SRA ", "?188 ", "SRT ", "RTE "};\r
265static char tagc[] = " 123";\r
266\r
267static int ascii_to_ebcdic_table[128] = \r
268{\r
269 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,\r
270 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,\r
271 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,\r
272 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,\r
273\r
274 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,\r
275 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d,\r
276 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,\r
277 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,\r
278};\r
279\r
280static int ebcdic_to_ascii (int ch)\r
281{\r
282 int j;\r
283\r
284 for (j = 32; j < 128; j++)\r
285 if (ascii_to_ebcdic_table[j] == ch)\r
286 return j;\r
287\r
288 return '?';\r
289}\r
290\r
291t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)\r
292{\r
293 int32 cflag, ch, OP, F, TAG, INDIR, DSPLC, IR, eaddr;\r
294 char *mnem, tst[12];\r
295\r
296 cflag = (uptr == NULL) || (uptr == &cpu_unit);\r
297\r
298/* if (sw & SWMASK ('A')) { // ASCII? not useful\r
299 fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);\r
300 return SCPE_OK;\r
301 }\r
302*/\r
303\r
304 if (sw & SWMASK ('C')) /* character? not useful -- make it EBCDIC */\r
305 sw |= SWMASK('E');\r
306\r
307 if (sw & SWMASK ('E')) { /* EBCDIC! */\r
308 ch = ebcdic_to_ascii((val[0] >> 8) & 0xFF); /* take high byte first */\r
309 fprintf (of, (ch < ' ')? "<%03o>": "%c", ch);\r
310 ch = ebcdic_to_ascii(val[0] & 0xFF);\r
311 fprintf (of, (ch < ' ')? "<%03o>": "%c", ch);\r
312 return SCPE_OK;\r
313 }\r
314\r
315 if (sw & SWMASK ('H')) { /* HOLLERITH! now THIS is useful! */\r
316 ch = hollerith_to_ascii((int16) val[0]);\r
317 fprintf (of, (ch < ' ')? "<%03o>": "%c", ch);\r
318 return SCPE_OK;\r
319 }\r
320\r
321 if (! (sw & SWMASK ('M')))\r
322 return SCPE_ARG;\r
323\r
324 IR = val[0];\r
325 OP = (IR >> 11) & 0x1F; /* opcode */\r
326 F = IR & 0x0400; /* format bit: 1 = long instr */\r
327 TAG = IR & 0x0300; /* tag bits: index reg select */\r
328 if (TAG)\r
329 TAG >>= 8;\r
330\r
331 if (F) { /* long instruction, ASSUME it's valid (have to decrement IAR if not) */\r
332 INDIR = IR & 0x0080; /* indirect bit */\r
333 DSPLC = IR & 0x007F; /* displacement or modifier */\r
334 if (DSPLC & 0x0040)\r
335 DSPLC |= ~ 0x7F; /* sign extend */\r
336\r
337 eaddr = val[1]; /* get reference address */\r
338 }\r
339 else { /* short instruction, use displacement */\r
340 INDIR = 0; /* never indirect */\r
341 DSPLC = IR & 0x00FF; /* get displacement */\r
342 if (DSPLC & 0x0080)\r
343 DSPLC |= ~ 0xFF;\r
344\r
345 eaddr = DSPLC;\r
346 if (relative[OP] && ! TAG)\r
347 eaddr += addr+1; /* turn displacement into address */\r
348 }\r
349\r
350 mnem = opcode[OP]; /* get mnemonic */\r
351 if (OP == 0x02) { /* left shifts are special */\r
352 mnem = lsopcode[(DSPLC >> 6) & 0x0003];\r
353 DSPLC &= 0x003F;\r
354 eaddr = DSPLC;\r
355 }\r
356 else if (OP == 0x03) { /* right shifts too */\r
357 mnem = rsopcode[(DSPLC >> 6) & 0x0003];\r
358 DSPLC &= 0x003F;\r
359 eaddr = DSPLC;\r
360 }\r
361 else if ((OP == 0x08 && F)|| OP == 0x09) { /* BSI L and BSC any */\r
362 if (OP == 0x09 && (IR & 0x40))\r
363 mnem = "BOSC";\r
364\r
365 tst[0] = '\0';\r
366 if (DSPLC & 0x20) strcat(tst, "Z");\r
367 if (DSPLC & 0x10) strcat(tst, "-");\r
368 if (DSPLC & 0x08) strcat(tst, "+");\r
369 if (DSPLC & 0x04) strcat(tst, "E");\r
370 if (DSPLC & 0x02) strcat(tst, "C");\r
371 if (DSPLC & 0x01) strcat(tst, "O");\r
372\r
373 if (F) {\r
374 fprintf(of, "%04x %s %c%c %s,%04x ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst, eaddr & 0xFFFF);\r
375 return -1;\r
376 }\r
377 fprintf(of, "%04x %s %c%c %s ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst);\r
378 return SCPE_OK;\r
379 }\r
380 else if (OP == 0x0e && TAG == 0) { /* MDX with no tag => MDM or jump */\r
381 if (F) {\r
382 fprintf(of, "%04x %s %c%c %04x,%x (%d) ", IR & 0xFFFF, "MDM ", (INDIR ? 'I' : 'L'), tagc[TAG], eaddr & 0xFFFF, DSPLC & 0xFFFF, DSPLC);\r
383 return -1;\r
384 }\r
385 mnem = "JMP ";\r
386 }\r
387\r
388 fprintf(of, "%04x %s %c%c %04x ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], eaddr & 0xFFFF);\r
389 return F ? -1 : SCPE_OK; /* inform how many words we read */\r
390}\r
391\r
392int32 get_reg (char *cptr, const char *strings[], char mchar)\r
393{\r
394return -1;\r
395}\r
396\r
397/* Number or memory address\r
398\r
399 Inputs:\r
400 *cptr = pointer to input string\r
401 *dptr = pointer to output displacement\r
402 *pflag = pointer to accumulating flags\r
403 Outputs:\r
404 cptr = pointer to next character in input string\r
405 NULL if parsing error\r
406\r
407 Flags: 0 (no result), A_NUM (number), A_REL (relative)\r
408*/\r
409\r
410char *get_addr (char *cptr, int32 *dptr, int32 *pflag)\r
411{\r
412 return 0;\r
413}\r
414\f\r
415/* Specifier decode\r
416\r
417 Inputs:\r
418 *cptr = pointer to input string\r
419 addr = current PC\r
420 n1 = 0 if no extra word used\r
421 -1 if extra word used in prior decode\r
422 *sptr = pointer to output specifier\r
423 *dptr = pointer to output displacement\r
424 cflag = true if parsing for the CPU\r
425 iflag = true if integer specifier\r
426 Outputs:\r
427 status = = -1 extra word decoded\r
428 = 0 ok\r
429 = +1 error\r
430*/\r
431\r
432t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr,\r
433 int32 cflag, int32 iflag)\r
434{\r
435 return -1;\r
436}\r
437\r
438/* Symbolic input\r
439\r
440 Inputs:\r
441 *cptr = pointer to input string\r
442 addr = current PC\r
443 *uptr = pointer to unit\r
444 *val = pointer to output values\r
445 sw = switches\r
446 Outputs:\r
447 status = > 0 error code\r
448 <= 0 -number of extra words\r
449*/\r
450\r
451t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r
452{\r
453 return SCPE_ARG;\r
454}\r
455\r
456#ifndef _WIN32\r
457\r
458int strnicmp (const char *a, const char *b, int n)\r
459{\r
460 int ca, cb;\r
461\r
462 for (;;) {\r
463 if (--n < 0) /* still equal after n characters? quit now */\r
464 return 0;\r
465\r
466 if ((ca = *a) == 0) /* get character, stop on null terminator */\r
467 return *b ? -1 : 0;\r
468\r
469 if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */\r
470 ca -= 32;\r
471\r
472 cb = *b;\r
473 if (cb >= 'a' && cb <= 'z')\r
474 cb -= 32;\r
475\r
476 if ((ca -= cb) != 0) /* if different, return comparison */\r
477 return ca;\r
478\r
479 a++, b++;\r
480 }\r
481}\r
482\r
483int strcmpi (const char *a, const char *b)\r
484{\r
485 int ca, cb;\r
486\r
487 for (;;) {\r
488 if ((ca = *a) == 0) /* get character, stop on null terminator */\r
489 return *b ? -1 : 0;\r
490\r
491 if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */\r
492 ca -= 32;\r
493\r
494 cb = *b;\r
495 if (cb >= 'a' && cb <= 'z')\r
496 cb -= 32;\r
497\r
498 if ((ca -= cb) != 0) /* if different, return comparison */\r
499 return ca;\r
500\r
501 a++, b++;\r
502 }\r
503}\r
504\r
505#endif\r