1 /* lgp_sys.c: LGP-30 simulator interface
2 
3    Copyright (c) 2004-2008, 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 
load_getw(FILE * fi,uint32 * wd)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))
112         continue;
113     if (flex == FLEX_CSTOP)
114         return SCPE_OK;
115     *wd = (*wd << 4) | ((flex >> 2) & 0xF);
116     }
117 return SCPE_FMT;
118 }
119 
120 /* Utility routine - convert ttss decimal address to binary */
121 
load_geta(uint32 wd,uint32 * ad)122 t_stat load_geta (uint32 wd, uint32 *ad)
123 {
124 uint32 n1, n2, n3, n4, tr, sc;
125 
126 n1 = (wd >> 12) & 0xF;
127 n2 = (wd >> 8) & 0xF;
128 n3 = (wd >> 4) & 0xF;
129 n4 = wd & 0xF;
130 if ((n2 > 9) || (n4 > 9))
131     return SCPE_ARG;
132 tr = (n1 * 10) + n2;
133 sc = (n3 * 10) + n4;
134 if ((tr >= NTK_30) || (sc >= NSC_30))
135     return SCPE_ARG;
136 *ad = (tr * NSC_30) + sc;
137 return SCPE_OK;
138 }
139 
140 /* Loader proper */
141 
sim_load(FILE * fi,char * cptr,char * fnam,int flag)142 t_stat sim_load (FILE *fi, char *cptr, char *fnam, int flag)
143 {
144 uint32 wd, origin, amod, csum, cnt, tr, sc, ad, cmd;
145 
146 origin = amod = 0;
147 for (;;) {                                              /* until stopped */
148     if (load_getw (fi, &wd))                            /* get ctrl word */
149         break;
150     cmd = (wd >> 28) & 0xF;                             /* get <0:3> */
151     switch (cmd) {                                      /* decode <0:3> */
152 
153         case 0x2:                                       /* + command */
154             return SCPE_FMT;
155 
156         case 0x3:                                       /* ; start fill */
157             if (load_geta (wd, &origin))                /* origin = addr */
158                 return SCPE_FMT;
159             break;
160 
161         case 0x4:                                       /* / set modifier */
162             if (load_geta (wd, &amod))                  /* modifier = addr */
163                 return SCPE_FMT;
164             break;
165 
166         case 0x5:                                       /* . transfer */
167             if (load_geta (wd, &PC))                    /* PC = addr */
168                 return SCPE_FMT;
169             return SCPE_OK;                             /* done! */
170 
171         case 0x6:                                       /* hex words */
172             if (load_geta (wd, &cnt))                   /* count = addr */
173                 return SCPE_FMT;
174             if ((cnt == 0) || (cnt > 63))
175                 return SCPE_FMT;
176             while (cnt--) {                             /* fill hex words */
177                 if (load_getw (fi, &wd))
178                     return SCPE_FMT;
179                 Write (origin, wd);
180                 origin = (origin + 1) & AMASK;
181                 }
182             break;
183 
184         case 0x7:                                       /* hex fill */
185             cnt = (wd >> 16) & 0xFFF;                   /* hex count */
186             tr = (wd >> 8) & 0xFF;                      /* hex track */
187             sc = wd & 0xFF;                             /* hex sector */
188             if ((cnt == 0) || (cnt > 0x7FF) ||          /* validate */
189                 (tr >= NTK_30) || (sc >= NSC_30))
190                 return SCPE_ARG;
191             ad = (tr * NSC_30) + sc;                    /* decimal addr */
192             for (csum = 0; cnt; cnt--) {                /* fill words */
193                 if (load_getw (fi, &wd))
194                     return SCPE_FMT;
195                 Write (ad, wd);
196                 csum = (csum + wd) & MMASK;
197                 ad = (ad + 1) & AMASK;
198                 }
199             if (!(sim_switches & SWMASK ('N'))) {       /* unless -n, csum */
200                 if (load_getw (fi, &wd))
201                     return SCPE_FMT;
202 /*              if ((csum ^wd) & MMASK)
203                     return SCPE_CSUM; */
204                 }
205             break;
206 
207         case 0x0: case 0x8:                             /* instructions */
208             if (load_geta (wd, &ad))                    /* get address */
209                 return SCPE_FMT;
210             if ((wd & 0x00F00000) != 0x00900000)        /* if not x, */
211                 ad = (ad + amod) & AMASK;               /* modify */
212             wd = (wd & (SIGN|I_OP)) + (ad << I_V_EA);   /* instruction */
213 
214         default:                                        /* data word */
215             Write (origin, wd);
216             origin = (origin + 1) & AMASK;
217             break;
218             }                                           /* end case */
219         }                                               /* end for */
220 return SCPE_OK;
221 }
222 
223 /* Symbol tables */
224 
225 static const char opcode[] = "ZBYRIDNMPEUTHCAS";
226 
227 static const char hex_decode[] = "0123456789FGJKQW";
228 
lgp_fprint_addr(FILE * st,DEVICE * dptr,t_addr addr)229 void lgp_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr)
230 {
231 if ((dptr == sim_devices[0]) &&
232     ((sim_switches & SWMASK ('T')) ||
233     ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N')))))
234     fprintf (st, "%02d%02d", addr >> 6, addr & SCMASK_30);
235 else fprint_val (st, addr, dptr->aradix, dptr->awidth, PV_LEFT);
236 return;
237 }
238 
lgp_parse_addr(DEVICE * dptr,char * cptr,char ** tptr)239 t_addr lgp_parse_addr (DEVICE *dptr, char *cptr, char **tptr)
240 {
241 t_addr ad, ea;
242 
243 if ((dptr == sim_devices[0]) &&
244     ((sim_switches & SWMASK ('T')) ||
245     ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N'))))) {
246     ad = (t_addr) strtotv (cptr, tptr, 10);
247     if (((ad / 100) >= NTK_30) || ((ad % 100) >= NSC_30)) {
248         *tptr = cptr;
249         return 0;
250         }
251     ea = ((ad / 100) * NSC_30) | (ad % 100);
252     }
253 else ea = (t_addr) strtotv (cptr, tptr, dptr->aradix);
254 return ea;
255 }
256 
lgp_vm_init(void)257 void lgp_vm_init (void)
258 {
259 sim_vm_fprint_addr = &lgp_fprint_addr;
260 sim_vm_parse_addr = &lgp_parse_addr;
261 return;
262 }
263 
264 /* Symbolic decode
265 
266    Inputs:
267         *of     =       output stream
268         addr    =       current PC
269         *val    =       pointer to data
270         *uptr   =       pointer to unit
271         sw      =       switches
272    Outputs:
273         return  =       status code
274 */
275 
fprint_sym(FILE * of,t_addr addr,t_value * val,UNIT * uptr,int32 sw)276 t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
277     UNIT *uptr, int32 sw)
278 {
279 int32 i, c;
280 uint32 inst, op, ea;
281 
282 inst = val[0];
283 if (sw & SWMASK ('A')) {                                /* alphabetic? */
284     if ((uptr == NULL) || !(uptr->flags & UNIT_ATT))
285         return SCPE_ARG;
286     if (uptr->flags & UNIT_FLEX) {                      /* Flex file? */
287         c = flex_to_ascii[inst];                        /* get ASCII equiv */
288         if (c <= 0)
289             return SCPE_ARG;
290         }
291     else c = inst & 0x7F;                               /* ASCII file */
292     fputc (c, of);
293     return SCPE_OK;
294     }
295 
296 if (uptr && (uptr != &cpu_unit))                        /* must be CPU */
297     return SCPE_ARG;
298 if ((sw & SWMASK ('M')) &&                              /* symbolic decode? */
299     ((inst & ~(SIGN|I_OP|I_EA)) == 0)) {
300 	op = I_GETOP (inst);
301     ea = I_GETEA (inst);
302     if (inst & SIGN)
303         fputc ('-', of);
304     fprintf (of, "%c ", opcode[op]);
305     lgp_fprint_addr (of, sim_devices[0], ea);
306     return SCPE_OK;
307     }
308 
309 if ((sw & SWMASK ('L')) ||                              /* LGP hex? */
310     ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) {
311     for (i = 0; i < 8; i++) {
312         c = (inst >> (4 * (7 - i))) & 0xF;
313         fputc (hex_decode[c], of);
314         }
315     return SCPE_OK;
316     }
317 return SCPE_ARG;
318 }
319 
320 /* Symbolic input
321 
322    Inputs:
323         *cptr   =       pointer to input string
324         addr    =       current PC
325         *uptr   =       pointer to unit
326         *val    =       pointer to output values
327         sw      =       switches
328    Outputs:
329         status  =       error status
330 */
331 
parse_sym(char * cptr,t_addr addr,UNIT * uptr,t_value * val,int32 sw)332 t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
333 {
334 int32 i, c;
335 char *tptr;
336 
337 while (isspace (*cptr))                                 /* absorb spaces */
338     cptr++;
339 if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) {
340     if ((uptr == NULL) || !(uptr->flags & UNIT_ATT))
341         return SCPE_ARG;
342     if (uptr->flags & UNIT_FLEX) {                      /* Flex file? */
343         c = ascii_to_flex[*cptr & 0x7F];                /* get Flex equiv */
344         if (c < 0)
345             return SCPE_ARG;
346         val[0] = ((c >> 1) | (c << 5)) & 0x3F;          /* transpose */
347         }
348     else val[0] = *cptr & 0x7F;                         /* ASCII file */
349     return SCPE_OK;
350     }
351 
352 if (uptr && (uptr != &cpu_unit))                        /* must be CPU */
353     return SCPE_ARG;
354 if (!parse_sym_m (cptr, val, sw))                       /* symbolic parse? */
355     return SCPE_OK;
356 if ((sw & SWMASK ('L')) ||                              /* LGP hex? */
357     ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) {
358     val[0] = 0;
359     while (isspace (*cptr)) cptr++;                     /* absorb spaces */
360     for (i = 0; i < 8; i++) {
361         c = *cptr++;                                    /* get char */
362         if (c == 0)
363             return SCPE_OK;
364         if (islower (c))
365             c = toupper (c);
366         if ((tptr = strchr (hex_decode, c)))
367             val[0] = (val[0] << 4) | (tptr - hex_decode);
368         else return SCPE_ARG;
369         }
370     if (*cptr == 0)
371         return SCPE_OK;
372     }
373 return SCPE_ARG;
374 }
375 
376 /* Instruction parse */
377 
parse_sym_m(char * cptr,t_value * val,int32 sw)378 t_stat parse_sym_m (char *cptr, t_value *val, int32 sw)
379 {
380 uint32 ea, sgn;
381 char *tptr, gbuf[CBUFSIZE];
382 
383 if (*cptr == '-') {
384     cptr++;
385     sgn = SIGN;
386     }
387 else sgn = 0;
388 cptr = get_glyph (cptr, gbuf, 0);                       /* get opcode */
389 if (gbuf[1] != 0)
390     return SCPE_ARG;
391 if ((tptr = strchr (opcode, gbuf[0])))
392     val[0] = ((tptr - opcode) << I_V_OP) | sgn;         /* merge opcode */
393 else return SCPE_ARG;
394 cptr = get_glyph (cptr, gbuf, 0);                       /* get address */
395 ea = lgp_parse_addr (sim_devices[0], gbuf, &tptr);
396 if ((tptr == gbuf) || (*tptr != 0) || (ea > AMASK))
397     return SCPE_ARG;
398 val[0] = val[0] | (ea << I_V_EA);                       /* merge address */
399 if (*cptr != 0)
400     return SCPE_2MARG;
401 return SCPE_OK;
402 }
403