Because some key files have changed, V3.0 should be unzipped to a clean directory. 1. New Features in 3.0-0 1.1 SCP and Libraries - Added ASSIGN/DEASSIGN (logical name) commands. - Changed RESTORE to unconditionally detach files. - Added E11 and TPC format support to magtape library. - Fixed bug in SHOW CONNECTIONS. - Added USE_ADDR64 support 1.2 All magtapes - Magtapes support SIMH format, E11 format, and TPC format (read only). - SET <tape_unit> FORMAT=format sets the specified tape unit's format. - SHOW <tape_unit> FORMAT displays the specified tape unit's format. - Tape format can also be set as part of the ATTACH command, using the -F switch. 1.3 VAX - VAX can be compiled without USE_INT64. - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support files > 2GB. - VAX ROM has speed control (SET ROM DELAY/NODELAY). 2. Bugs Fixed in 3.01-0 2.1 VAX - Fixed CVTfi bug: integer overflow not set if exponent out of range - Fixed EMODx bugs: o First and second operands reversed o Separated fraction received wrong exponent o Overflow calculation on separated integer incorrect o Fraction not set to zero if exponent out of range - Fixed interval timer and ROM access to pass power-up self-test even on very fast host processors (fixes from Mark Pizzolato). 2.2 1401 - Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. - Fixed MCE bug, BS off by 1 if zero suppress. - Fixed chaining bug, D lost if return to SCP. - Fixed H branch, branch occurs after continue. - Added check for invalid 8 character MCW, LCA. - Fixed magtape load-mode end of record response. 2.3 Nova - Fixed DSK variable size interaction with restore. 2.4 PDP-1 - Fixed DT variable size interaction with restore. 2.5 PDP-11 - Fixed DT variable size interaction with restore. - Fixed bug in MMR1 update (found by Tim Stark). - Added XQ features and fixed bugs: o Corrected XQ interrupts on IE state transition (code by Tom Evans). o Added XQ interrupt clear on soft reset. o Removed XQ interrupt when setting XL or RL (multiple people). o Added SET/SHOW XQ STATS. o Added SHOW XQ FILTERS. o Added ability to split received packet into multiple buffers. o Added explicit runt and giant packet processing. 2.6 PDP-18B - Fixed DT, RF variable size interaction with restore. - Fixed MT bug in MTTR. 2.7 PDP-8 - Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed MT bug in SKTR. 2.8 HP2100 - Fixed bug in DP (13210A controller only), DQ read status. - Fixed bug in DP, DQ seek complete. 2.9 GRI - Fixed bug in SC queue pointer management. 3. New Features in 3.0 vs prior releases N/A 4. Bugs Fixed in 3.0 vs prior releases N/A 5. General Notes WARNING: The RESTORE command has changed. RESTORE will now detach an attached file on a unit, if that unit did not have an attached file in the saved configuration. This is required to assure that the unit flags and the file state are consistent. WARNING: The compilation scheme for the PDP-10, PDP-11, and VAX has changed. Use one of the supplied build files, or read the documentation carefully, before compiling any of these simulators.
302 lines
10 KiB
C
302 lines
10 KiB
C
/* altair_sys.c: MITS Altair system interface
|
||
|
||
Copyright (c) 1997-2003, Charles E. Owen
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a
|
||
copy of this software and associated documentation files (the "Software"),
|
||
to deal in the Software without restriction, including without limitation
|
||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
and/or sell copies of the Software, and to permit persons to whom the
|
||
Software is furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
Except as contained in this notice, the name of Charles E. Owen shall not
|
||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||
in this Software without prior written authorization from Charles E. Owen.
|
||
*/
|
||
|
||
#include <ctype.h>
|
||
#include "altair_defs.h"
|
||
|
||
extern DEVICE cpu_dev;
|
||
extern DEVICE dsk_dev;
|
||
extern UNIT cpu_unit;
|
||
extern REG cpu_reg[];
|
||
extern DEVICE sio_dev;
|
||
extern DEVICE ptr_dev;
|
||
extern DEVICE ptp_dev;
|
||
extern DEVICE lpt_dev;
|
||
extern unsigned char M[];
|
||
extern int32 saved_PC;
|
||
|
||
/* SCP data structures
|
||
|
||
sim_name simulator name string
|
||
sim_PC pointer to saved PC register descriptor
|
||
sim_emax number of words needed for examine
|
||
sim_devices array of pointers to simulated devices
|
||
sim_stop_messages array of pointers to stop messages
|
||
sim_load binary loader
|
||
*/
|
||
|
||
char sim_name[] = "Altair 8800";
|
||
|
||
REG *sim_PC = &cpu_reg[0];
|
||
|
||
int32 sim_emax = 4;
|
||
|
||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev,
|
||
&ptp_dev, &dsk_dev, NULL };
|
||
|
||
const char *sim_stop_messages[] = {
|
||
"Unknown error",
|
||
"Unknown I/O Instruction",
|
||
"HALT instruction",
|
||
"Breakpoint",
|
||
"Invalid Opcode" };
|
||
|
||
static const char *opcode[] = {
|
||
"NOP", "LXI B", "STAX B", "INX B", /* 000-003 */
|
||
"INR B", "DCR B", "MVI B", "RLC", /* 004-007 */
|
||
"???", "DAD B", "LDAX B", "DCX B", /* 010-013 */
|
||
"INR C", "DCR C", "MVI C", "RRC", /* 014-017 */
|
||
"???", "LXI D", "STAX D", "INX D", /* 020-023 */
|
||
"INR D", "DCR D", "MVI D", "RAL", /* 024-027 */
|
||
"???", "DAD D", "LDAX D", "DCX D", /* 030-033 */
|
||
"INR E", "DCR E", "MVI E", "RAR", /* 034-037 */
|
||
"???", "LXI H", "SHLD", "INX H", /* 040-043 */
|
||
"INR H", "DCR H", "MVI H", "DAA", /* 044-047 */
|
||
"???", "DAD H", "LHLD", "DCX H", /* 050-053 */
|
||
"INR L", "DCR L", "MVI L", "CMA", /* 054-057 */
|
||
"???", "LXI SP", "STA", "INX SP", /* 060-063 */
|
||
"INR M", "DCR M", "MVI M", "STC", /* 064-067 */
|
||
"???", "DAD SP", "LDA", "DCX SP", /* 070-073 */
|
||
"INR A", "DCR A", "MVI A", "CMC", /* 074-077 */
|
||
"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", /* 100-103 */
|
||
"MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 104-107 */
|
||
"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", /* 110-113 */
|
||
"MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 114-117 */
|
||
"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", /* 120-123 */
|
||
"MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 124-127 */
|
||
"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", /* 130-133 */
|
||
"MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 134-137 */
|
||
"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", /* 140-143 */
|
||
"MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 144-147 */
|
||
"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", /* 150-153 */
|
||
"MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 154-157 */
|
||
"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", /* 160-163 */
|
||
"MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 164-167 */
|
||
"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", /* 170-173 */
|
||
"MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 174-177 */
|
||
"ADD B", "ADD C", "ADD D", "ADD E", /* 200-203 */
|
||
"ADD H", "ADD L", "ADD M", "ADD A", /* 204-207 */
|
||
"ADC B", "ADC C", "ADC D", "ADC E", /* 210-213 */
|
||
"ADC H", "ADC L", "ADC M", "ADC A", /* 214-217 */
|
||
"SUB B", "SUB C", "SUB D", "SUB E", /* 220-223 */
|
||
"SUB H", "SUB L", "SUB M", "SUB A", /* 224-227 */
|
||
"SBB B", "SBB C", "SBB D", "SBB E", /* 230-233 */
|
||
"SBB H", "SBB L", "SBB M", "SBB A", /* 234-237 */
|
||
"ANA B", "ANA C", "ANA D", "ANA E", /* 240-243 */
|
||
"ANA H", "ANA L", "ANA M", "ANA A", /* 244-247 */
|
||
"XRA B", "XRA C", "XRA D", "XRA E", /* 250-253 */
|
||
"XRA H", "XRA L", "XRA M", "XRA A", /* 254-257 */
|
||
"ORA B", "ORA C", "ORA D", "ORA E", /* 260-263 */
|
||
"ORA H", "ORA L", "ORA M", "ORA A", /* 264-267 */
|
||
"CMP B", "CMP C", "CMP D", "CMP E", /* 270-273 */
|
||
"CMP H", "CMP L", "CMP M", "CMP A", /* 274-277 */
|
||
"RNZ", "POP B", "JNZ", "JMP", /* 300-303 */
|
||
"CNZ", "PUSH B", "ADI", "RST 0", /* 304-307 */
|
||
"RZ", "RET", "JZ", "???", /* 310-313 */
|
||
"CZ", "CALL", "ACI", "RST 1", /* 314-317 */
|
||
"RNC", "POP D", "JNC", "OUT", /* 320-323 */
|
||
"CNC", "PUSH D", "SUI", "RST 2", /* 324-327 */
|
||
"RC", "???", "JC", "IN", /* 330-333 */
|
||
"CC", "???", "SBI", "RST 3", /* 334-337 */
|
||
"RPO", "POP H", "JPO", "XTHL", /* 340-343 */
|
||
"CPO", "PUSH H", "ANI", "RST 4", /* 344-347 */
|
||
"RPE", "PCHL", "JPE", "XCHG", /* 350-353 */
|
||
"CPE", "???", "XRI", "RST 5", /* 354-357 */
|
||
"RP", "POP PSW", "JP", "DI", /* 360-363 */
|
||
"CP", "PUSH PSW", "ORI", "RST 6", /* 364-367 */
|
||
"RM", "SPHL", "JM", "EI", /* 370-373 */
|
||
"CM", "???", "CPI", "RST 7", /* 374-377 */
|
||
};
|
||
|
||
int32 oplen[256] = {
|
||
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,
|
||
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,
|
||
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,
|
||
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,
|
||
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,
|
||
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,
|
||
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,
|
||
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 };
|
||
|
||
/* This is the binary loader. The input file is considered to be
|
||
a string of literal bytes with no format special format. The
|
||
load starts at the current value of the PC.
|
||
*/
|
||
|
||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||
{
|
||
int32 i, addr = 0, cnt = 0;
|
||
|
||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||
addr = saved_PC;
|
||
while ((i = getc (fileref)) != EOF) {
|
||
M[addr] = i;
|
||
addr++;
|
||
cnt++;
|
||
} /* end while */
|
||
printf ("%d Bytes loaded.\n", cnt);
|
||
return (SCPE_OK);
|
||
}
|
||
|
||
/* Symbolic output
|
||
|
||
Inputs:
|
||
*of = output stream
|
||
addr = current PC
|
||
*val = pointer to values
|
||
*uptr = pointer to unit
|
||
sw = switches
|
||
Outputs:
|
||
status = error code
|
||
*/
|
||
|
||
int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val,
|
||
UNIT *uptr, int32 sw)
|
||
{
|
||
int32 cflag, c1, c2, inst, adr;
|
||
|
||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||
c1 = (val[0] >> 8) & 0177;
|
||
c2 = val[0] & 0177;
|
||
if (sw & SWMASK ('A')) {
|
||
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
|
||
return SCPE_OK; }
|
||
if (sw & SWMASK ('C')) {
|
||
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
|
||
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
|
||
return SCPE_OK; }
|
||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||
inst = val[0];
|
||
fprintf (of, "%s", opcode[inst]);
|
||
if (oplen[inst] == 2) {
|
||
if (strchr(opcode[inst], ' ') != NULL)
|
||
fprintf (of, ",");
|
||
else fprintf (of, " ");
|
||
fprintf (of, "%o", val[1]);
|
||
}
|
||
if (oplen[inst] == 3) {
|
||
adr = val[1] & 0xFF;
|
||
adr |= (val[2] << 8) & 0xff00;
|
||
if (strchr(opcode[inst], ' ') != NULL)
|
||
fprintf (of, ",");
|
||
else fprintf (of, " ");
|
||
fprintf (of, "%o", adr);
|
||
}
|
||
return -(oplen[inst] - 1);
|
||
}
|
||
|
||
/* Symbolic input
|
||
|
||
Inputs:
|
||
*cptr = pointer to input string
|
||
addr = current PC
|
||
*uptr = pointer to unit
|
||
*val = pointer to output values
|
||
sw = switches
|
||
Outputs:
|
||
status = error status
|
||
*/
|
||
|
||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, unsigned int32 *val, int32 sw)
|
||
{
|
||
int32 cflag, i = 0, j, r;
|
||
char gbuf[CBUFSIZE];
|
||
|
||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||
val[0] = (unsigned int) cptr[0];
|
||
return SCPE_OK; }
|
||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
|
||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||
val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1];
|
||
return SCPE_OK; }
|
||
|
||
/* An instruction: get opcode (all characters until null, comma,
|
||
or numeric (including spaces).
|
||
*/
|
||
|
||
while (1) {
|
||
if (*cptr == ',' || *cptr == '\0' ||
|
||
isdigit(*cptr))
|
||
break;
|
||
gbuf[i] = toupper(*cptr);
|
||
cptr++;
|
||
i++;
|
||
}
|
||
|
||
/* Allow for RST which has numeric as part of opcode */
|
||
|
||
if (toupper(gbuf[0]) == 'R' &&
|
||
toupper(gbuf[1]) == 'S' &&
|
||
toupper(gbuf[2]) == 'T') {
|
||
gbuf[i] = toupper(*cptr);
|
||
cptr++;
|
||
i++;
|
||
}
|
||
|
||
/* Allow for 'MOV' which is only opcode that has comma in it. */
|
||
|
||
if (toupper(gbuf[0]) == 'M' &&
|
||
toupper(gbuf[1]) == 'O' &&
|
||
toupper(gbuf[2]) == 'V') {
|
||
gbuf[i] = toupper(*cptr);
|
||
cptr++;
|
||
i++;
|
||
gbuf[i] = toupper(*cptr);
|
||
cptr++;
|
||
i++;
|
||
}
|
||
|
||
/* kill trailing spaces if any */
|
||
gbuf[i] = '\0';
|
||
for (j = i - 1; gbuf[j] == ' '; j--) {
|
||
gbuf[j] = '\0';
|
||
}
|
||
|
||
/* find opcode in table */
|
||
for (j = 0; j < 256; j++) {
|
||
if (strcmp(gbuf, opcode[j]) == 0)
|
||
break;
|
||
}
|
||
if (j > 255) /* not found */
|
||
return SCPE_ARG;
|
||
|
||
val[0] = j; /* store opcode */
|
||
if (oplen[j] < 2) /* if 1-byter we are done */
|
||
return SCPE_OK;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0); /* get address */
|
||
sscanf(gbuf, "%o", &r);
|
||
if (oplen[j] == 2) {
|
||
val[1] = r & 0xFF;
|
||
return (-1);
|
||
}
|
||
val[1] = r & 0xFF;
|
||
val[2] = (r >> 8) & 0xFF;
|
||
return (-2);
|
||
}
|