First Commit of my working state
[simh.git] / LGP / lgp_sys.c
CommitLineData
196ba1fc
PH
1/* lgp_sys.c: LGP-30 simulator interface\r
2\r
3 Copyright (c) 2004-2005, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 04-Jan-05 RMS Modified VM pointer setup\r
27*/\r
28\r
29#include "lgp_defs.h"\r
30#include <ctype.h>\r
31\r
32t_stat parse_sym_m (char *cptr, t_value *val, int32 sw);\r
33void lgp_init (void);\r
34\r
35extern DEVICE cpu_dev;\r
36extern UNIT cpu_unit;\r
37extern DEVICE tti_dev, tto_dev;\r
38extern DEVICE ptr_dev, ptp_dev;\r
39extern REG cpu_reg[];\r
40extern uint32 M[];\r
41extern uint32 PC;\r
42extern uint32 ts_flag;\r
43extern int32 sim_switches;\r
44extern int32 flex_to_ascii[128], ascii_to_flex[128];\r
45\r
46extern void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr);\r
47extern t_addr (*sim_vm_parse_addr) (DEVICE *dptr, char *cptr, char **tptr);\r
48\r
49/* SCP data structures and interface routines\r
50\r
51 sim_name simulator name string\r
52 sim_PC pointer to saved PC register descriptor\r
53 sim_emax maximum number of words for examine/deposit\r
54 sim_devices array of pointers to simulated devices\r
55 sim_stop_messages array of pointers to stop messages\r
56 sim_load binary loader\r
57*/\r
58\r
59char sim_name[] = "LGP30";\r
60\r
61REG *sim_PC = &cpu_reg[0];\r
62\r
63int32 sim_emax = 1;\r
64\r
65DEVICE *sim_devices[] = {\r
66 &cpu_dev,\r
67 &tti_dev,\r
68 &tto_dev,\r
69 &ptr_dev,\r
70 &ptp_dev,\r
71 NULL\r
72 };\r
73\r
74const char *sim_stop_messages[] = {\r
75 "Unknown error",\r
76 "STOP",\r
77 "Breakpoint",\r
78 "Arithmetic overflow"\r
79 };\r
80\r
81/* Binary loader - implements a restricted form of subroutine 10.4\r
82\r
83 Switches:\r
84 -t, input file is transposed Flex\r
85 -n, no checksums on v commands (10.0 compatible)\r
86 default is ASCII encoded Flex\r
87 Commands (in bits 0-3):\r
88 (blank) instruction\r
89 + command (not supported)\r
90 ; start fill\r
91 / set modifier\r
92 . stop and transfer\r
93 , hex words\r
94 v hex fill (checksummed unless -n)\r
95 8 negative instruction\r
96*/\r
97\r
98/* Utility routine - read characters until ' (conditional stop) */\r
99\r
100t_stat load_getw (FILE *fi, uint32 *wd)\r
101{\r
102int32 flex, c;\r
103\r
104*wd = 0;\r
105while ((c = fgetc (fi)) != EOF) {\r
106 if (sim_switches & SWMASK ('T'))\r
107 flex = ((c << 1) | (c >> 5)) & 0x3F;\r
108 else flex = ascii_to_flex[c & 0x7F];\r
109 if ((flex == FLEX_CR) || (flex == FLEX_DEL) ||\r
110 (flex == FLEX_UC) || (flex == FLEX_LC) ||\r
111 (flex == FLEX_BS) || (flex < 0)) continue;\r
112 if (flex == FLEX_CSTOP) return SCPE_OK;\r
113 *wd = (*wd << 4) | ((flex >> 2) & 0xF);\r
114 }\r
115return SCPE_FMT;\r
116}\r
117\r
118/* Utility routine - convert ttss decimal address to binary */\r
119\r
120t_stat load_geta (uint32 wd, uint32 *ad)\r
121{\r
122uint32 n1, n2, n3, n4, tr, sc;\r
123\r
124n1 = (wd >> 12) & 0xF;\r
125n2 = (wd >> 8) & 0xF;\r
126n3 = (wd >> 4) & 0xF;\r
127n4 = wd & 0xF;\r
128if ((n2 > 9) || (n4 > 9)) return SCPE_ARG;\r
129tr = (n1 * 10) + n2;\r
130sc = (n3 * 10) + n4;\r
131if ((tr >= NTK_30) || (sc >= NSC_30)) return SCPE_ARG;\r
132*ad = (tr * NSC_30) + sc;\r
133return SCPE_OK;\r
134}\r
135\r
136/* Loader proper */\r
137\r
138t_stat sim_load (FILE *fi, char *cptr, char *fnam, int flag)\r
139{\r
140uint32 wd, origin, amod, csum, cnt, tr, sc, ad, cmd;\r
141\r
142origin = amod = 0;\r
143for (;;) { /* until stopped */\r
144 if (load_getw (fi, &wd)) break; /* get ctrl word */\r
145 cmd = (wd >> 28) & 0xF; /* get <0:3> */\r
146 switch (cmd) { /* decode <0:3> */\r
147\r
148 case 0x2: /* + command */\r
149 return SCPE_FMT;\r
150\r
151 case 0x3: /* ; start fill */\r
152 if (load_geta (wd, &origin)) return SCPE_FMT; /* origin = addr */\r
153 break;\r
154\r
155 case 0x4: /* / set modifier */\r
156 if (load_geta (wd, &amod)) return SCPE_FMT; /* modifier = addr */\r
157 break;\r
158\r
159 case 0x5: /* . transfer */\r
160 if (load_geta (wd, &PC)) return SCPE_FMT; /* PC = addr */\r
161 return SCPE_OK; /* done! */\r
162\r
163 case 0x6: /* hex words */\r
164 if (load_geta (wd, &cnt)) return SCPE_FMT; /* count = addr */\r
165 if ((cnt == 0) || (cnt > 63)) return SCPE_FMT;\r
166 while (cnt--) { /* fill hex words */\r
167 if (load_getw (fi, &wd)) return SCPE_FMT;\r
168 Write (origin, wd);\r
169 origin = (origin + 1) & AMASK;\r
170 }\r
171 break;\r
172\r
173 case 0x7: /* hex fill */\r
174 cnt = (wd >> 16) & 0xFFF; /* hex count */\r
175 tr = (wd >> 8) & 0xFF; /* hex track */\r
176 sc = wd & 0xFF; /* hex sector */\r
177 if ((cnt == 0) || (cnt > 0x7FF) || /* validate */\r
178 (tr >= NTK_30) || (sc >= NSC_30)) return SCPE_ARG;\r
179 ad = (tr * NSC_30) + sc; /* decimal addr */\r
180 for (csum = 0; cnt; cnt--) { /* fill words */\r
181 if (load_getw (fi, &wd)) return SCPE_FMT;\r
182 Write (ad, wd);\r
183 csum = (csum + wd) & MMASK;\r
184 ad = (ad + 1) & AMASK;\r
185 }\r
186 if (!(sim_switches & SWMASK ('N'))) { /* unless -n, csum */\r
187 if (load_getw (fi, &wd)) return SCPE_FMT;\r
188/* if ((csum ^wd) & MMASK) return SCPE_CSUM; */\r
189 }\r
190 break;\r
191\r
192 case 0x0: case 0x8: /* instructions */\r
193 if (load_geta (wd, &ad)) return SCPE_FMT; /* get address */\r
194 if ((wd & 0x00F00000) != 0x00900000) /* if not x, */\r
195 ad = (ad + amod) & AMASK; /* modify */\r
196 wd = (wd & (SIGN|I_OP)) + (ad << I_V_EA); /* instruction */\r
197\r
198 default: /* data word */\r
199 Write (origin, wd);\r
200 origin = (origin + 1) & AMASK;\r
201 break;\r
202 } /* end case */\r
203 } /* end for */\r
204return SCPE_OK;\r
205}\r
206\r
207/* Symbol tables */\r
208\r
209static const char opcode[] = "ZBYRIDNMPEUTHCAS";\r
210\r
211static const char hex_decode[] = "0123456789FGJKQW";\r
212\r
213void lgp_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr)\r
214{\r
215if ((dptr == sim_devices[0]) &&\r
216 ((sim_switches & SWMASK ('T')) ||\r
217 ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N')))))\r
218 fprintf (st, "%02d%02d", addr >> 6, addr & SCMASK_30);\r
219else fprint_val (st, addr, dptr->aradix, dptr->awidth, PV_LEFT);\r
220return;\r
221}\r
222\r
223t_addr lgp_parse_addr (DEVICE *dptr, char *cptr, char **tptr)\r
224{\r
225t_addr ad, ea;\r
226\r
227if ((dptr == sim_devices[0]) &&\r
228 ((sim_switches & SWMASK ('T')) ||\r
229 ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N'))))) {\r
230 ad = (t_addr) strtotv (cptr, tptr, 10);\r
231 if (((ad / 100) >= NTK_30) || ((ad % 100) >= NSC_30)) {\r
232 *tptr = cptr;\r
233 return 0;\r
234 }\r
235 ea = ((ad / 100) * NSC_30) | (ad % 100);\r
236 }\r
237else ea = (t_addr) strtotv (cptr, tptr, dptr->aradix);\r
238return ea;\r
239}\r
240\r
241void lgp_vm_init (void)\r
242{\r
243sim_vm_fprint_addr = &lgp_fprint_addr;\r
244sim_vm_parse_addr = &lgp_parse_addr;\r
245return;\r
246}\r
247\r
248/* Symbolic decode\r
249\r
250 Inputs:\r
251 *of = output stream\r
252 addr = current PC\r
253 *val = pointer to data\r
254 *uptr = pointer to unit \r
255 sw = switches\r
256 Outputs:\r
257 return = status code\r
258*/\r
259\r
260t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r
261 UNIT *uptr, int32 sw)\r
262{\r
263int32 i, c;\r
264uint32 inst, op, ea;\r
265\r
266inst = val[0];\r
267if (sw & SWMASK ('A')) { /* alphabetic? */\r
268 if ((uptr == NULL) || !(uptr->flags & UNIT_ATT)) return SCPE_ARG;\r
269 if (uptr->flags & UNIT_FLEX) { /* Flex file? */\r
270 c = flex_to_ascii[inst]; /* get ASCII equiv */\r
271 if (c <= 0) return SCPE_ARG;\r
272 }\r
273 else c = inst & 0x7F; /* ASCII file */\r
274 fputc (c, of);\r
275 return SCPE_OK;\r
276 }\r
277\r
278if (uptr && (uptr != &cpu_unit)) return SCPE_ARG; /* must be CPU */\r
279if ((sw & SWMASK ('M')) && /* symbolic decode? */\r
280 ((inst & ~(SIGN|I_OP|I_EA)) == 0)) {\r
281 op = I_GETOP (inst);\r
282 ea = I_GETEA (inst);\r
283 if (inst & SIGN) fputc ('-', of);\r
284 fprintf (of, "%c ", opcode[op]);\r
285 lgp_fprint_addr (of, sim_devices[0], ea);\r
286 return SCPE_OK;\r
287 }\r
288\r
289if ((sw & SWMASK ('L')) || /* LGP hex? */\r
290 ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) {\r
291 for (i = 0; i < 8; i++) {\r
292 c = (inst >> (4 * (7 - i))) & 0xF;\r
293 fputc (hex_decode[c], of);\r
294 }\r
295 return SCPE_OK;\r
296 }\r
297return SCPE_ARG;\r
298}\r
299\r
300/* Symbolic input\r
301\r
302 Inputs:\r
303 *cptr = pointer to input string\r
304 addr = current PC\r
305 *uptr = pointer to unit\r
306 *val = pointer to output values\r
307 sw = switches\r
308 Outputs:\r
309 status = error status\r
310*/\r
311\r
312t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r
313{\r
314int32 i, c;\r
315char *tptr;\r
316\r
317while (isspace (*cptr)) cptr++; /* absorb spaces */\r
318if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) {\r
319 if ((uptr == NULL) || !(uptr->flags & UNIT_ATT)) return SCPE_ARG;\r
320 if (uptr->flags & UNIT_FLEX) { /* Flex file? */ \r
321 c = ascii_to_flex[*cptr & 0x7F]; /* get Flex equiv */\r
322 if (c < 0) return SCPE_ARG;\r
323 val[0] = ((c >> 1) | (c << 5)) & 0x3F; /* transpose */\r
324 }\r
325 else val[0] = *cptr & 0x7F; /* ASCII file */\r
326 return SCPE_OK;\r
327 } \r
328\r
329if (uptr && (uptr != &cpu_unit)) return SCPE_ARG; /* must be CPU */\r
330if (!parse_sym_m (cptr, val, sw)) return SCPE_OK; /* symbolic parse? */\r
331if ((sw & SWMASK ('L')) || /* LGP hex? */\r
332 ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) {\r
333 val[0] = 0;\r
334 while (isspace (*cptr)) cptr++; /* absorb spaces */\r
335 for (i = 0; i < 8; i++) {\r
336 c = *cptr++; /* get char */\r
337 if (c == 0) return SCPE_OK;\r
338 if (islower (c)) c = toupper (c);\r
339 if (tptr = strchr (hex_decode, c))\r
340 val[0] = (val[0] << 4) | (tptr - hex_decode);\r
341 else return SCPE_ARG;\r
342 }\r
343 if (*cptr == 0) return SCPE_OK;\r
344 }\r
345return SCPE_ARG;\r
346}\r
347\r
348/* Instruction parse */\r
349\r
350t_stat parse_sym_m (char *cptr, t_value *val, int32 sw)\r
351{\r
352uint32 ea, sgn;\r
353char *tptr, gbuf[CBUFSIZE];\r
354\r
355if (*cptr == '-') {\r
356 cptr++;\r
357 sgn = SIGN;\r
358 }\r
359else sgn = 0;\r
360cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r
361if (gbuf[1] != 0) return SCPE_ARG;\r
362if (tptr = strchr (opcode, gbuf[0]))\r
363 val[0] = ((tptr - opcode) << I_V_OP) | sgn; /* merge opcode */\r
364else return SCPE_ARG;\r
365cptr = get_glyph (cptr, gbuf, 0); /* get address */\r
366ea = lgp_parse_addr (sim_devices[0], gbuf, &tptr);\r
367if ((tptr == gbuf) || (*tptr != 0) || (ea > AMASK))\r
368 return SCPE_ARG;\r
369val[0] = val[0] | (ea << I_V_EA); /* merge address */\r
370if (*cptr != 0) return SCPE_2MARG;\r
371return SCPE_OK;\r
372}\r