First Commit of my working state
[simh.git] / ALTAIR / altair_sys.c
1 /* altair_sys.c: MITS Altair system interface
2
3 Copyright (c) 1997-2005, Charles E. Owen
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 Charles E. Owen 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 Charles E. Owen.
25 */
26
27 #include <ctype.h>
28 #include "altair_defs.h"
29
30 extern DEVICE cpu_dev;
31 extern DEVICE dsk_dev;
32 extern UNIT cpu_unit;
33 extern REG cpu_reg[];
34 extern DEVICE sio_dev;
35 extern DEVICE ptr_dev;
36 extern DEVICE ptp_dev;
37 extern DEVICE lpt_dev;
38 extern unsigned char M[];
39 extern int32 saved_PC;
40
41 /* SCP data structures
42
43 sim_name simulator name string
44 sim_PC pointer to saved PC register descriptor
45 sim_emax number of words needed for examine
46 sim_devices array of pointers to simulated devices
47 sim_stop_messages array of pointers to stop messages
48 sim_load binary loader
49 */
50
51 char sim_name[] = "Altair 8800";
52
53 REG *sim_PC = &cpu_reg[0];
54
55 int32 sim_emax = 4;
56
57 DEVICE *sim_devices[] = {
58 &cpu_dev,
59 &sio_dev,
60 &ptr_dev,
61 &ptp_dev,
62 &dsk_dev,
63 NULL
64 };
65
66 const char *sim_stop_messages[] = {
67 "Unknown error",
68 "Unknown I/O Instruction",
69 "HALT instruction",
70 "Breakpoint",
71 "Invalid Opcode"
72 };
73
74 static const char *opcode[] = {
75 "NOP", "LXI B", "STAX B", "INX B", /* 000-003 */
76 "INR B", "DCR B", "MVI B", "RLC", /* 004-007 */
77 "???", "DAD B", "LDAX B", "DCX B", /* 010-013 */
78 "INR C", "DCR C", "MVI C", "RRC", /* 014-017 */
79 "???", "LXI D", "STAX D", "INX D", /* 020-023 */
80 "INR D", "DCR D", "MVI D", "RAL", /* 024-027 */
81 "???", "DAD D", "LDAX D", "DCX D", /* 030-033 */
82 "INR E", "DCR E", "MVI E", "RAR", /* 034-037 */
83 "???", "LXI H", "SHLD", "INX H", /* 040-043 */
84 "INR H", "DCR H", "MVI H", "DAA", /* 044-047 */
85 "???", "DAD H", "LHLD", "DCX H", /* 050-053 */
86 "INR L", "DCR L", "MVI L", "CMA", /* 054-057 */
87 "???", "LXI SP", "STA", "INX SP", /* 060-063 */
88 "INR M", "DCR M", "MVI M", "STC", /* 064-067 */
89 "???", "DAD SP", "LDA", "DCX SP", /* 070-073 */
90 "INR A", "DCR A", "MVI A", "CMC", /* 074-077 */
91 "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", /* 100-103 */
92 "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 104-107 */
93 "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", /* 110-113 */
94 "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 114-117 */
95 "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", /* 120-123 */
96 "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 124-127 */
97 "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", /* 130-133 */
98 "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 134-137 */
99 "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", /* 140-143 */
100 "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 144-147 */
101 "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", /* 150-153 */
102 "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 154-157 */
103 "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", /* 160-163 */
104 "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 164-167 */
105 "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", /* 170-173 */
106 "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 174-177 */
107 "ADD B", "ADD C", "ADD D", "ADD E", /* 200-203 */
108 "ADD H", "ADD L", "ADD M", "ADD A", /* 204-207 */
109 "ADC B", "ADC C", "ADC D", "ADC E", /* 210-213 */
110 "ADC H", "ADC L", "ADC M", "ADC A", /* 214-217 */
111 "SUB B", "SUB C", "SUB D", "SUB E", /* 220-223 */
112 "SUB H", "SUB L", "SUB M", "SUB A", /* 224-227 */
113 "SBB B", "SBB C", "SBB D", "SBB E", /* 230-233 */
114 "SBB H", "SBB L", "SBB M", "SBB A", /* 234-237 */
115 "ANA B", "ANA C", "ANA D", "ANA E", /* 240-243 */
116 "ANA H", "ANA L", "ANA M", "ANA A", /* 244-247 */
117 "XRA B", "XRA C", "XRA D", "XRA E", /* 250-253 */
118 "XRA H", "XRA L", "XRA M", "XRA A", /* 254-257 */
119 "ORA B", "ORA C", "ORA D", "ORA E", /* 260-263 */
120 "ORA H", "ORA L", "ORA M", "ORA A", /* 264-267 */
121 "CMP B", "CMP C", "CMP D", "CMP E", /* 270-273 */
122 "CMP H", "CMP L", "CMP M", "CMP A", /* 274-277 */
123 "RNZ", "POP B", "JNZ", "JMP", /* 300-303 */
124 "CNZ", "PUSH B", "ADI", "RST 0", /* 304-307 */
125 "RZ", "RET", "JZ", "???", /* 310-313 */
126 "CZ", "CALL", "ACI", "RST 1", /* 314-317 */
127 "RNC", "POP D", "JNC", "OUT", /* 320-323 */
128 "CNC", "PUSH D", "SUI", "RST 2", /* 324-327 */
129 "RC", "???", "JC", "IN", /* 330-333 */
130 "CC", "???", "SBI", "RST 3", /* 334-337 */
131 "RPO", "POP H", "JPO", "XTHL", /* 340-343 */
132 "CPO", "PUSH H", "ANI", "RST 4", /* 344-347 */
133 "RPE", "PCHL", "JPE", "XCHG", /* 350-353 */
134 "CPE", "???", "XRI", "RST 5", /* 354-357 */
135 "RP", "POP PSW", "JP", "DI", /* 360-363 */
136 "CP", "PUSH PSW", "ORI", "RST 6", /* 364-367 */
137 "RM", "SPHL", "JM", "EI", /* 370-373 */
138 "CM", "???", "CPI", "RST 7", /* 374-377 */
139 };
140
141 int32 oplen[256] = {
142 1,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1,0,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1,
143 0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1,0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1,
144 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
145 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
146 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
147 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
148 1,1,3,3,3,1,2,1,1,1,3,0,3,3,2,1,1,1,3,2,3,1,2,1,1,0,3,2,3,0,2,1,
149 1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1,1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1 };
150
151 /* This is the binary loader. The input file is considered to be
152 a string of literal bytes with no format special format. The
153 load starts at the current value of the PC.
154 */
155
156 int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
157 {
158 int32 i, addr = 0, cnt = 0;
159
160 if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
161 addr = saved_PC;
162 while ((i = getc (fileref)) != EOF) {
163 M[addr] = i;
164 addr++;
165 cnt++;
166 } /* end while */
167 printf ("%d Bytes loaded.\n", cnt);
168 return (SCPE_OK);
169 }
170
171 /* Symbolic output
172
173 Inputs:
174 *of = output stream
175 addr = current PC
176 *val = pointer to values
177 *uptr = pointer to unit
178 sw = switches
179 Outputs:
180 status = error code
181 */
182
183 int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
184 UNIT *uptr, int32 sw)
185 {
186 int32 cflag, c1, c2, inst, adr;
187
188 cflag = (uptr == NULL) || (uptr == &cpu_unit);
189 c1 = (val[0] >> 8) & 0177;
190 c2 = val[0] & 0177;
191 if (sw & SWMASK ('A')) {
192 fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
193 return SCPE_OK;
194 }
195 if (sw & SWMASK ('C')) {
196 fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
197 fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
198 return SCPE_OK;
199 }
200 if (!(sw & SWMASK ('M'))) return SCPE_ARG;
201 inst = val[0];
202 fprintf (of, "%s", opcode[inst]);
203 if (oplen[inst] == 2) {
204 if (strchr(opcode[inst], ' ') != NULL)
205 fprintf (of, ",");
206 else fprintf (of, " ");
207 fprintf (of, "%o", val[1]);
208 }
209 if (oplen[inst] == 3) {
210 adr = val[1] & 0xFF;
211 adr |= (val[2] << 8) & 0xff00;
212 if (strchr(opcode[inst], ' ') != NULL)
213 fprintf (of, ",");
214 else fprintf (of, " ");
215 fprintf (of, "%o", adr);
216 }
217 return -(oplen[inst] - 1);
218 }
219
220 /* Symbolic input
221
222 Inputs:
223 *cptr = pointer to input string
224 addr = current PC
225 *uptr = pointer to unit
226 *val = pointer to output values
227 sw = switches
228 Outputs:
229 status = error status
230 */
231
232 int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
233 {
234 int32 cflag, i = 0, j, r;
235 char gbuf[CBUFSIZE];
236
237 cflag = (uptr == NULL) || (uptr == &cpu_unit);
238 while (isspace (*cptr)) cptr++; /* absorb spaces */
239 if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
240 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
241 val[0] = (uint32) cptr[0];
242 return SCPE_OK;
243 }
244 if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
245 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
246 val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1];
247 return SCPE_OK;
248 }
249
250 /* An instruction: get opcode (all characters until null, comma,
251 or numeric (including spaces).
252 */
253
254 while (1) {
255 if (*cptr == ',' || *cptr == '\0' ||
256 isdigit(*cptr))
257 break;
258 gbuf[i] = toupper(*cptr);
259 cptr++;
260 i++;
261 }
262
263 /* Allow for RST which has numeric as part of opcode */
264
265 if (toupper(gbuf[0]) == 'R' &&
266 toupper(gbuf[1]) == 'S' &&
267 toupper(gbuf[2]) == 'T') {
268 gbuf[i] = toupper(*cptr);
269 cptr++;
270 i++;
271 }
272
273 /* Allow for 'MOV' which is only opcode that has comma in it. */
274
275 if (toupper(gbuf[0]) == 'M' &&
276 toupper(gbuf[1]) == 'O' &&
277 toupper(gbuf[2]) == 'V') {
278 gbuf[i] = toupper(*cptr);
279 cptr++;
280 i++;
281 gbuf[i] = toupper(*cptr);
282 cptr++;
283 i++;
284 }
285
286 /* kill trailing spaces if any */
287 gbuf[i] = '\0';
288 for (j = i - 1; gbuf[j] == ' '; j--) {
289 gbuf[j] = '\0';
290 }
291
292 /* find opcode in table */
293 for (j = 0; j < 256; j++) {
294 if (strcmp(gbuf, opcode[j]) == 0)
295 break;
296 }
297 if (j > 255) /* not found */
298 return SCPE_ARG;
299
300 val[0] = j; /* store opcode */
301 if (oplen[j] < 2) /* if 1-byter we are done */
302 return SCPE_OK;
303 if (*cptr == ',') cptr++;
304 cptr = get_glyph(cptr, gbuf, 0); /* get address */
305 sscanf(gbuf, "%o", &r);
306 if (oplen[j] == 2) {
307 val[1] = r & 0xFF;
308 return (-1);
309 }
310 val[1] = r & 0xFF;
311 val[2] = (r >> 8) & 0xFF;
312 return (-2);
313 }