1 /* lgp_sys.c: LGP-30 simulator interface
3 Copyright (c) 2004-2005, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 04-Jan-05 RMS Modified VM pointer setup
32 t_stat
parse_sym_m (char *cptr
, t_value
*val
, int32 sw
);
35 extern DEVICE cpu_dev
;
37 extern DEVICE tti_dev
, tto_dev
;
38 extern DEVICE ptr_dev
, ptp_dev
;
42 extern uint32 ts_flag
;
43 extern int32 sim_switches
;
44 extern int32 flex_to_ascii
[128], ascii_to_flex
[128];
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
);
49 /* SCP data structures and interface routines
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
59 char sim_name
[] = "LGP30";
61 REG
*sim_PC
= &cpu_reg
[0];
65 DEVICE
*sim_devices
[] = {
74 const char *sim_stop_messages
[] = {
81 /* Binary loader - implements a restricted form of subroutine 10.4
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):
89 + command (not supported)
94 v hex fill (checksummed unless -n)
95 8 negative instruction
98 /* Utility routine - read characters until ' (conditional stop) */
100 t_stat
load_getw (FILE *fi
, uint32
*wd
)
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);
118 /* Utility routine - convert ttss decimal address to binary */
120 t_stat
load_geta (uint32 wd
, uint32
*ad
)
122 uint32 n1
, n2
, n3
, n4
, tr
, sc
;
124 n1
= (wd
>> 12) & 0xF;
125 n2
= (wd
>> 8) & 0xF;
126 n3
= (wd
>> 4) & 0xF;
128 if ((n2
> 9) || (n4
> 9)) return SCPE_ARG
;
131 if ((tr
>= NTK_30
) || (sc
>= NSC_30
)) return SCPE_ARG
;
132 *ad
= (tr
* NSC_30
) + sc
;
138 t_stat
sim_load (FILE *fi
, char *cptr
, char *fnam
, int flag
)
140 uint32 wd
, origin
, amod
, csum
, cnt
, tr
, sc
, ad
, cmd
;
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> */
148 case 0x2: /* + command */
151 case 0x3: /* ; start fill */
152 if (load_geta (wd
, &origin
)) return SCPE_FMT
; /* origin = addr */
155 case 0x4: /* / set modifier */
156 if (load_geta (wd
, &amod
)) return SCPE_FMT
; /* modifier = addr */
159 case 0x5: /* . transfer */
160 if (load_geta (wd
, &PC
)) return SCPE_FMT
; /* PC = addr */
161 return SCPE_OK
; /* done! */
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
;
169 origin
= (origin
+ 1) & AMASK
;
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
;
183 csum
= (csum
+ wd
) & MMASK
;
184 ad
= (ad
+ 1) & AMASK
;
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; */
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 */
198 default: /* data word */
200 origin
= (origin
+ 1) & AMASK
;
209 static const char opcode
[] = "ZBYRIDNMPEUTHCAS";
211 static const char hex_decode
[] = "0123456789FGJKQW";
213 void lgp_fprint_addr (FILE *st
, DEVICE
*dptr
, t_addr addr
)
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
);
223 t_addr
lgp_parse_addr (DEVICE
*dptr
, char *cptr
, char **tptr
)
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
)) {
235 ea
= ((ad
/ 100) * NSC_30
) | (ad
% 100);
237 else ea
= (t_addr
) strtotv (cptr
, tptr
, dptr
->aradix
);
241 void lgp_vm_init (void)
243 sim_vm_fprint_addr
= &lgp_fprint_addr
;
244 sim_vm_parse_addr
= &lgp_parse_addr
;
253 *val = pointer to data
254 *uptr = pointer to unit
260 t_stat
fprint_sym (FILE *of
, t_addr addr
, t_value
*val
,
261 UNIT
*uptr
, int32 sw
)
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
;
273 else c
= inst
& 0x7F; /* ASCII file */
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)) {
283 if (inst
& SIGN
) fputc ('-', of
);
284 fprintf (of
, "%c ", opcode
[op
]);
285 lgp_fprint_addr (of
, sim_devices
[0], ea
);
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
);
303 *cptr = pointer to input string
305 *uptr = pointer to unit
306 *val = pointer to output values
309 status = error status
312 t_stat
parse_sym (char *cptr
, t_addr addr
, UNIT
*uptr
, t_value
*val
, int32 sw
)
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 */
325 else val
[0] = *cptr
& 0x7F; /* ASCII file */
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')))) {
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
;
343 if (*cptr
== 0) return SCPE_OK
;
348 /* Instruction parse */
350 t_stat
parse_sym_m (char *cptr
, t_value
*val
, int32 sw
)
353 char *tptr
, gbuf
[CBUFSIZE
];
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
))
369 val
[0] = val
[0] | (ea
<< I_V_EA
); /* merge address */
370 if (*cptr
!= 0) return SCPE_2MARG
;