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 
my_load(FILE * fileref,char * cptr,char * fnam)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 
my_save(FILE * fileref,char * cptr,char * fnam)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 
sim_load(FILE * fileref,char * cptr,char * fnam,int flag)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 
ebcdic_to_ascii(int ch)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 
fprint_sym(FILE * of,t_addr addr,t_value * val,UNIT * uptr,int32 sw)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 
get_reg(char * cptr,const char * strings[],char mchar)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 
get_addr(char * cptr,int32 * dptr,int32 * pflag)410 char *get_addr (char *cptr, int32 *dptr, int32 *pflag)
411 {
412 	return 0;
413 }
414 
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 
get_spec(char * cptr,t_addr addr,int32 n1,int32 * sptr,t_value * dptr,int32 cflag,int32 iflag)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 
parse_sym(char * cptr,t_addr addr,UNIT * uptr,t_value * val,int32 sw)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 
strnicmp(const char * a,const char * b,size_t n)458 int strnicmp (const char *a, const char *b, size_t n)
459 {
460 	int ca, cb;
461 
462 	if (n == 0) return 0;					/* zero length compare is equal */
463 
464 	for (;;) {
465 		if ((ca = *a) == 0)				/* get character, stop on null terminator */
466 			return *b ? -1 : 0;
467 
468 		if (ca >= 'a' && ca <= 'z')		/* fold lowercase to uppercase */
469 			ca -= 32;
470 
471 		cb = *b;
472 		if (cb >= 'a' && cb <= 'z')
473 			cb -= 32;
474 
475 		if ((ca -= cb) != 0)			/* if different, return comparison */
476 			return ca;
477 
478 		a++, b++;
479 
480 		if (--n == 0)					/* still equal after n characters? quit now */
481 			return 0;
482 	}
483 }
484 
strcmpi(const char * a,const char * b)485 int strcmpi (const char *a, const char *b)
486 {
487 	int ca, cb;
488 
489 	for (;;) {
490 		if ((ca = *a) == 0)				/* get character, stop on null terminator */
491 			return *b ? -1 : 0;
492 
493 		if (ca >= 'a' && ca <= 'z')		/* fold lowercase to uppercase */
494 			ca -= 32;
495 
496 		cb = *b;
497 		if (cb >= 'a' && cb <= 'z')
498 			cb -= 32;
499 
500 		if ((ca -= cb) != 0)			/* if different, return comparison */
501 			return ca;
502 
503 		a++, b++;
504 	}
505 }
506 
507 #endif
508