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