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