1 /* altair_sys.c: MITS Altair system interface
3 Copyright (c) 1997-2005, Charles E. Owen
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 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.
28 #include "altair_defs.h"
30 extern DEVICE cpu_dev
;
31 extern DEVICE dsk_dev
;
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
;
41 /* SCP data structures
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
51 char sim_name
[] = "Altair 8800";
53 REG
*sim_PC
= &cpu_reg
[0];
57 DEVICE
*sim_devices
[] = {
66 const char *sim_stop_messages
[] = {
68 "Unknown I/O Instruction",
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 */
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 };
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.
156 int32
sim_load (FILE *fileref
, char *cptr
, char *fnam
, int flag
)
158 int32 i
, addr
= 0, cnt
= 0;
160 if ((*cptr
!= 0) || (flag
!= 0)) return SCPE_ARG
;
162 while ((i
= getc (fileref
)) != EOF
) {
167 printf ("%d Bytes loaded.\n", cnt
);
176 *val = pointer to values
177 *uptr = pointer to unit
183 int32
fprint_sym (FILE *of
, int32 addr
, uint32
*val
,
184 UNIT
*uptr
, int32 sw
)
186 int32 cflag
, c1
, c2
, inst
, adr
;
188 cflag
= (uptr
== NULL
) || (uptr
== &cpu_unit
);
189 c1
= (val
[0] >> 8) & 0177;
191 if (sw
& SWMASK ('A')) {
192 fprintf (of
, (c2
< 040)? "<%03o>": "%c", c2
);
195 if (sw
& SWMASK ('C')) {
196 fprintf (of
, (c1
< 040)? "<%03o>": "%c", c1
);
197 fprintf (of
, (c2
< 040)? "<%03o>": "%c", c2
);
200 if (!(sw
& SWMASK ('M'))) return SCPE_ARG
;
202 fprintf (of
, "%s", opcode
[inst
]);
203 if (oplen
[inst
] == 2) {
204 if (strchr(opcode
[inst
], ' ') != NULL
)
206 else fprintf (of
, " ");
207 fprintf (of
, "%o", val
[1]);
209 if (oplen
[inst
] == 3) {
211 adr
|= (val
[2] << 8) & 0xff00;
212 if (strchr(opcode
[inst
], ' ') != NULL
)
214 else fprintf (of
, " ");
215 fprintf (of
, "%o", adr
);
217 return -(oplen
[inst
] - 1);
223 *cptr = pointer to input string
225 *uptr = pointer to unit
226 *val = pointer to output values
229 status = error status
232 int32
parse_sym (char *cptr
, int32 addr
, UNIT
*uptr
, uint32
*val
, int32 sw
)
234 int32 cflag
, i
= 0, j
, r
;
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];
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];
250 /* An instruction: get opcode (all characters until null, comma,
251 or numeric (including spaces).
255 if (*cptr
== ',' || *cptr
== '\0' ||
258 gbuf
[i
] = toupper(*cptr
);
263 /* Allow for RST which has numeric as part of opcode */
265 if (toupper(gbuf
[0]) == 'R' &&
266 toupper(gbuf
[1]) == 'S' &&
267 toupper(gbuf
[2]) == 'T') {
268 gbuf
[i
] = toupper(*cptr
);
273 /* Allow for 'MOV' which is only opcode that has comma in it. */
275 if (toupper(gbuf
[0]) == 'M' &&
276 toupper(gbuf
[1]) == 'O' &&
277 toupper(gbuf
[2]) == 'V') {
278 gbuf
[i
] = toupper(*cptr
);
281 gbuf
[i
] = toupper(*cptr
);
286 /* kill trailing spaces if any */
288 for (j
= i
- 1; gbuf
[j
] == ' '; j
--) {
292 /* find opcode in table */
293 for (j
= 0; j
< 256; j
++) {
294 if (strcmp(gbuf
, opcode
[j
]) == 0)
297 if (j
> 255) /* not found */
300 val
[0] = j
; /* store opcode */
301 if (oplen
[j
] < 2) /* if 1-byter we are done */
303 if (*cptr
== ',') cptr
++;
304 cptr
= get_glyph(cptr
, gbuf
, 0); /* get address */
305 sscanf(gbuf
, "%o", &r
);
311 val
[2] = (r
>> 8) & 0xFF;