The makefile now works for Linux and most Unix's. However, for Solaris and MacOS, you must first export the OSTYPE environment variable: > export OSTYPE > make Otherwise, you will get build errors. 1. New Features 1.1 3.8-0 1.1.1 SCP and Libraries - BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and show (respectively) a breakpoint at the current PC. 1.1.2 GRI - Added support for the GRI-99 processor. 1.1.3 HP2100 - Added support for the BACI terminal interface. - Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions. 1.1.4 Nova - Added support for 64KW memory (implemented in third-party CPU's). 1.1.5 PDP-11 - Added support for DC11, RC11, KE11A, KG11A. - Added modem control support for DL11. - Added ASCII character support for all 8b devices. 1.2 3.8-1 1.2.1 SCP and libraries - Added capability to set line connection order for terminal multiplexers. 1.2.2 HP2100 - Added support for 12620A/12936A privileged interrupt fence. - Added support for 12792C eight-channel asynchronous multiplexer. 1.3 3.8-2 1.3.1 1401 - Added "no rewind" option to magtape boot. 1.3.2 PDP-11 - Added RD32 support to RQ - Added debug support to RL 1.3.3 PDP-8 - Added FPP support (many thanks to Rick Murphy for debugging the code) 2. Bugs Fixed Please see the revision history on http://simh.trailing-edge.com or in the source module sim_rev.h.
425 lines
12 KiB
C
425 lines
12 KiB
C
/* swtp_sys.c: SWTP 6800 system interface
|
||
|
||
Copyright (c) 2005, William Beech
|
||
|
||
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
|
||
WILLIAM A BEECH 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 William A. Beech shall not
|
||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||
in this Software without prior written authorization from William A. Beech.
|
||
|
||
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
|
||
|
||
*/
|
||
|
||
#include <ctype.h>
|
||
#include <string.h>
|
||
#include "swtp_defs.h"
|
||
|
||
/* externals */
|
||
|
||
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;
|
||
extern int32 sim_switches;
|
||
//extern int32 (*sim_vm_fprint_addr)(FILE*, DEVICE*,t_addr);
|
||
|
||
/* prototypes */
|
||
|
||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag);
|
||
int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
|
||
UNIT *uptr, int32 sw);
|
||
t_addr fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr);
|
||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw);
|
||
void sim_special_init (void);
|
||
|
||
/* links into scp */
|
||
|
||
void (*sim_vm_init)(void) = &sim_special_init;
|
||
|
||
/* 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[] = "SWTP 6800";
|
||
|
||
REG *sim_PC = &cpu_reg[0];
|
||
|
||
int32 sim_emax = 16;
|
||
|
||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptp_dev, &ptr_dev, &dsk_dev, NULL };
|
||
|
||
const char *sim_stop_messages[] = {
|
||
"Unknown error",
|
||
"Unknown I/O Instruction",
|
||
"HALT instruction",
|
||
"Breakpoint",
|
||
"Invalid Opcode",
|
||
"Invalid Memory" };
|
||
|
||
static const char *opcode[] = {
|
||
"???", "NOP", "???", "???", //0x00
|
||
"???", "???", "TAP", "TPA",
|
||
"INX", "DEX", "CLV", "SEV",
|
||
"CLC", "SEC", "CLI", "SEI",
|
||
"SBA", "CBA", "???", "???", //0x10
|
||
"???", "???", "TAB", "TBA",
|
||
"???", "DAA", "???", "ABA",
|
||
"???", "???", "???", "???",
|
||
"BRA", "???", "BHI", "BLS", //0x20
|
||
"BCC", "BCS", "BNE", "BEQ",
|
||
"BVC", "BVS", "BPL", "BMI",
|
||
"BGE", "BLT", "BGT", "BLE",
|
||
"TSX", "INS", "PULA", "PULB", //0x30
|
||
"DES", "TXS", "PSHA", "PSHB",
|
||
"???", "RTS", "???", "RTI",
|
||
"???", "???", "WAI", "SWI",
|
||
"NEGA", "???", "???", "COMA", //0x40
|
||
"LSRA", "???", "RORA", "ASRA",
|
||
"ASLA", "ROLA", "DECA", "???",
|
||
"INCA", "TSTA", "???", "CLRA",
|
||
"NEGB", "???", "???", "COMB", //0x50
|
||
"LSRB", "???", "RORB", "ASRB",
|
||
"ASLB", "ROLB", "DECB", "???",
|
||
"INCB", "TSTB", "???", "CLRB",
|
||
"NEG", "???", "???", "COM", //0x60
|
||
"LSR", "???", "ROR", "ASR",
|
||
"ASL", "ROL", "DEC", "???",
|
||
"INC", "TST", "JMP", "CLR",
|
||
"NEG", "???", "???", "COM", //0x70
|
||
"LSR", "???", "ROR", "ASR",
|
||
"ASL", "ROL", "DEC", "???",
|
||
"INC", "TST", "JMP", "CLR",
|
||
"SUBA", "CMPA", "SBCA", "???", //0x80
|
||
"ANDA", "BITA", "LDAA", "???",
|
||
"EORA", "ADCA", "ORAA", "ADDA",
|
||
"CPX", "BSR", "LDS", "???",
|
||
"SUBA", "CMPA", "SBCA", "???", //0x90
|
||
"ANDA", "BITA", "LDAA", "STAA",
|
||
"EORA", "ADCA", "ORAA", "ADDA",
|
||
"CPX", "???", "LDS", "STS",
|
||
"SUBA", "CMPA", "SBCA", "???", //0xA0
|
||
"ANDA", "BITA", "LDAA", "STAA",
|
||
"EORA", "ADCA", "ORAA", "ADDA",
|
||
"CPX X", "JSR X", "LDS X", "STS X",
|
||
"SUBA", "CMPA", "SBCA", "???", //0xB0
|
||
"ANDA", "BITA", "LDAA", "STAA",
|
||
"EORA", "ADCA", "ORAA", "ADDA",
|
||
"CPX", "JSR", "LDS", "STS",
|
||
"SUBB", "CMPB", "SBCB", "???", //0xC0
|
||
"ANDB", "BITB", "LDAB", "???",
|
||
"EORB", "ADCB", "ORAB", "ADDB",
|
||
"???", "???", "LDX", "???",
|
||
"SUBB", "CMPB", "SBCB", "???", //0xD0
|
||
"ANDB", "BITB", "LDAB", "STAB",
|
||
"EORB", "ADCB", "ORAB", "ADDB",
|
||
"???", "???", "LDX", "STX",
|
||
"SUBB", "CMPB", "SBCB", "???", //0xE0
|
||
"ANDB", "BITB", "LDAB", "STAB",
|
||
"EORB", "ADCB", "ORAB", "ADDB",
|
||
"???", "???", "LDX", "STX",
|
||
"SUBB", "CMPB", "SBCB", "???", //0xF0
|
||
"ANDB", "BITB", "LDAB", "STAB",
|
||
"EORB", "ADCB", "ORAB", "ADDB",
|
||
"???", "???", "LDX", "STX",
|
||
};
|
||
|
||
int32 oplen[256] = {
|
||
0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00
|
||
1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0,
|
||
2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||
1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,
|
||
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40
|
||
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1,
|
||
2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2,
|
||
3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3,
|
||
2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80
|
||
2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2,
|
||
2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,
|
||
3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,
|
||
2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0
|
||
2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,
|
||
2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,
|
||
3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 };
|
||
|
||
/* This is the dumper/loader. This command uses the -h to signify a
|
||
hex dump/load vice a binary one. If no address is given to load, it
|
||
takes the address from the hex record or the current PC for binary.
|
||
*/
|
||
|
||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||
{
|
||
int32 i, cnt = 0, addr = 0, start = 0x10000, end = 0, bytecnt,
|
||
cksum1, cksum, bytes[250];
|
||
char buffer[256];
|
||
|
||
sscanf(cptr," %x-%x", &start, &end);
|
||
if (flag) { // dump
|
||
if (start == 0x10000) // no address parameter
|
||
return SCPE_2FARG;
|
||
if (sim_switches & 0x80) { // hex dump
|
||
addr = start;
|
||
while (addr <= end) { // more records to write
|
||
if ((addr + 16) <= end) // how many bytes this record
|
||
bytecnt = 16 + 3;
|
||
else
|
||
bytecnt = end - addr + 4;
|
||
cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum
|
||
fprintf(fileref, "S1%02X%02X%02X", bytecnt, addr>>8, addr&0xFF); //header
|
||
for (i=0; i<bytecnt-3; i++, addr++, cnt++) { // data
|
||
fprintf(fileref, "%02X", M[addr]);
|
||
cksum -= M[addr];
|
||
}
|
||
fprintf(fileref, "%02X\r\n", cksum & 0xff); // eor
|
||
}
|
||
fprintf(fileref, "S9\r\n"); // eof
|
||
} else { // binary dump
|
||
for (addr = start; addr <= end; addr++, cnt++) {
|
||
putc(M[addr], fileref);
|
||
}
|
||
}
|
||
printf ("%d Bytes dumped starting at %04X\n", cnt, start);
|
||
} else { // load
|
||
if (sim_switches & 0x80) { // hex load
|
||
while ((fgets(buffer, 255, fileref)) != NULL) {
|
||
if (buffer[0] != 'S')
|
||
printf("Not a Motorola hex format file\n");
|
||
else {
|
||
if (buffer[0] == '0') // name record
|
||
printf("Name record found and ignored\n");
|
||
else if (buffer[1] == '1') { // another record
|
||
sscanf(buffer+2,"%2x%4x", &bytecnt, &addr);
|
||
if (start == 0x10000)
|
||
start = addr;
|
||
for (i=0; i < bytecnt-3; i++)
|
||
sscanf(buffer+8+(2*i), "%2x", &bytes[i]);
|
||
sscanf(buffer+8+(2*i), "%2x", &cksum1);
|
||
cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum
|
||
for (i=0; i < bytecnt-3; i++)
|
||
cksum -= bytes[i];
|
||
cksum &= 0xFF;
|
||
if (cksum != cksum1)
|
||
printf("Checksum error\n");
|
||
else {
|
||
for (i=0; i < bytecnt-3; i++) {
|
||
M[addr++] = bytes[i];
|
||
cnt++;
|
||
}
|
||
}
|
||
} else if (buffer[1] == '9') // end of file
|
||
printf("End of file\n");
|
||
}
|
||
}
|
||
} else { // binary load
|
||
if (start == 0x10000) // no starting address
|
||
addr = saved_PC;
|
||
else
|
||
addr = start;
|
||
start = addr;
|
||
while ((i = getc (fileref)) != EOF) {
|
||
M[addr] = i;
|
||
addr++;
|
||
cnt++;
|
||
}
|
||
}
|
||
printf ("%d Bytes loaded starting at %04X\n", cnt, start);
|
||
}
|
||
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, uint32 *val,
|
||
UNIT *uptr, int32 sw)
|
||
{
|
||
int32 i, inst, inst1;
|
||
|
||
if (sw & SWMASK ('D')) { // dump memory
|
||
for (i=0; i<16; i++)
|
||
fprintf(of, "%02X ", val[i]);
|
||
fprintf(of, " ");
|
||
for (i=0; i<16; i++)
|
||
if (isprint(val[i]))
|
||
fprintf(of, "%c", val[i]);
|
||
else
|
||
fprintf(of, ".");
|
||
return -15;
|
||
} else if (sw & SWMASK ('M')) { // dump instruction mnemonic
|
||
inst = val[0];
|
||
if (!oplen[inst]) { // invalid opcode
|
||
fprintf(of, "%02X", inst);
|
||
return 0;
|
||
}
|
||
inst1 = inst & 0xF0;
|
||
fprintf (of, "%s", opcode[inst]); // mnemonic
|
||
if (strlen(opcode[inst]) == 3)
|
||
fprintf(of, " ");
|
||
if (inst1 == 0x20 || inst == 0x8D) { // rel operand
|
||
inst1 = val[1];
|
||
if (val[1] & 0x80)
|
||
inst1 |= 0xFF00;
|
||
fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK);
|
||
} else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand
|
||
if ((inst & 0x0F) < 0x0C)
|
||
fprintf(of, " #$%02X", val[1]);
|
||
else
|
||
fprintf(of, " #$%02X%02X", val[1], val[2]);
|
||
} else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand
|
||
fprintf(of, " %d,X", val[1]);
|
||
else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand
|
||
fprintf(of, " $%02X%02X", val[1], val[2]);
|
||
return (-(oplen[inst] - 1));
|
||
} else
|
||
return SCPE_ARG;
|
||
}
|
||
|
||
/* address output routine */
|
||
|
||
t_addr fprint_addr(FILE *of, DEVICE *dptr, t_addr addr)
|
||
{
|
||
fprintf(of, "%04X", addr);
|
||
return 0;
|
||
}
|
||
|
||
/* 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, uint32 *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] = (uint32) 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] = ((uint32) cptr[0] << 8) + (uint32) 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);
|
||
}
|
||
|
||
/* initialize optional interfaces */
|
||
|
||
void sim_special_init (void)
|
||
{
|
||
// *sim_vm_fprint_addr = &fprint_addr;
|
||
}
|
||
|