Notes For V3.7-0

1. New Features

1.1 3.7-0

1.1.1 SCP

- Added SET THROTTLE and SET NOTHROTTLE commands to regulate simulator
  execution rate and host resource utilization.
- Added idle support (based on work by Mark Pizzolato).
- Added -e to control error processing in nested DO commands (from
  Dave Bryan).

1.1.2 HP2100

- Added Double Integer instructions, 1000-F CPU, and Floating Point
  Processor (from Dave Bryan).
- Added 2114 and 2115 CPUs, 12607B and 12578A DMA controllers, and
  21xx binary loader protection (from Dave Bryan).

1.1.3 Interdata

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state.

1.1.4 PDP-11

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (WAIT instruction executed).
- Added TA11/TU60 cassette support.

1.1.5 PDP-8

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (keyboard poll loop or jump-to-self).
- Added TA8E/TU60 cassette support.

1.1.6 PDP-1

- Added support for 16-channel sequence break system.
- Added support for PDP-1D extended features and timesharing clock.
- Added support for Type 630 data communications subsystem.

1.1.6 PDP-4/7/9/15

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (keyboard poll loop or jump-to-self).

1.1.7 VAX, VAX780

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (more than 200 cycles at IPL's 0, 1, or 3 in kernel mode).

1.1.8 PDP-10

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (operating system dependent).
- Added CD20 (CD11) support.

2. Bugs Fixed

Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.
This commit is contained in:
Bob Supnik 2007-02-03 14:59:00 -08:00 committed by Mark Pizzolato
parent 15919a2dd7
commit 53d02f7fa7
161 changed files with 18604 additions and 6903 deletions

View file

@ -1,51 +0,0 @@
Notes For V3.6-0
The save/restore format has been updated to improve its reliability.
As a result, save files prior to release 3.0 are no longer supported.
The text documentation files are obsolete and are no longer included
with the distribution. Up-to-date PDF documentation files are
available on the SimH web site.
1. New Features
1.1 3.6-0
1.1.1 Most magnetic tapes
- Added support for limiting tape capacity to a particular size in MB
1.1.2 IBM 7090/7094
- First release
1.1.3 VAX-11/780
- Added FLOAD command, loads system file from console floppy disk
1.1.4 VAX, VAX-11/780, and PDP-11
- Added card reader support (from John Dundas)
1.1.5 PDP-11
- Added instruction history
1.2 3.6-1
1.2.1 PDP-11
- Added RF11 support
- Added multiple KL11/DL11 support
- Added upper-case only mode to TTI, TTO
1.2.2
- Added binary loader (courtesy of Dave Pitt)
2. Bugs Fixed
Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.

66
0readme_37.txt Normal file
View file

@ -0,0 +1,66 @@
Notes For V3.7-0
1. New Features
1.1 3.7-0
1.1.1 SCP
- Added SET THROTTLE and SET NOTHROTTLE commands to regulate simulator
execution rate and host resource utilization.
- Added idle support (based on work by Mark Pizzolato).
- Added -e to control error processing in nested DO commands (from
Dave Bryan).
1.1.2 HP2100
- Added Double Integer instructions, 1000-F CPU, and Floating Point
Processor (from Dave Bryan).
- Added 2114 and 2115 CPUs, 12607B and 12578A DMA controllers, and
21xx binary loader protection (from Dave Bryan).
1.1.3 Interdata
- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
state.
1.1.4 PDP-11
- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
state (WAIT instruction executed).
- Added TA11/TU60 cassette support.
1.1.5 PDP-8
- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
state (keyboard poll loop or jump-to-self).
- Added TA8E/TU60 cassette support.
1.1.6 PDP-1
- Added support for 16-channel sequence break system.
- Added support for PDP-1D extended features and timesharing clock.
- Added support for Type 630 data communications subsystem.
1.1.6 PDP-4/7/9/15
- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
state (keyboard poll loop or jump-to-self).
1.1.7 VAX, VAX780
- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
state (more than 200 cycles at IPL's 0, 1, or 3 in kernel mode).
1.1.8 PDP-10
- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
state (operating system dependent).
- Added CD20 (CD11) support.
2. Bugs Fixed
Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* altairz80_defs.h: MITS Altair simulator definitions
Copyright (c) 2002-2006, Peter Schorn
Copyright (c) 2002-2007, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -30,19 +30,19 @@
#define MAXMEMSIZE 65536 /* maximum memory size */
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
#define bootrom_size 256 /* size of boot rom */
#define BOOTROM_SIZE 256 /* size of boot rom */
#define MAXBANKS 8 /* max number of memory banks */
#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */
#define BANKMASK (MAXBANKS-1) /* bank mask */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define KB 1024 /* kilo byte */
#define defaultROMLow 0xff00 /* default for lowest address of ROM */
#define defaultROMHigh 0xffff /* default for highest address of ROM */
#define DEFAULT_ROM_LOW 0xff00 /* default for lowest address of ROM */
#define DEFAULT_ROM_HIGH 0xffff /* default for highest address of ROM */
#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */
#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */
#define unitNoOffset1 0x37 /* LD A,<unitno> */
#define unitNoOffset2 0xb4 /* LD a,80h | <unitno> */
#define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */
#define UNIT_NO_OFFSET_1 0x37 /* LD A,<unitno> */
#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | <unitno> */
#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */
#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
@ -59,17 +59,22 @@
#define UNIT_V_WARNROM (UNIT_V_UF+6) /* warn if ROM is written to */
#define UNIT_WARNROM (1 << UNIT_V_WARNROM)
#define AddressFormat "[%04xh]"
#define PCformat "\n" AddressFormat " "
#define message1(p1) \
sprintf(messageBuffer,PCformat p1,PCX); printMessage()
#define message2(p1,p2) \
sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage()
#define message3(p1,p2,p3) \
sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage()
#define message4(p1,p2,p3,p4) \
sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage()
#define message5(p1,p2,p3,p4,p5) \
sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage()
#define message6(p1,p2,p3,p4,p5,p6) \
sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage()
#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) || defined (__OpenBSD__) || \
defined (__FreeBSD__) || defined (__APPLE__))
#define ADDRESS_FORMAT "[%04xh]"
#define PC_FORMAT "\n" ADDRESS_FORMAT " "
#define MESSAGE_1(p1) \
sprintf(messageBuffer,PC_FORMAT p1,PCX); printMessage()
#define MESSAGE_2(p1,p2) \
sprintf(messageBuffer,PC_FORMAT p1,PCX,p2); printMessage()
#define MESSAGE_3(p1,p2,p3) \
sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3); printMessage()
#define MESSAGE_4(p1,p2,p3,p4) \
sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4); printMessage()
#define MESSAGE_5(p1,p2,p3,p4,p5) \
sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5); printMessage()
#define MESSAGE_6(p1,p2,p3,p4,p5,p6) \
sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5,p6); printMessage()
#define MESSAGE_7(p1,p2,p3,p4,p5,p6,p7) \
sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5,p6,p7); printMessage()

View file

@ -1,6 +1,6 @@
/* altairz80_dsk.c: MITS Altair 88-DISK Simulator
Copyright (c) 2002-2006, Peter Schorn
Copyright (c) 2002-2007, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -132,7 +132,6 @@ int32 dsk12(const int32 port, const int32 io, const int32 data);
static int32 dskseek(const UNIT *xptr);
static t_stat dsk_boot(int32 unitno, DEVICE *dptr);
static t_stat dsk_reset(DEVICE *dptr);
static t_stat dsk_svc(UNIT *uptr);
static void writebuf(void);
static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc);
static void resetDSKWarningFlags(void);
@ -142,11 +141,12 @@ static char* selectInOut(const int32 io);
extern int32 PCX;
extern int32 saved_PC;
extern FILE *sim_log;
extern void printMessage(void);
extern char messageBuffer[];
extern int32 install_bootrom(void);
extern UNIT cpu_unit;
extern void printMessage(void);
extern int32 install_bootrom(void);
/* global data on status */
static int32 current_disk = NUM_OF_DSK; /* currently selected drive (values are 0 .. NUM_OF_DSK)
@ -170,7 +170,7 @@ static int32 warnDSK12 = 0;
static int8 dskbuf[DSK_SECTSIZE]; /* data Buffer */
/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */
int32 bootrom[bootrom_size] = {
int32 bootrom[BOOTROM_SIZE] = {
0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */
0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* ff08-ff0f */
0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* ff10-ff17 */
@ -208,14 +208,14 @@ int32 bootrom[bootrom_size] = {
/* 88DSK Standard I/O Data Structures */
static UNIT dsk_unit[] = {
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }
};
static REG dsk_reg[] = {
@ -290,13 +290,6 @@ static char* selectInOut(const int32 io) {
}
/* service routines to handle simulator functions */
/* service routine - actually gets char & places in buffer */
static t_stat dsk_svc(UNIT *uptr) {
return SCPE_OK;
}
/* reset routine */
static t_stat dsk_reset(DEVICE *dptr) {
@ -317,16 +310,16 @@ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) {
printf("ALTAIR boot ROM installed.\n");
}
/* check whether we are really modifying an LD A,<> instruction */
if ((bootrom[unitNoOffset1 - 1] == LDAInstruction) && (bootrom[unitNoOffset2 - 1] == LDAInstruction)) {
bootrom[unitNoOffset1] = unitno & 0xff; /* LD A,<unitno> */
bootrom[unitNoOffset2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
if ((bootrom[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) && (bootrom[UNIT_NO_OFFSET_2 - 1] == LDA_INSTRUCTION)) {
bootrom[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A,<unitno> */
bootrom[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
}
else { /* Attempt to modify non LD A,<> instructions is refused. */
printf("Incorrect boot ROM offsets detected.\n");
return SCPE_IERR;
}
}
saved_PC = defaultROMLow;
saved_PC = DEFAULT_ROM_LOW;
return SCPE_OK;
}
@ -356,7 +349,7 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) {
if (current_disk >= NUM_OF_DSK) {
if (hasVerbose() && (warnDSK10 < warnLevelDSK)) {
warnDSK10++;
/*01*/ message1("Attempt of IN 0x08 on unattached disk - ignored.");
/*01*/ MESSAGE_1("Attempt of IN 0x08 on unattached disk - ignored.");
}
return 0xff; /* no drive selected - can do nothing */
}
@ -368,14 +361,14 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) {
writebuf();
}
if (trace_flag & TRACE_IN_OUT) {
message2("OUT 0x08: %x", data);
MESSAGE_2("OUT 0x08: %x", data);
}
current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */
current_disk_flags = (dsk_dev.units + current_disk) -> flags;
if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */
if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) {
warnAttached[current_disk]++;
/*02*/message2("Attempt to select unattached DSK%d - ignored.", current_disk);
/*02*/MESSAGE_2("Attempt to select unattached DSK%d - ignored.", current_disk);
}
current_disk = NUM_OF_DSK;
}
@ -395,7 +388,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
if (current_disk >= NUM_OF_DSK) {
if (hasVerbose() && (warnDSK11 < warnLevelDSK)) {
warnDSK11++;
/*03*/ message2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io));
/*03*/ MESSAGE_2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io));
}
return 0; /* no drive selected - can do nothing */
}
@ -405,10 +398,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
in9_count++;
if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) {
in9_message = TRUE;
message2("Looping on sector find %d.", current_disk);
MESSAGE_2("Looping on sector find %d.", current_disk);
}
if (trace_flag & TRACE_IN_OUT) {
message1("IN 0x09");
MESSAGE_1("IN 0x09");
}
if (dirty) {/* implies that current_disk < NUM_OF_DSK */
writebuf();
@ -430,12 +423,12 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
/* drive functions */
if (trace_flag & TRACE_IN_OUT) {
message2("OUT 0x09: %x", data);
MESSAGE_2("OUT 0x09: %x", data);
}
if (data & 0x01) { /* step head in */
if (trace_flag & TRACE_TRACK_STUCK) {
if (current_track[current_disk] == (tracks[current_disk] - 1)) {
message2("Unnecessary step in for disk %d", current_disk);
MESSAGE_2("Unnecessary step in for disk %d", current_disk);
}
}
current_track[current_disk]++;
@ -452,7 +445,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
if (data & 0x02) { /* step head out */
if (trace_flag & TRACE_TRACK_STUCK) {
if (current_track[current_disk] == 0) {
message2("Unnecessary step out for disk %d", current_disk);
MESSAGE_2("Unnecessary step out for disk %d", current_disk);
}
}
current_track[current_disk]--;
@ -506,7 +499,7 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) {
if (current_disk >= NUM_OF_DSK) {
if (hasVerbose() && (warnDSK12 < warnLevelDSK)) {
warnDSK12++;
/*04*/ message2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io));
/*04*/ MESSAGE_2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io));
}
return 0;
}
@ -518,7 +511,7 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) {
if (current_byte[current_disk] >= DSK_SECTSIZE) {
/* physically read the sector */
if (trace_flag & TRACE_READ_WRITE) {
message4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
MESSAGE_4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
}
for (i = 0; i < DSK_SECTSIZE; i++) {
dskbuf[i] = 0;
@ -552,20 +545,20 @@ static void writebuf(void) {
uptr = dsk_dev.units + current_disk;
if (((uptr -> flags) & UNIT_DSKWLK) == 0) { /* write enabled */
if (trace_flag & TRACE_READ_WRITE) {
message4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
MESSAGE_4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
}
if (dskseek(uptr)) {
message4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
MESSAGE_4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
}
rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
if (rtn != 1) {
message4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn);
MESSAGE_4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn);
}
}
else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[current_disk] < warnLevelDSK) ) {
/* write locked - print warning message if required */
warnLock[current_disk]++;
/*05*/ message2("Attempt to write to locked DSK%d - ignored.", current_disk);
/*05*/ MESSAGE_2("Attempt to write to locked DSK%d - ignored.", current_disk);
}
current_flag[current_disk] &= 0xfe; /* ENWD off */
current_byte[current_disk] = 0xff;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* altairz80_sys.c: MITS Altair system interface
Copyright (c) 2002-2006, Peter Schorn
Copyright (c) 2002-2007, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -39,6 +39,7 @@ extern DEVICE sio_dev;
extern DEVICE simh_device;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE net_dev;
extern int32 saved_PC;
int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw);
@ -65,7 +66,7 @@ char sim_name[] = "Altair 8800 (Z80)";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 4;
DEVICE *sim_devices[] = {
&cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL
&cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, &net_dev, NULL
};
char memoryAccessMessage[80];

View file

@ -1,6 +1,6 @@
/* altairz80_hdsk.c: simulated hard disk device to increase capacity
Copyright (c) 2002-2006, Peter Schorn
Copyright (c) 2002-2007, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -22,28 +22,39 @@
Except as contained in this notice, the name of Peter Schorn shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Peter Schorn.
Contains code from Howard M. Harte for defining and changing disk geometry.
*/
#include "altairz80_defs.h"
/* the following routines provided courtesy of Howard M. Harte */
t_stat set_geom (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_geom (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat set_format (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_format (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat hdsk_attach (UNIT *uptr, char *cptr);
#define UNIT_V_HDSKWLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_HDSKWLK (1 << UNIT_V_HDSKWLK)
#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE)
#define HDSK_SECTOR_SIZE 128 /* size of sector */
#define HDSK_SECTORS_PER_TRACK 32 /* sectors per track */
#define HDS_MAX_TRACKS 2048 /* number of tracks */
#define HDSK_TRACK_SIZE (HDSK_SECTOR_SIZE * HDSK_SECTORS_PER_TRACK)
#define HDSK_CAPACITY (HDSK_TRACK_SIZE * HDS_MAX_TRACKS)
#define HDSK_MAX_SECTOR_SIZE 1024 /* size of sector */
#define HDSK_SECTOR_SIZE u5 /* size of sector */
#define HDSK_SECTORS_PER_TRACK u4 /* sectors per track */
#define HDSK_MAX_TRACKS u3 /* number of tracks */
#define HDSK_FORMAT_TYPE u6 /* Disk Format Type */
#define HDSK_CAPACITY (2048*32*128) /* Default Altair HDSK Capacity */
#define HDSK_NUMBER 8 /* number of hard disks */
#define CPM_OK 0 /* indicates to CP/M everything ok */
#define CPM_ERROR 1 /* indicates to CP/M an error condition */
#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */
#define hdsk_none 0
#define hdsk_reset 1
#define hdsk_read 2
#define hdsk_write 3
#define hdsk_boot_address 0x5c00
#define HDSK_NONE 0
#define HDSK_RESET 1
#define HDSK_READ 2
#define HDSK_WRITE 3
#define HDSK_PARAM 4
#define HDSK_BOOT_ADDRESS 0x5c00
extern char messageBuffer[];
extern int32 PCX;
@ -57,9 +68,8 @@ extern void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Valu
extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
extern void protect(const int32 l, const int32 h);
extern uint8 GetBYTEWrapper(const uint32 Addr);
extern int32 bootrom[bootrom_size];
extern int32 bootrom[BOOTROM_SIZE];
static t_stat hdsk_svc(UNIT *uptr);
static t_stat hdsk_boot(int32 unitno, DEVICE *dptr);
static int32 hdsk_hasVerbose(void);
int32 hdsk_io(const int32 port, const int32 io, const int32 data);
@ -70,23 +80,50 @@ static int32 doSeek(void);
static int32 doRead(void);
static int32 doWrite(void);
static int32 hdskLastCommand = hdsk_none;
static int32 hdskLastCommand = HDSK_NONE;
static int32 hdskCommandPosition = 0;
static int32 paramcount = 0;
static int32 selectedDisk;
static int32 selectedSector;
static int32 selectedTrack;
static int32 selectedDMA;
static int32 hdskTrace;
typedef struct {
char name[16];
t_addr capac;
uint16 spt;
uint8 bsh;
uint8 blm;
uint8 exm;
uint16 dsm;
uint16 drm;
uint8 al0;
uint8 al1;
uint16 cks;
uint16 off;
uint8 psh;
uint8 phm;
} DPB;
static DPB dpb[] = {
/* NAME CAPAC SPT BSH BLM EXM DSM DRM AL0 AL1 CKS OFF PSH PHM */
{ "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF, 0xFF, 0x00, 0x8000, 0x0006, 0x00, 0x00 }, /* AZ80 HDSK */
{ "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E, 0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03 }, /* 128K FLASH */
{ "P112", 1474560, 72, 0x04, 0x0F, 0x00, 710, 0x00FE, 0xF0, 0x00, 0x0000, 0x0002, 0x02, 0x03 }, /* 1.44M P112 */
{ "SU720", 737280, 36, 0x04, 0x0F, 0x00, 354, 0x007E, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* 720K Super I/O */
{ "", 0 }
};
static UNIT hdsk_unit[] = {
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }
};
static REG hdsk_reg[] = {
@ -101,12 +138,14 @@ static REG hdsk_reg[] = {
};
static MTAB hdsk_mod[] = {
{ UNIT_HDSKWLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_HDSKWLK, UNIT_HDSKWLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "FORMAT", "FORMAT", &set_format, &show_format, NULL },
{ UNIT_HDSKWLK, 0, "WRTENB", "WRTENB", NULL },
{ UNIT_HDSKWLK, UNIT_HDSKWLK, "WRTLCK", "WRTLCK", NULL },
/* quiet, no warning messages */
{ UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL },
/* verbose, show warning messages */
{ UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL },
{ MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "GEOM", "GEOM", &set_geom, &show_geom, NULL },
{ 0 }
};
@ -114,16 +153,127 @@ DEVICE hdsk_dev = {
"HDSK", hdsk_unit, hdsk_reg, hdsk_mod,
8, 10, 31, 1, 8, 8,
NULL, NULL, NULL,
&hdsk_boot, NULL, NULL,
&hdsk_boot, &hdsk_attach, NULL,
NULL, 0, 0,
NULL, NULL, NULL
};
static t_stat hdsk_svc(UNIT *uptr) {
/* Attach routine */
t_stat hdsk_attach (UNIT *uptr, char *cptr) {
uint32 flen;
t_stat r;
int32 i;
r = attach_unit (uptr, cptr); /* attach unit */
if (r != SCPE_OK) return r; /* error? */
if ((flen = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */
if (uptr->flags & UNIT_RO) return SCPE_OK; /* if ro, done */
return SCPE_OK;
}
static const int32 hdskBoot[bootrom_size] = {
if(flen>0) {
uptr->capac = flen;
uptr->HDSK_FORMAT_TYPE = -1; /* Default to unknown format type */
for(i=0; dpb[i].spt != 0; i++) {
if(dpb[i].capac == uptr->capac) {
uptr->HDSK_FORMAT_TYPE = i;
break;
}
}
}
if(uptr->HDSK_FORMAT_TYPE == -1) {
uptr->HDSK_FORMAT_TYPE = 0;
uptr->capac = dpb[uptr->HDSK_FORMAT_TYPE].capac;
printf("HDSK: WARNING: Unsupported disk capacity, assuming HDSK type.\n");
uptr->flags |= UNIT_HDSKWLK;
printf("HDSK: WARNING: Forcing WRTLCK.\n");
if(uptr->capac != (uptr->HDSK_MAX_TRACKS * uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE)) {
printf("HDSK: WARNING: Geometry may be incorrect.\n");
}
}
uptr->HDSK_SECTOR_SIZE = (128 << dpb[uptr->HDSK_FORMAT_TYPE].psh);
uptr->HDSK_SECTORS_PER_TRACK = dpb[uptr->HDSK_FORMAT_TYPE].spt >> dpb[uptr->HDSK_FORMAT_TYPE].psh;
uptr->HDSK_MAX_TRACKS = uptr->capac / (uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE);
return SCPE_OK;
}
/* Set disk geometry routine */
t_stat set_geom (UNIT *uptr, int32 val, char *cptr, void *desc) {
DEVICE *dptr;
uint32 ncyl, nsect, ssize;
if (cptr == NULL) return SCPE_ARG;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
sscanf(cptr, "%d/%d/%d", &ncyl, &nsect, &ssize);
uptr->HDSK_MAX_TRACKS = ncyl;
uptr->HDSK_SECTORS_PER_TRACK = nsect;
uptr->HDSK_SECTOR_SIZE = ssize;
return SCPE_OK;
}
/* Show disk geometry routine */
t_stat show_geom (FILE *st, UNIT *uptr, int32 val, void *desc) {
DEVICE *dptr;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
fprintf (st, "T:%d/N:%d/S:%d", uptr->HDSK_MAX_TRACKS, uptr->HDSK_SECTORS_PER_TRACK, uptr->u5);
return SCPE_OK;
}
/* Set disk format routine */
t_stat set_format (UNIT *uptr, int32 val, char *cptr, void *desc) {
DEVICE *dptr;
char fmtname[16];
int32 i;
if (cptr == NULL) return SCPE_ARG;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
sscanf(cptr, "%s", fmtname);
for(i=0;dpb[i].spt != 0;i++) {
if(!strncmp(fmtname, dpb[i].name, strlen(fmtname))) {
uptr->HDSK_FORMAT_TYPE = i;
uptr->capac = dpb[i].capac; /* Set capacity */
/* Configure physical disk geometry */
uptr->HDSK_SECTOR_SIZE = (128 << dpb[uptr->HDSK_FORMAT_TYPE].psh);
uptr->HDSK_SECTORS_PER_TRACK = dpb[uptr->HDSK_FORMAT_TYPE].spt >> dpb[uptr->HDSK_FORMAT_TYPE].psh;
uptr->HDSK_MAX_TRACKS = uptr->capac / (uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE);
return SCPE_OK;
}
}
return SCPE_ARG;
}
/* Show disk format routine */
t_stat show_format (FILE *st, UNIT *uptr, int32 val, void *desc) {
DEVICE *dptr;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
fprintf (st, "%s", dpb[uptr->HDSK_FORMAT_TYPE].name);
return SCPE_OK;
}
static const int32 hdskBoot[BOOTROM_SIZE] = {
0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* 5c00-5c07 */
0xc2, 0x05, 0x5c, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* 5c08-5c0f */
0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* 5c10-5c17 */
@ -169,19 +319,19 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) {
printf("ALTAIR boot ROM installed.\n");
}
/* check whether we are really modifying an LD A,<> instruction */
if (bootrom[unitNoOffset1 - 1] == LDAInstruction) {
bootrom[unitNoOffset1] = (unitno + NUM_OF_DSK) & 0xff; /* LD A,<unitno> */
if (bootrom[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) {
bootrom[UNIT_NO_OFFSET_1] = (unitno + NUM_OF_DSK) & 0xff; /* LD A,<unitno> */
}
else { /* Attempt to modify non LD A,<> instructions is refused. */
printf("Incorrect boot ROM offset detected.\n");
return SCPE_IERR;
}
}
for (i = 0; i < bootrom_size; i++) {
PutBYTEBasic(i + hdsk_boot_address, 0, hdskBoot[i] & 0xff);
for (i = 0; i < BOOTROM_SIZE; i++) {
PutBYTEBasic(i + HDSK_BOOT_ADDRESS, 0, hdskBoot[i] & 0xff);
}
saved_PC = hdsk_boot_address;
protect(hdsk_boot_address, hdsk_boot_address + bootrom_size - 1);
saved_PC = HDSK_BOOT_ADDRESS;
protect(HDSK_BOOT_ADDRESS, HDSK_BOOT_ADDRESS + BOOTROM_SIZE - 1);
return SCPE_OK;
}
@ -200,14 +350,14 @@ static int32 hdsk_hasVerbose(void) {
1. Reset
ld b,32
ld a,hdsk_reset
ld a,HDSK_RESET
l: out (0fdh),a
dec b
jp nz,l
2. Read / write
; parameter block
cmd: db hdsk_read or hdsk_write
cmd: db HDSK_READ or HDSK_WRITE
hd: db 0 ; 0 .. 7, defines hard disk to be used
sector: db 0 ; 0 .. 31, defines sector
track: dw 0 ; 0 .. 2047, defines track
@ -223,43 +373,65 @@ static int32 hdsk_hasVerbose(void) {
jp nz,l ; again, if not done
in a,(0fdh) ; get result code
3. Retrieve Disk Parameters from controller (Howard M. Harte)
Reads a 19-byte parameter block from the disk controller.
This parameter block is in CP/M DPB format for the first 17 bytes,
and the last two bytes are the lsb/msb of the disk's physical
sector size.
; routine to execute
ld a,hdskParam ; hdskParam = 4
out (hdskPort),a ; Send 'get parameters' command, hdskPort = 0fdh
ld a,(diskno)
out (hdskPort),a ; Send selected HDSK number
ld b,17
1: in a,(hdskPort) ; Read 17-bytes of DPB
ld (hl), a
inc hl
djnz 1
in a,(hdskPort) ; Read LSB of disk's physical sector size.
ld (hsecsiz), a
in a,(hdskPort) ; Read MSB of disk's physical sector size.
ld (hsecsiz+1), a
*/
/* check the parameters and return TRUE iff parameters are correct or have been repaired */
static int32 checkParameters(void) {
UNIT *uptr = hdsk_dev.units + selectedDisk;
int32 currentFlag;
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
if (hdsk_hasVerbose()) {
message2("HDSK%d does not exist, will use HDSK0 instead.", selectedDisk);
MESSAGE_2("HDSK%d does not exist, will use HDSK0 instead.", selectedDisk);
}
selectedDisk = 0;
}
currentFlag = (hdsk_dev.units + selectedDisk) -> flags;
if ((currentFlag & UNIT_ATT) == 0) {
if (currentFlag & UNIT_HDSK_VERBOSE) {
message2("HDSK%d is not attached.", selectedDisk);
MESSAGE_2("HDSK%d is not attached.", selectedDisk);
}
return FALSE; /* cannot read or write */
}
if ((selectedSector < 0) || (selectedSector >= HDSK_SECTORS_PER_TRACK)) {
if ((selectedSector < 0) || (selectedSector >= uptr->HDSK_SECTORS_PER_TRACK)) {
if (currentFlag & UNIT_HDSK_VERBOSE) {
message4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.",
selectedDisk, selectedSector, HDSK_SECTORS_PER_TRACK);
MESSAGE_4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.",
selectedDisk, selectedSector, uptr->HDSK_SECTORS_PER_TRACK);
}
selectedSector = 0;
}
if ((selectedTrack < 0) || (selectedTrack >= HDS_MAX_TRACKS)) {
if ((selectedTrack < 0) || (selectedTrack >= uptr->HDSK_MAX_TRACKS)) {
if (currentFlag & UNIT_HDSK_VERBOSE) {
message4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.",
selectedDisk, selectedTrack, HDS_MAX_TRACKS);
MESSAGE_4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.",
selectedDisk, selectedTrack, uptr->HDSK_MAX_TRACKS);
}
selectedTrack = 0;
}
selectedDMA &= ADDRMASK;
if (hdskTrace) {
message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x",
(hdskLastCommand == hdsk_read) ? "Read" : "Write",
selectedDisk, selectedSector, selectedTrack, selectedDMA);
MESSAGE_7("%s HDSK%d Track=%04d Sector=%02d Len=%04d DMA=%04x\n",
(hdskLastCommand == HDSK_READ) ? "Read" : "Write",
selectedDisk, selectedTrack, selectedSector, uptr->HDSK_SECTOR_SIZE, selectedDMA);
}
return TRUE;
}
@ -267,9 +439,9 @@ static int32 checkParameters(void) {
static int32 doSeek(void) {
UNIT *uptr = hdsk_dev.units + selectedDisk;
if (fseek(uptr -> fileref,
HDSK_TRACK_SIZE * selectedTrack + HDSK_SECTOR_SIZE * selectedSector, SEEK_SET)) {
(uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE) * selectedTrack + (uptr->HDSK_SECTOR_SIZE * selectedSector), SEEK_SET)) {
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
message4("Could not access HDSK%d Sector=%02d Track=%04d.",
MESSAGE_4("Could not access HDSK%d Sector=%02d Track=%04d.",
selectedDisk, selectedSector, selectedTrack);
}
return CPM_ERROR;
@ -279,24 +451,26 @@ static int32 doSeek(void) {
}
}
uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE]; /* data buffer */
static int32 doRead(void) {
int32 i;
uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */
UNIT *uptr = hdsk_dev.units + selectedDisk;
if (doSeek()) {
return CPM_ERROR;
}
if (fread(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
for (i = 0; i < HDSK_SECTOR_SIZE; i++) {
if (fread(hdskbuf, uptr->HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) {
hdskbuf[i] = CPM_EMPTY;
}
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
message4("Could not read HDSK%d Sector=%02d Track=%04d.",
MESSAGE_4("Could not read HDSK%d Sector=%02d Track=%04d.",
selectedDisk, selectedSector, selectedTrack);
}
return CPM_OK; /* allows the creation of empty hard disks */
}
for (i = 0; i < HDSK_SECTOR_SIZE; i++) {
for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) {
PutBYTEWrapper(selectedDMA + i, hdskbuf[i]);
}
return CPM_OK;
@ -304,18 +478,18 @@ static int32 doRead(void) {
static int32 doWrite(void) {
int32 i;
uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */
UNIT *uptr = hdsk_dev.units + selectedDisk;
if (((uptr -> flags) & UNIT_HDSKWLK) == 0) { /* write enabled */
if (doSeek()) {
return CPM_ERROR;
}
for (i = 0; i < HDSK_SECTOR_SIZE; i++) {
for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) {
hdskbuf[i] = GetBYTEWrapper(selectedDMA + i);
}
if (fwrite(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
if (fwrite(hdskbuf, uptr->HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
message4("Could not write HDSK%d Sector=%02d Track=%04d.",
MESSAGE_4("Could not write HDSK%d Sector=%02d Track=%04d.",
selectedDisk, selectedSector, selectedTrack);
}
return CPM_ERROR;
@ -323,7 +497,7 @@ static int32 doWrite(void) {
}
else {
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
message4("Could not write to locked HDSK%d Sector=%02d Track=%04d.",
MESSAGE_4("Could not write to locked HDSK%d Sector=%02d Track=%04d.",
selectedDisk, selectedSector, selectedTrack);
}
return CPM_ERROR;
@ -332,15 +506,44 @@ static int32 doWrite(void) {
}
static int32 hdsk_in(const int32 port) {
UNIT *uptr = hdsk_dev.units + selectedDisk;
int32 result;
if ((hdskCommandPosition == 6) && ((hdskLastCommand == hdsk_read) || (hdskLastCommand == hdsk_write))) {
result = checkParameters() ? ((hdskLastCommand == hdsk_read) ? doRead() : doWrite()) : CPM_ERROR;
hdskLastCommand = hdsk_none;
if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) {
result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR;
hdskLastCommand = HDSK_NONE;
hdskCommandPosition = 0;
return result;
} else if (hdskLastCommand == HDSK_PARAM) {
DPB current = dpb[uptr->HDSK_FORMAT_TYPE];
uint8 params[17];
params[ 0] = current.spt & 0xff; params[ 1] = (current.spt >> 8) & 0xff;
params[ 2] = current.bsh;
params[ 3] = current.blm;
params[ 4] = current.exm;
params[ 5] = current.dsm & 0xff; params[ 6] = (current.dsm >> 8) & 0xff;
params[ 7] = current.drm & 0xff; params[ 8] = (current.drm >> 8) & 0xff;
params[ 9] = current.al0;
params[10] = current.al1;
params[11] = current.cks & 0xff; params[12] = (current.cks >> 8) & 0xff;
params[13] = current.off & 0xff; params[14] = (current.off >> 8) & 0xff;
params[15] = current.psh;
params[16] = current.phm;
if (++paramcount >= 19) {
hdskLastCommand = HDSK_NONE;
}
if (paramcount <= 17)
return params[paramcount - 1];
else if (paramcount == 18)
return (uptr->HDSK_SECTOR_SIZE & 0xff);
else if (paramcount == 19)
return (uptr->HDSK_SECTOR_SIZE >> 8);
else
MESSAGE_2("HDSK%d Get parameter error.", selectedDisk);
}
else if (hdsk_hasVerbose()) {
message4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).",
MESSAGE_4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).",
port, hdskLastCommand, hdskCommandPosition);
}
return CPM_OK;
@ -349,9 +552,14 @@ static int32 hdsk_in(const int32 port) {
static int32 hdsk_out(const int32 data) {
switch(hdskLastCommand) {
case hdsk_read:
case HDSK_PARAM:
paramcount = 0;
selectedDisk = data;
break;
case hdsk_write:
case HDSK_READ:
case HDSK_WRITE:
switch(hdskCommandPosition) {
case 0:
@ -385,7 +593,7 @@ static int32 hdsk_out(const int32 data) {
break;
default:
hdskLastCommand = hdsk_none;
hdskLastCommand = HDSK_NONE;
hdskCommandPosition = 0;
}
break;

292
AltairZ80/altairz80_net.c Normal file
View file

@ -0,0 +1,292 @@
/* altairz80_net.c: networking capability
Copyright (c) 2002-2007, Peter Schorn
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
PETER SCHORN 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 Peter Schorn shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Peter Schorn.
*/
#include "altairz80_defs.h"
#include "sim_sock.h"
#define UNIT_V_SERVER (UNIT_V_UF + 0) /* define machine as a server */
#define UNIT_SERVER (1 << UNIT_V_SERVER)
#define NET_INIT_POLL_SERVER 16000
#define NET_INIT_POLL_CLIENT 15000
/*#define DEBUG_NETWORK TRUE*/
static t_stat net_attach (UNIT *uptr, char *cptr);
static t_stat net_detach (UNIT *uptr);
static t_stat net_reset (DEVICE *dptr);
static t_stat net_svc (UNIT *uptr);
static t_stat set_net (UNIT *uptr, int32 value, char *cptr, void *desc);
int32 netStatus (const int32 port, const int32 io, const int32 data);
int32 netData (const int32 port, const int32 io, const int32 data);
#define MAX_CONNECTIONS 2 /* maximal number of server connections */
#define BUFFER_LENGTH 512 /* length of input and output buffer */
static struct {
int32 Z80StatusPort; /* Z80 status port associated with this ioSocket, read only */
int32 Z80DataPort; /* Z80 data port associated with this ioSocket, read only */
SOCKET masterSocket; /* server master socket, only defined at [1] */
SOCKET ioSocket; /* accepted server socket or connected client socket, 0 iff free */
char inputBuffer[BUFFER_LENGTH]; /* buffer for input characters read from ioSocket */
int32 inputPosRead; /* position of next character to read from buffer */
int32 inputPosWrite; /* position of next character to append to input buffer from ioSocket */
int32 inputSize; /* number of characters in circular input buffer */
char outputBuffer[BUFFER_LENGTH];/* buffer for output characters to be written to ioSocket */
int32 outputPosRead; /* position of next character to write to ioSocket */
int32 outputPosWrite; /* position of next character to append to output buffer */
int32 outputSize; /* number of characters in circular output buffer */
} serviceDescriptor[MAX_CONNECTIONS+1] = { /* serviceDescriptor[0] holds the information for a client */
/* stat dat ms ios in inPR inPW inS out outPR outPW outS */
{50, 51, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* client Z80 port 50 and 51 */
{40, 41, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* server Z80 port 40 and 41 */
{42, 43, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0} /* server Z80 port 42 and 43 */
};
static UNIT net_unit = {
UDATA (&net_svc, UNIT_ATTABLE, 0),
0, /* wait, set in attach */
0, /* u3 = Port */
0, /* u4 = IP of host */
0, /* u5, unused */
0, /* u6, unused */
};
static REG net_reg[] = {
{ DRDATA (POLL, net_unit.wait, 32) },
{ HRDATA (IPHOST, net_unit.u4, 32), REG_RO },
{ DRDATA (PORT, net_unit.u3, 32), REG_RO },
{ NULL }
};
static MTAB net_mod[] = {
{ UNIT_SERVER, 0, "CLIENT", "CLIENT", &set_net}, /* machine is a client */
{ UNIT_SERVER, UNIT_SERVER, "SERVER", "SERVER", &set_net}, /* machine is a server */
{ 0 }
};
DEVICE net_dev = {
"NET", &net_unit, net_reg, net_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &net_reset,
NULL, &net_attach, &net_detach,
NULL, 0, 0,
NULL, NULL, NULL
};
static t_stat set_net(UNIT *uptr, int32 value, char *cptr, void *desc) {
char temp[CBUFSIZE];
if ((net_unit.flags & UNIT_ATT) && ((net_unit.flags & UNIT_SERVER) != value)) {
strncpy(temp, net_unit.filename, CBUFSIZE); /* save name for later attach */
net_detach(&net_unit);
net_unit.flags ^= UNIT_SERVER; /* now switch from client to server and vice versa */
net_attach(uptr, temp);
return SCPE_OK;
}
return SCPE_OK;
}
static void serviceDescriptor_reset(const uint32 i) {
serviceDescriptor[i].inputPosRead = 0;
serviceDescriptor[i].inputPosWrite = 0;
serviceDescriptor[i].inputSize = 0;
serviceDescriptor[i].outputPosRead = 0;
serviceDescriptor[i].outputPosWrite = 0;
serviceDescriptor[i].outputSize = 0;
}
static t_stat net_reset(DEVICE *dptr) {
uint32 i;
if (net_unit.flags & UNIT_ATT)
sim_activate(&net_unit, net_unit.wait); /* start poll */
for (i = 0; i <= MAX_CONNECTIONS; i++)
serviceDescriptor_reset(i);
return SCPE_OK;
}
static t_stat net_attach(UNIT *uptr, char *cptr) {
uint32 i, ipa, ipp;
t_stat r = get_ipaddr(cptr, &ipa, &ipp);
if (r != SCPE_OK) return SCPE_ARG;
if (ipa == 0) ipa = 0x7F000001; /* localhost = 127.0.0.1 */
if (ipp == 0) ipp = 3000;
net_unit.u3 = ipp;
net_unit.u4 = ipa;
net_reset(&net_dev);
for (i = 0; i <= MAX_CONNECTIONS; i++) serviceDescriptor[i].ioSocket = 0;
if (net_unit.flags & UNIT_SERVER) {
net_unit.wait = NET_INIT_POLL_SERVER;
serviceDescriptor[1].masterSocket = sim_master_sock(ipp);
if (serviceDescriptor[1].masterSocket == INVALID_SOCKET) return SCPE_IOERR;
}
else {
net_unit.wait = NET_INIT_POLL_CLIENT;
serviceDescriptor[0].ioSocket = sim_connect_sock(ipa, ipp);
if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR;
}
net_unit.flags |= UNIT_ATT;
net_unit.filename = (char *) calloc(CBUFSIZE, sizeof (char)); /* alloc name buf */
if (net_unit.filename == NULL) return SCPE_MEM;
strncpy(net_unit.filename, cptr, CBUFSIZE); /* save name */
return SCPE_OK;
}
static t_stat net_detach(UNIT *uptr) {
uint32 i;
if (!(net_unit.flags & UNIT_ATT)) return SCPE_OK; /* if not attached simply return */
if (net_unit.flags & UNIT_SERVER)
sim_close_sock(serviceDescriptor[1].masterSocket, TRUE);
for (i = 0; i <= MAX_CONNECTIONS; i++)
if (serviceDescriptor[i].ioSocket)
sim_close_sock(serviceDescriptor[i].ioSocket, FALSE);
free(net_unit.filename); /* free port string */
net_unit.filename = NULL;
net_unit.flags &= ~UNIT_ATT; /* not attached */
return SCPE_OK;
}
/* cannot use sim_check_conn to check whether read will return an error */
static t_stat net_svc(UNIT *uptr) {
int32 i, j, k, r;
SOCKET s;
static char svcBuffer[BUFFER_LENGTH];
if (net_unit.flags & UNIT_ATT) {
sim_activate(&net_unit, net_unit.wait); /* continue poll */
if (net_unit.flags & UNIT_SERVER) {
for (i = 1; i <= MAX_CONNECTIONS; i++)
if (serviceDescriptor[i].ioSocket == 0) {
s = sim_accept_conn(serviceDescriptor[1].masterSocket, NULL);
if (s != INVALID_SOCKET) {
serviceDescriptor[i].ioSocket = s;
#ifdef DEBUG_NETWORK
printf("Accepted connection %i with socket %i.\n\r", i, s);
#endif
}
}
}
else if (serviceDescriptor[0].ioSocket == 0) {
serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.u4, net_unit.u3);
if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR;
printf("\rWaiting for server ... Type g<return> (possibly twice) when ready\n\r");
return SCPE_STOP;
}
for (i = 0; i <= MAX_CONNECTIONS; i++)
if (serviceDescriptor[i].ioSocket) {
if (serviceDescriptor[i].inputSize < BUFFER_LENGTH) { /* there is space left in inputBuffer */
r = sim_read_sock(serviceDescriptor[i].ioSocket, svcBuffer,
BUFFER_LENGTH - serviceDescriptor[i].inputSize);
if (r == -1) {
#ifdef DEBUG_NETWORK
printf("Drop connection %i with socket %i.\n\r", i, serviceDescriptor[i].ioSocket);
#endif
sim_close_sock(serviceDescriptor[i].ioSocket, FALSE);
serviceDescriptor[i].ioSocket = 0;
serviceDescriptor_reset(i);
continue;
}
else {
for (j = 0; j < r; j++) {
serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosWrite++] = svcBuffer[j];
if (serviceDescriptor[i].inputPosWrite == BUFFER_LENGTH)
serviceDescriptor[i].inputPosWrite = 0;
}
serviceDescriptor[i].inputSize += r;
}
}
if (serviceDescriptor[i].outputSize > 0) { /* there is something to write in outputBuffer */
k = serviceDescriptor[i].outputPosRead;
for (j = 0; j < serviceDescriptor[i].outputSize; j++) {
svcBuffer[j] = serviceDescriptor[i].outputBuffer[k++];
if (k == BUFFER_LENGTH) k = 0;
}
r = sim_write_sock(serviceDescriptor[i].ioSocket, svcBuffer, serviceDescriptor[i].outputSize);
if (r >= 0) {
serviceDescriptor[i].outputSize -= r;
serviceDescriptor[i].outputPosRead += r;
if (serviceDescriptor[i].outputPosRead >= BUFFER_LENGTH)
serviceDescriptor[i].outputPosRead -= BUFFER_LENGTH;
}
else printf("write %i\r\n", r);
}
}
}
return SCPE_OK;
}
int32 netStatus(const int32 port, const int32 io, const int32 data) {
uint32 i;
net_svc(&net_unit);
if (io == 0) { /* IN */
for (i = 0; i <= MAX_CONNECTIONS; i++)
if (serviceDescriptor[i].Z80StatusPort == port)
return (serviceDescriptor[i].inputSize > 0 ? 1 : 0) |
(serviceDescriptor[i].outputSize < BUFFER_LENGTH ? 2 : 0);
}
return 0;
}
int32 netData(const int32 port, const int32 io, const int32 data) {
uint32 i;
char result;
net_svc(&net_unit);
for (i = 0; i <= MAX_CONNECTIONS; i++)
if (serviceDescriptor[i].Z80DataPort == port)
if (io == 0) { /* IN */
if (serviceDescriptor[i].inputSize == 0) {
printf("re-read from %i\r\n", port);
result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead > 0 ?
serviceDescriptor[i].inputPosRead - 1 : BUFFER_LENGTH - 1];
}
else {
result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead++];
if (serviceDescriptor[i].inputPosRead == BUFFER_LENGTH)
serviceDescriptor[i].inputPosRead = 0;
serviceDescriptor[i].inputSize--;
}
#ifdef DEBUG_NETWORK
printf(" IN(%i)=%03xh (%c)\r\n", port, (result & 0xff),
(32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?');
#endif
return result;
}
else { /* OUT */
if (serviceDescriptor[i].outputSize == BUFFER_LENGTH) {
printf("over-write %i to %i\r\n", data, port);
serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite > 0 ?
serviceDescriptor[i].outputPosWrite - 1 : BUFFER_LENGTH - 1] = data;
}
else {
serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite++] = data;
if (serviceDescriptor[i].outputPosWrite== BUFFER_LENGTH)
serviceDescriptor[i].outputPosWrite = 0;
serviceDescriptor[i].outputSize++;
}
#ifdef DEBUG_NETWORK
printf("OUT(%i)=%03xh (%c)\r\n", port, data, (32 <= data) && (data <= 127) ? data : '?');
#endif
return 0;
}
return 0;
}

View file

@ -1,6 +1,6 @@
/* gri_stddev.c: GRI-909 standard devices
Copyright (c) 2001-2005, Robert M Supnik
Copyright (c) 2001-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -29,6 +29,7 @@
hsp S42-006 high speed punch
rtc real time clock
30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode
22-Nov-05 RMS Revised for new terminal processing routines
29-Dec-03 RMS Added support for console backpressure
25-Apr-03 RMS Revised for extended file support
@ -254,7 +255,7 @@ t_stat tto_svc (UNIT *uptr)
int32 c;
t_stat r;
c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags));
c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR);
if (c >= 0) {
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */

View file

@ -28,6 +28,7 @@
tty 316/516-33 teleprinter
clk/options 316/516-12 real time clocks/internal options
30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode
03-Apr-06 RMS Fixed bugs in punch state handling (from Theo Engel)
22-Nov-05 RMS Revised for new terminal processing routines
05-Feb-05 RMS Fixed bug in OCP '0001 (found by Philipp Hachtmann)
@ -688,7 +689,7 @@ t_stat tto_write (int32 c)
{
UNIT *tuptr = &tty_unit[TTO];
c = sim_tt_outcvt (c, TT_GET_MODE (tuptr->flags));
c = sim_tt_outcvt (c, TT_GET_MODE (tuptr->flags) | TTUF_KSR);
tuptr->pos = tuptr->pos + 1;
if (c >= 0) return sim_putchar_s (c);
else return SCPE_OK;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* hp2100_cpu.h: HP 2100 CPU definitions
Copyright (c) 2005, Robert M. Supnik
Copyright (c) 2005-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,72 +23,175 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
16-Dec-06 JDB Added UNIT_2115 and UNIT_2114
16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c
26-Sep-06 JDB Added CPU externs for microcode simulators
16-Aug-06 JDB Added UNIT_EMA for future RTE-4 EMA microcode
Added UNIT_VMA for future RTE-6 VMA and OS microcode
Added UNIT_1000_F for future F-Series support
09-Aug-06 JDB Added UNIT_DBI for double integer microcode
21-Jan-05 JDB Reorganized CPU option flags
14-Jan-05 RMS Cloned from hp2100_cpu.c
CPU models are broken down into type and series to facilitate option
validation. Bits 3:2 encode the type, and bits 1:0 encode the series
within the type.
CPU models are broken down into family, type, and series to facilitate option
validation. Bit 3 encodes the family, bit 2 encodes the type, and bits 1:0
encode the series within the type.
*/
#ifndef _HP2100_CPU_H_
#define _HP2100_CPU_H_ 0
/* CPU model definition flags */
#define CPU_V_SERIES 0
#define CPU_V_TYPE 2
#define CPU_V_FAMILY 3
#define TYPE_211X 0 /* 2114, 2115, 2116 */
#define TYPE_2100 1 /* 2100A, 2100S */
#define TYPE_21MX 2 /* 21MX-M, 21MX-E, 21MX-F */
#define TYPE_1000A 3 /* A600, A700, A900, A990 */
#define FAMILY_21XX (0 << CPU_V_FAMILY)
#define FAMILY_1000 (1 << CPU_V_FAMILY)
#define CPU_2116 (TYPE_211X << CPU_V_TYPE | 0)
#define CPU_2100 (TYPE_2100 << CPU_V_TYPE | 0)
#define CPU_21MX_M (TYPE_21MX << CPU_V_TYPE | 0)
#define CPU_21MX_E (TYPE_21MX << CPU_V_TYPE | 1)
#define TYPE_211X (0 << CPU_V_TYPE) /* 2114, 2115, 2116 */
#define TYPE_2100 (1 << CPU_V_TYPE) /* 2100A, 2100S */
#define TYPE_1000MEF (0 << CPU_V_TYPE) /* 1000-M, 1000-E, 1000-F */
#define TYPE_1000AL (1 << CPU_V_TYPE) /* 1000-L, A600, A700, A900, A990 */
#define SERIES_16 (0 << CPU_V_SERIES) /* 211X */
#define SERIES_15 (1 << CPU_V_SERIES) /* 211X */
#define SERIES_14 (2 << CPU_V_SERIES) /* 211X */
#define SERIES_00 (0 << CPU_V_SERIES) /* 2100 */
#define SERIES_M (0 << CPU_V_SERIES) /* 1000 */
#define SERIES_E (1 << CPU_V_SERIES) /* 1000 */
#define SERIES_F (2 << CPU_V_SERIES) /* 1000 */
/* CPU unit flags */
#define UNIT_M_CPU 017 /* CPU model mask [3:0] */
#define UNIT_M_TYPE 014 /* CPU type mask [3:2] */
#define UNIT_M_FAMILY 010 /* CPU family mask [3:3] */
#define UNIT_V_CPU (UNIT_V_UF + 0) /* CPU model bits 0-3 */
#define UNIT_M_CPU 017 /* CPU model mask */
#define UNIT_M_TYPE 014 /* CPU type mask */
#define UNIT_V_EAU (UNIT_V_UF + 4) /* EAU installed */
#define UNIT_V_FP (UNIT_V_UF + 5) /* FP installed */
#define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP installed */
#define UNIT_V_DMS (UNIT_V_UF + 7) /* DMS installed */
#define UNIT_V_FFP (UNIT_V_UF + 8) /* FFP installed */
#define UNIT_V_DBI (UNIT_V_UF + 9) /* DBI installed */
#define UNIT_V_EMA (UNIT_V_UF + 10) /* RTE-4 EMA installed */
#define UNIT_V_VMAOS (UNIT_V_UF + 11) /* RTE-6 VMA/OS installed */
/* Future microcode expansion; reuse flags bottom-up if needed */
#define UNIT_V_VIS (UNIT_V_UF + 12) /* VIS installed */
#define UNIT_V_DS (UNIT_V_UF + 13) /* DS installed */
#define UNIT_V_SIGNAL (UNIT_V_UF + 14) /* SIGNAL/1000 installed */
#define UNIT_CPU_MASK (UNIT_M_CPU << UNIT_V_CPU)
#define UNIT_2116 (CPU_2116 << UNIT_V_CPU)
#define UNIT_2100 (CPU_2100 << UNIT_V_CPU)
#define UNIT_21MX_M (CPU_21MX_M << UNIT_V_CPU)
#define UNIT_21MX_E (CPU_21MX_E << UNIT_V_CPU)
/* Unit models */
#define UNIT_MODEL_MASK (UNIT_M_CPU << UNIT_V_CPU)
#define UNIT_2116 ((FAMILY_21XX | TYPE_211X | SERIES_16) << UNIT_V_CPU)
#define UNIT_2115 ((FAMILY_21XX | TYPE_211X | SERIES_15) << UNIT_V_CPU)
#define UNIT_2114 ((FAMILY_21XX | TYPE_211X | SERIES_14) << UNIT_V_CPU)
#define UNIT_2100 ((FAMILY_21XX | TYPE_2100 | SERIES_00) << UNIT_V_CPU)
#define UNIT_1000_M ((FAMILY_1000 | TYPE_1000MEF | SERIES_M) << UNIT_V_CPU)
#define UNIT_1000_E ((FAMILY_1000 | TYPE_1000MEF | SERIES_E) << UNIT_V_CPU)
#define UNIT_1000_F ((FAMILY_1000 | TYPE_1000MEF | SERIES_F) << UNIT_V_CPU)
/* Unit types */
#define UNIT_TYPE_MASK (UNIT_M_TYPE << UNIT_V_CPU)
#define UNIT_TYPE_211X ((TYPE_211X << CPU_V_TYPE) << UNIT_V_CPU)
#define UNIT_TYPE_2100 ((TYPE_2100 << CPU_V_TYPE) << UNIT_V_CPU)
#define UNIT_TYPE_21MX ((TYPE_21MX << CPU_V_TYPE) << UNIT_V_CPU)
#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_CPU_MASK)
#define UNIT_TYPE_211X ((FAMILY_21XX | TYPE_211X) << UNIT_V_CPU)
#define UNIT_TYPE_2100 ((FAMILY_21XX | TYPE_2100) << UNIT_V_CPU)
#define UNIT_TYPE_1000 ((FAMILY_1000 | TYPE_1000MEF) << UNIT_V_CPU)
/* Unit families */
#define UNIT_FAMILY_MASK (UNIT_M_FAMILY << UNIT_V_CPU)
#define UNIT_FAMILY_21XX (FAMILY_21XX << UNIT_V_CPU)
#define UNIT_FAMILY_1000 (FAMILY_1000 << UNIT_V_CPU)
/* Unit accessors */
#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK)
#define UNIT_CPU_TYPE (cpu_unit.flags & UNIT_TYPE_MASK)
#define CPU_TYPE (UNIT_CPU_TYPE >> (UNIT_V_CPU + CPU_V_TYPE))
#define UNIT_CPU_FAMILY (cpu_unit.flags & UNIT_FAMILY_MASK)
#define CPU_MODEL_INDEX (UNIT_CPU_MODEL >> UNIT_V_CPU)
/* Unit features */
#define UNIT_EAU (1 << UNIT_V_EAU)
#define UNIT_FP (1 << UNIT_V_FP)
#define UNIT_IOP (1 << UNIT_V_IOP)
#define UNIT_DMS (1 << UNIT_V_DMS)
#define UNIT_FFP (1 << UNIT_V_FFP)
#define UNIT_DBI (1 << UNIT_V_DBI)
#define UNIT_EMA (1 << UNIT_V_EMA)
#define UNIT_VMAOS (1 << UNIT_V_VMAOS)
#define UNIT_VIS (1 << UNIT_V_VIS)
#define UNIT_DS (1 << UNIT_V_DS)
#define UNIT_SIGNAL (1 << UNIT_V_SIGNAL)
#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | UNIT_DMS | UNIT_FFP)
#define UNIT_EMA_VMA (UNIT_EMA | UNIT_VMAOS)
#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | \
UNIT_DMS | UNIT_FFP | UNIT_DBI | \
UNIT_EMA | UNIT_VMAOS | \
UNIT_VIS | UNIT_DS | UNIT_SIGNAL)
/* "Pseudo-option" flags used only for option testing; never set into UNIT structure. */
#define UNIT_V_PFAIL (UNIT_V_UF - 1) /* Power fail installed */
#define UNIT_V_DMA (UNIT_V_UF - 2) /* DMA installed */
#define UNIT_V_MP (UNIT_V_UF - 3) /* Memory protect installed */
#define UNIT_PFAIL (1 << UNIT_V_PFAIL)
#define UNIT_DMA (1 << UNIT_V_DMA)
#define UNIT_MP (1 << UNIT_V_MP)
#define UNIT_NONE 0 /* no options */
/* PC queue. */
#define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = err_PC
/* CPU registers */
extern uint16 ABREG[2]; /* A/B regs (use AR/BR) */
extern uint32 PC; /* P register */
extern uint32 SR; /* S register */
extern uint32 MR; /* M register */
extern uint32 TR; /* T register */
extern uint32 XR; /* X register */
extern uint32 YR; /* Y register */
extern uint32 E; /* E register */
extern uint32 O; /* O register */
/* CPU state */
extern uint32 err_PC;
extern uint32 dms_enb;
extern uint32 dms_ump;
extern uint32 dms_sr;
extern uint32 dms_vr;
extern uint32 mp_fence;
extern uint32 iop_sp;
extern uint32 ion_defer;
extern uint16 pcq[PCQ_SIZE];
extern uint32 pcq_p;
extern uint32 stop_inst;
extern UNIT cpu_unit;
/* CPU functions */
t_stat resolve (uint32 MA, uint32 *addr, uint32 irq);
uint8 ReadB (uint32 addr);
uint8 ReadBA (uint32 addr);
uint16 ReadW (uint32 addr);
uint16 ReadWA (uint32 addr);
uint32 ReadF (uint32 addr);
void WriteB (uint32 addr, uint32 dat);
void WriteBA (uint32 addr, uint32 dat);
void WriteW (uint32 addr, uint32 dat);

557
HP2100/hp2100_cpu0.c Normal file
View file

@ -0,0 +1,557 @@
/* hp2100_cpu0.c: HP 1000 unimplemented instruction set stubs
Copyright (c) 2006, J. David Bryan
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
THE AUTHOR 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 the author shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
CPU0 Unimplemented firmware option instructions
01-Dec-06 JDB Removed and implemented "cpu_sis".
26-Sep-06 JDB Created
This file contains template simulations for the firmware options that have
not yet been implemented. When a given firmware option is implemented, it
should be moved out of this file and into another (or its own, depending on
complexity).
Primary references:
- HP 1000 M/E/F-Series Computers Technical Reference Handbook
(5955-0282, Mar-1980)
- HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
(92851-90001, Mar-1981)
- Macro/1000 Reference Manual (92059-90001, Dec-1992)
Additional references are listed with the associated firmware
implementations, as are the HP option model numbers pertaining to the
applicable CPUs.
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include "hp2100_cpu1.h"
t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* RTE-4 EMA */
t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-6 VMA */
t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* RTE-6 OS */
t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed System */
t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction Set */
t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 Instructions */
/* RTE-IV Extended Memory Area Instructions
The RTE-IV operating system (HP product number 92067A) introduced the
Extended Memory Area (EMA) instructions. EMA provided a mappable data area
up to one megaword in size. These three instructions accelerated data
accesses to variables stored in EMA partitions. Support was limited to
E/F-Series machines; M-Series machines used software equivalents.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A 92067A 92067A
The routines are mapped to instruction codes as follows:
Instr. 1000-E/F Description
------ -------- ----------------------------------------------
.EMIO 105240 EMA I/O
MMAP 105241 Map physical to logical memory
[test] 105242 [self test]
.EMAP 105257 Resolve array element address
Notes:
1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a
given machine can run one or the other, but not both.
Additional references:
- RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983).
- RTE-IVB Technical Specifications (92068-90013, Jan-1980).
*/
static const OP_PAT op_ema[16] = {
OP_A, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_A /* --- --- --- .EMAP */
};
t_stat cpu_rte_ema (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;
if ((cpu_unit.flags & UNIT_EMA) == 0) /* EMA option installed? */
return stop_inst;
entry = IR & 017; /* mask to entry point */
if (op_ema[entry] != OP_N)
if (reason = cpu_ops (op_ema[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<3:0> */
default: /* others undefined */
reason = stop_inst;
}
return reason;
}
/* RTE-6/VM Virtual Memory Area Instructions
RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA)
instructions -- a superset of the RTE-IV EMA instructions. Different
microcode was supplied with the operating system that replaced the microcode
used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series
used software equivalents.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A 92084A 92084A
The routines are mapped to instruction codes as follows:
Instr. 1000-E/F Description
------ -------- ----------------------------------------------
.PMAP 105240 Map VMA page into map register
$LOC 105241 Load on call
[test] 105242 [self test]
.SWP 105243 [Swap A and B registers]
.STAS 105244 [STA B; LDA SP]
.LDAS 105245 [LDA SP]
.MYAD 105246 [NOP in microcode]
.UMPY 105247 [Unsigned multiply and add]
.IMAP 105250 Integer element resolve address and map
.IMAR 105251 Integer element resolve address
.JMAP 105252 Double integer element resolve address and map
.JMAR 105253 Double integer element resolve address
.LPXR 105254 Map pointer in P+1 plus offset in P+2
.LPX 105255 Map pointer in A/B plus offset in P+1
.LBPR 105256 Map pointer in P+1
.LBP 105257 Map pointer in A/B registers
Notes:
1. The opcodes 105243-247 are undocumented and do not appear to be used in
any HP software.
2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD -
multiply 2 signed integers." The microcode listing shows that this
instruction was deleted, and the opcode is now a NOP.
3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so
a given machine could run one or the other, but not both.
Additional references:
- RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3).
- RTE-6/VM Technical Specifications (92084-90015, Apr-1983).
- M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984).
*/
static const OP_PAT op_vma[16] = {
OP_N, OP_KKKAKK, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */
OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */
OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */
OP_FF, OP_F, OP_F, OP_N /* .LPXR .LPX .LBPR .LBP */
};
t_stat cpu_rte_vma (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;
if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */
return cpu_rte_ema (IR, intrq); /* try EMA */
entry = IR & 017; /* mask to entry point */
if (op_vma[entry] != OP_N)
if (reason = cpu_ops (op_vma[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<3:0> */
default: /* others undefined */
reason = stop_inst;
}
return reason;
}
/* RTE-6/VM Operating System Instructions
The OS instructions were added to acccelerate certain time-consuming
operations of the RTE-6/VM operating system, HP product number 92084A.
Microcode was available for the E- and F-Series; the M-Series used software
equivalents.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A 92084A 92084A
The routines are mapped to instruction codes as follows:
Instr. 1000-E/F Description
------ -------- ----------------------------------------------
$LIBR 105340 Enter privileged/reentrant library routine
$LIBX 105341 Exit privileged/reentrant library routine
.TICK 105342 TBG tick interrupt handler
.TNAM 105343 Find ID segment that matches name
.STIO 105344 Configure I/O instructions
.FNW 105345 Find word with user increment
.IRT 105346 Interrupt return processing
.LLS 105347 Linked list search
.SIP 105350 Skip if interrupt pending
.YLD 105351 .SIP completion return point
.CPM 105352 Compare words LT/EQ/GT
.ETEQ 105353 Set up EQT pointers in base page
.ENTN 105354 Transfer parameter addresses (utility)
[test] 105355 [self test]
.ENTC 105356 Transfer parameter addresses (priv/reent)
.DSPI 105357 Set display indicator
Opcodes 105354-105357 are "dual use" instructions that take different
actions, depending on whether they are executed from a trap cell during an
interrupt. When executed from a trap cell, they have these actions:
Instr. 1000-E/F Description
------ -------- ----------------------------------------------
[dma] 105354 DCPC channel interrupt processing
[dms] 105355 DMS/MP/PE interrupt processing
[dev] 105356 Standard device interrupt processing
[tbg] 105357 TBG interrupt processing
Notes:
1. The microcode differentiates between interrupt processing and normal
execution of the "dual use" instructions by testing the CPU flag.
Interrupt vectoring sets the flag; a normal instruction fetch clears it.
Under simulation, interrupt vectoring is indicated by the value of the
"iotrap" parameter.
2. The operand patterns for .ENTN and .ENTC normally would be coded as
"OP_A", as each takes a single address as a parameter. However, because
they might also be executed from a trap cell, we cannot assume that P+1
is an address, or we might cause a DM abort when trying to access
memory. Therefore, "OP_A" handling is done within each routine, once
the type of use is determined.
Additional references:
- RTE-6/VM O/S Microcode Source (92084-18831, revision 6).
- RTE-6/VM Technical Specifications (92084-90015, Apr-1983).
*/
static const OP_PAT op_os[16] = {
OP_A, OP_A, OP_N, OP_N, /* $LIBR $LIBX .TICK .TNAM */
OP_A, OP_K, OP_A, OP_KK, /* .STIO .FNW .IRT .LLS */
OP_N, OP_CC, OP_KK, OP_N, /* .SIP .YLD .CPM .ETEQ */
OP_N, OP_N, OP_N, OP_N /* .ENTN [test] .ENTC .DSPI */
};
t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;
if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */
return stop_inst;
entry = IR & 017; /* mask to entry point */
if (op_os[entry] != OP_N)
if (reason = cpu_ops (op_os[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<3:0> */
default: /* others undefined */
reason = stop_inst;
}
return reason;
}
/* Distributed System
Distributed System firmware was provided with the HP 91740A DS/1000 product
for use with the HP 12771A (12665A) Serial Interface and 12773A Modem
Interface system interconnection kits. Firmware permitted high-speed
transfers with minimum impact to the processor. The advent of the
"intelligent" 12794A and 12825A HDLC cards, the 12793A and 12834A Bisync
cards, and the 91750A DS-1000/IV software obviated the need for CPU firmware,
as essentially the firmware was moved onto the I/O cards.
Primary documentation for the DS instructions has not been located. However,
examination of the DS/1000 sources reveals that two instruction were used by
the DVA65 Serial Interface driver (91740-18071) and placed in the trap cells
of the communications interfaces. Presumably they handled interrupts from
the cards.
Implementation of the DS instructions will also require simulation of the
12665A Hardwired Serial Data Interface Card and the 12620A RTE Privileged
Interrupt Fence. These are required for DS/1000.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A 91740A 91740B 91740B
The routines are mapped to instruction codes as follows:
Instr. 1000-M 1000-E/F Description
------ ------ -------- ----------------------------------------------
105520 105300 "Open loop" (trap cell handler)
105521 105301 "Closed loop" (trap cell handler)
105522 105302 [unknown]
[test] 105524 105304 [self test]
Notes:
1. The E/F-Series opcodes were moved from 105340-357 to 105300-317 at
revision 1813.
2. DS/1000 ROM data are available from Bitsavers.
Additional references (documents unavailable):
- HP 91740A M-Series Distributed System (DS/1000) Firmware Installation
Manual (91740-90007).
- HP 91740B Distributed System (DS/1000) Firmware Installation Manual
(91740-90009).
*/
static const OP_PAT op_ds[16] = {
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */
};
t_stat cpu_ds (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;
if ((cpu_unit.flags & UNIT_DS) == 0) /* DS option installed? */
return stop_inst;
entry = IR & 017; /* mask to entry point */
if (op_ds[entry] != OP_N)
if (reason = cpu_ops (op_ds[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<3:0> */
default: /* others undefined */
reason = stop_inst;
}
return reason;
}
/* Vector Instruction Set
The VIS provides instructions that operate on one-dimensional arrays of
floating-point values. Both single- and double-precision operations are
supported.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A N/A 12824A
The routines are mapped to instruction codes as follows:
Single-Precision Double-Precision
Instr. Opcode Subcod Instr. Opcode Subcod Description
------ ------ ------ ------ ------ ------ -----------------------------
VADD 101460 000000 DVADD 105460 004002 Vector add
VSUB 101460 000020 DVSUB 105460 004022 Vector subtract
VMPY 101460 000040 DVMPY 105460 004042 Vector multiply
VDIV 101460 000060 DVDIV 105460 004062 Vector divide
VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add
VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract
VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply
VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide
VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot
VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value
VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum
VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm
VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product
VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value
VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value
VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value
VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value
VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move
VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap
.ERES 101474 -- -- -- -- Resolve array element address
.ESEG 101475 -- -- -- -- Load MSEG maps
.VSET 101476 -- -- -- -- Vector setup
[test] -- -- -- 105477 -- [self test]
Instructions use IR bit 11 to select single- or double-precision format. The
double-precision instruction names begin with "D" (e.g., DVADD vs. VADD).
Most VIS instructions are two words in length, with a sub-opcode immediately
following the primary opcode.
Notes:
1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or
double-precision arithmetic operation that is determined by the
sub-opcode value. The remainder of the dual-precision sub-opcode values
are "don't care," except for requiring a zero in bit 15.
2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are
detected by the VIS firmware and are indicated by a memory-protect
violation and setting the overflow flag. Under simulation,
malfunctions cannot occur.
3. VIS ROM data are available from Bitsavers.
Additional references:
- 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979).
*/
static const OP_PAT op_vis[16] = {
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */
};
t_stat cpu_vis (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;
if ((cpu_unit.flags & UNIT_VIS) == 0) /* VIS option installed? */
return stop_inst;
entry = IR & 017; /* mask to entry point */
if (op_vis[entry] != OP_N)
if (reason = cpu_ops (op_vis[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<3:0> */
default: /* others undefined */
reason = stop_inst;
}
return reason;
}
/* SIGNAL/1000 Instructions
The SIGNAL/1000 instructions provide fast Fourier transforms and complex
arithmetic. They utilize the F-Series floating-point processor and the
Vector Instruction Set.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A N/A 92835A
The routines are mapped to instruction codes as follows:
Instr. 1000-F Description
------ ------ ----------------------------------------------
BITRV 105600 Bit reversal
BTRFY 105601 Butterfly algorithm
UNSCR 105602 Unscramble for phasor MPY
PRSCR 105603 Unscramble for phasor MPY
BITR1 105604 Swap two elements in array (alternate format)
BTRF1 105605 Butterfly algorithm (alternate format)
.CADD 105606 Complex number addition
.CSUB 105607 Complex number subtraction
.CMPY 105610 Complex number multiplication
.CDIV 105611 Complex number division
CONJG 105612 Complex conjugate
..CCM 105613 Complex complement
AIMAG 105614 Return imaginary part
CMPLX 105615 Form complex number
[nop] 105616 [no operation]
[test] 105617 [self test]
Notes:
1. SIGNAL/1000 ROM data are available from Bitsavers.
Additional references (documents unavailable):
- HP Signal/1000 User Reference and Installation Manual (92835-90002).
*/
static const OP_PAT op_signal[16] = {
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */
OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */
};
t_stat cpu_signal (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;
if ((cpu_unit.flags & UNIT_SIGNAL) == 0) /* SIGNAL option installed? */
return stop_inst;
entry = IR & 017; /* mask to entry point */
if (op_signal[entry] != OP_N)
if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<3:0> */
default: /* others undefined */
reason = stop_inst;
}
return reason;
}

File diff suppressed because it is too large Load diff

215
HP2100/hp2100_cpu1.h Normal file
View file

@ -0,0 +1,215 @@
/* hp2100_cpu1.h: HP 2100/1000 firmware dispatcher definitions
Copyright (c) 2006, J. David Bryan
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
THE AUTHOR 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 the author shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
16-Oct-06 JDB Generalized operands for F-Series FP types
26-Sep-06 JDB Split from hp2100_cpu1.c
*/
#ifndef _HP2100_CPU1_H_
#define _HP2100_CPU1_H_
/* Operand processing encoding. */
/* Base operand types. Note that all address encodings must be grouped together
after OP_ADR. */
#define OP_NUL 0 /* no operand */
#define OP_IAR 1 /* 1-word int in A reg */
#define OP_JAB 2 /* 2-word int in A/B regs */
#define OP_FAB 3 /* 2-word FP const in A/B regs */
#define OP_CON 4 /* inline 1-word constant */
#define OP_VAR 5 /* inline 1-word variable */
#define OP_ADR 6 /* inline address */
#define OP_ADK 7 /* addr of 1-word int const */
#define OP_ADD 8 /* addr of 2-word int const */
#define OP_ADF 9 /* addr of 2-word FP const */
#define OP_ADX 10 /* addr of 3-word FP const */
#define OP_ADT 11 /* addr of 4-word FP const */
#define OP_ADE 12 /* addr of 5-word FP const */
#define OP_N_FLAGS 4 /* number of bits needed for flags */
#define OP_M_FLAGS ((1 << OP_N_FLAGS) - 1) /* mask for flag bits */
#define OP_N_F (8 * sizeof (uint32) / OP_N_FLAGS) /* max number of op fields */
#define OP_V_F1 (0 * OP_N_FLAGS) /* 1st operand field */
#define OP_V_F2 (1 * OP_N_FLAGS) /* 2nd operand field */
#define OP_V_F3 (2 * OP_N_FLAGS) /* 3rd operand field */
#define OP_V_F4 (3 * OP_N_FLAGS) /* 4th operand field */
#define OP_V_F5 (4 * OP_N_FLAGS) /* 5th operand field */
#define OP_V_F6 (5 * OP_N_FLAGS) /* 6th operand field */
#define OP_V_F7 (6 * OP_N_FLAGS) /* 7th operand field */
#define OP_V_F8 (7 * OP_N_FLAGS) /* 8th operand field */
/* Operand processing patterns. */
#define OP_N (OP_NUL << OP_V_F1)
#define OP_I (OP_IAR << OP_V_F1)
#define OP_J (OP_JAB << OP_V_F1)
#define OP_R (OP_FAB << OP_V_F1)
#define OP_C (OP_CON << OP_V_F1)
#define OP_V (OP_VAR << OP_V_F1)
#define OP_A (OP_ADR << OP_V_F1)
#define OP_K (OP_ADK << OP_V_F1)
#define OP_D (OP_ADD << OP_V_F1)
#define OP_F (OP_ADF << OP_V_F1)
#define OP_X (OP_ADX << OP_V_F1)
#define OP_T (OP_ADT << OP_V_F1)
#define OP_E (OP_ADE << OP_V_F1)
#define OP_IA ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2))
#define OP_JA ((OP_JAB << OP_V_F1) | (OP_ADR << OP_V_F2))
#define OP_JD ((OP_JAB << OP_V_F1) | (OP_ADD << OP_V_F2))
#define OP_RC ((OP_FAB << OP_V_F1) | (OP_CON << OP_V_F2))
#define OP_RK ((OP_FAB << OP_V_F1) | (OP_ADK << OP_V_F2))
#define OP_RF ((OP_FAB << OP_V_F1) | (OP_ADF << OP_V_F2))
#define OP_CC ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2))
#define OP_CV ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2))
#define OP_AC ((OP_ADR << OP_V_F1) | (OP_CON << OP_V_F2))
#define OP_AA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2))
#define OP_AK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2))
#define OP_AX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2))
#define OP_AT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2))
#define OP_KV ((OP_ADK << OP_V_F1) | (OP_VAR << OP_V_F2))
#define OP_KA ((OP_ADK << OP_V_F1) | (OP_ADR << OP_V_F2))
#define OP_KK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2))
#define OP_FF ((OP_ADF << OP_V_F1) | (OP_ADF << OP_V_F2))
#define OP_IIF ((OP_IAR << OP_V_F1) | (OP_IAR << OP_V_F2) | \
(OP_ADF << OP_V_F3))
#define OP_IAT ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
(OP_ADT << OP_V_F3))
#define OP_CVA ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2) | \
(OP_ADR << OP_V_F3))
#define OP_AAF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
(OP_ADF << OP_V_F3))
#define OP_AAX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
(OP_ADX << OP_V_F3))
#define OP_AAT ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
(OP_ADT << OP_V_F3))
#define OP_AKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \
(OP_ADK << OP_V_F3))
#define OP_AXX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2) | \
(OP_ADX << OP_V_F3))
#define OP_ATT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2) | \
(OP_ADT << OP_V_F3))
#define OP_AEE ((OP_ADR << OP_V_F1) | (OP_ADE << OP_V_F2) | \
(OP_ADE << OP_V_F3))
#define OP_AAXX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
(OP_ADX << OP_V_F3) | (OP_ADX << OP_V_F4))
#define OP_KKKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \
(OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4))
#define OP_CATAKK ((OP_CON << OP_V_F1) | (OP_ADR << OP_V_F2) | \
(OP_ADT << OP_V_F3) | (OP_ADR << OP_V_F4) | \
(OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6))
#define OP_KKKAKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \
(OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \
(OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6))
#define OP_CCACACCA ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \
(OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \
(OP_ADR << OP_V_F5) | (OP_CON << OP_V_F6) | \
(OP_CON << OP_V_F7) | (OP_ADR << OP_V_F8))
/* Operand precisions (compatible with F-Series FPP):
- S = 1-word integer
- D = 2-word integer
- F = 2-word single-precision floating-point
- X = 3-word extended-precision floating-point
- T = 4-word double-precision floating-point
- E = 5-word expanded-exponent floating-point
- A = null operand (operand is in FPP accumulator)
5-word floating-point numbers are supported by the F-Series Floating-Point
Processor hardware, but the instruction codes are not documented.
Note that ordering is important, as we depend on the "fp" type codes to
reflect the number of words needed.
*/
typedef enum { in_s, in_d, fp_f, fp_x, fp_t, fp_e, fp_a } OPSIZE;
/* Conversion from operand size to word count. */
#define TO_COUNT(s) ((s == fp_a) ? 0 : s + (s < fp_f))
/* HP in-memory representation of a packed floating-point number.
Actual value will use two, three, four, or five words, as needed. */
typedef uint16 FPK[5];
/* Operand processing types.
NOTE: Microsoft VC++ 6.0 does not support the C99 standard, so we cannot
initialize unions by arbitrary variant ("designated initializers").
Therefore, we follow the C90 form of initializing via the first named
variant. The FPK variant must appear first in the OP structure, as we define
a number of FPK constants in other modules.
*/
typedef union { /* general operand */
FPK fpk; /* floating-point value */
uint16 word; /* 16-bit integer */
uint32 dword; /* 32-bit integer */
} OP;
typedef OP OPS[OP_N_F]; /* operand array */
typedef uint32 OP_PAT; /* operand pattern */
/* Microcode dispatcher functions. */
t_stat cpu_eau (uint32 IR, uint32 intrq); /* EAU group simulator */
t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); /* UIG group 0 dispatcher */
t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); /* UIG group 1 dispatcher */
/* Microcode helper functions. */
OP ReadOp (uint32 va, OPSIZE precision); /* generalized operand read */
void WriteOp (uint32 va, OP operand, OPSIZE precision); /* generalized operand write */
t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */
#endif

1125
HP2100/hp2100_cpu2.c Normal file

File diff suppressed because it is too large Load diff

819
HP2100/hp2100_cpu3.c Normal file
View file

@ -0,0 +1,819 @@
/* hp2100_cpu3.c: HP 2100/1000 FFP/DBI instructions
Copyright (c) 2005-2006, J. David Bryan
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
THE AUTHOR 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 the author shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
CPU3 Fast FORTRAN and Double Integer instructions
16-Oct-06 JDB Calls FPP for extended-precision math
12-Oct-06 JDB Altered DBLE, DDINT for F-Series FFP compatibility
26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions
09-Aug-06 JDB Added double-integer instruction set
18-Feb-05 JDB Add 2100/21MX Fast FORTRAN Processor instructions
Primary references:
- HP 1000 M/E/F-Series Computers Technical Reference Handbook
(5955-0282, Mar-1980)
- HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
(92851-90001, Mar-1981)
- Macro/1000 Reference Manual (92059-90001, Dec-1992)
Additional references are listed with the associated firmware
implementations, as are the HP option model numbers pertaining to the
applicable CPUs.
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include "hp2100_cpu1.h"
#if defined (HAVE_INT64) /* int64 support available */
#include "hp2100_fp1.h"
#else /* int64 support unavailable */
#include "hp2100_fp.h"
#endif /* end of int64 support */
t_stat cpu_ffp (uint32 IR, uint32 intrq); /* Fast FORTRAN Processor */
t_stat cpu_dbi (uint32 IR, uint32 intrq); /* Double-Integer instructions */
/* Fast FORTRAN Processor.
The Fast FORTRAN Processor (FFP) is a set of FORTRAN language accelerators
and extended-precision (three-word) floating point routines. Although the
FFP is an option for the 2100 and later CPUs, each implements the FFP in a
slightly different form.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A 12907A 12977B 13306B std
The instruction codes are mapped to routines as follows:
Instr. 2100 1000-M 1000-E 1000-F Instr. 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------ ------ ------ ------
105200 -- [nop] [nop] [test] 105220 .XFER .XFER .XFER .XFER
105201 DBLE DBLE DBLE DBLE 105221 .GOTO .GOTO .GOTO .GOTO
105202 SNGL SNGL SNGL SNGL 105222 ..MAP ..MAP ..MAP ..MAP
105203 .XMPY .XMPY .XMPY .DNG 105223 .ENTR .ENTR .ENTR .ENTR
105204 .XDIV .XDIV .XDIV .DCO 105224 .ENTP .ENTP .ENTP .ENTP
105205 .DFER .DFER .DFER .DFER 105225 -- .PWR2 .PWR2 .PWR2
105206 -- .XPAK .XPAK .XPAK 105226 -- .FLUN .FLUN .FLUN
105207 -- XADD XADD .BLE 105227 $SETP $SETP $SETP $SETP
105210 -- XSUB XSUB .DIN 105230 -- .PACK .PACK .PACK
105211 -- XMPY XMPY .DDE 105231 -- -- .CFER .CFER
105212 -- XDIV XDIV .DIS 105232 -- -- -- ..FCM
105213 .XADD .XADD .XADD .DDS 105233 -- -- -- ..TCM
105214 .XSUB .XSUB .XSUB .NGL 105234 -- -- -- --
105215 -- .XCOM .XCOM .XCOM 105235 -- -- -- --
105216 -- ..DCM ..DCM ..DCM 105236 -- -- -- --
105217 -- DDINT DDINT DDINT 105237 -- -- -- --
The F-Series maps different instructions to several of the standard FFP
opcodes. We first look for these and dispatch them appropriately before
falling into the handler for the common instructions.
The math functions use the F-Series FPP for implementation. The FPP requires
that the host compiler support 64-bit integers. Therefore, if 64-bit
integers are not available, the math instructions of the FFP are disabled.
We allow this partial implementation as an aid in running systems generated
for the FFP. Most system programs did not use the math instructions, but
almost all use .ENTR. Supporting the latter even on systems that do not
support the former still allows such systems to boot.
Notes:
1. The "$SETP" instruction is sometimes listed as ".SETP" in the
documentation.
2. Extended-precision arithmetic routines (e.g., .XMPY) exist on the
1000-F, but they are assigned instruction codes in the single-precision
floating-point module range. They are replaced by several double
integer instructions, which we dispatch to the double integer handler.
3. The software implementation of ..MAP supports 1-, 2-, or 3-dimensional
arrays, designated by setting A = -1, 0, and +1, respectively. The
firmware implementation supports only 2- and 3-dimensional access.
4. The documentation for ..MAP for the 2100 FFP shows A = 0 or -1 for two
or three dimensions, respectively, but the 1000 FFP shows A = 0 or +1.
The firmware actually only checks the LSB of A.
5. The .DFER and .XFER implementations for the 2100 FFP return X+4 and Y+4
in the A and B registers, whereas the 1000 FFP returns X+3 and Y+3.
6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the
1000 implementation returns to P+1.
7. The firmware implementations of DBLE, .BLE, and DDINT clear the overflow
flag. The software implementations do not change overflow.
8. The M/E-Series FFP arithmetic instructions (.XADD, etc.) return negative
infinity on negative overflow and positive infinity on positive
overflow. The equivalent F-Series instructions return positive infinity
on both.
Additional references:
- DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981)
- Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974)
*/
static const OP_PAT op_ffp_f[32] = { /* patterns for F-Series only */
OP_N, OP_AAF, OP_AX, OP_N, /* [tst] DBLE SNGL .DNG */
OP_N, OP_AA, OP_A, OP_AAF, /* .DCO .DFER .XPAK .BLE */
OP_N, OP_N, OP_N, OP_N, /* .DIN .DDE .DIS .DDS */
OP_AT, OP_A, OP_A, OP_AAX, /* .NGL .XCOM ..DCM DDINT */
OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */
OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */
OP_RC, OP_AA, OP_R, OP_A, /* .PACK .CFER ..FCM ..TCM */
OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */
};
static const OP_PAT op_ffp_e[32] = { /* patterns for 2100/M/E-Series */
OP_N, OP_AAF, OP_AX, OP_AXX, /* [nop] DBLE SNGL .XMPY */
OP_AXX, OP_AA, OP_A, OP_AAXX, /* .XDIV .DFER .XPAK XADD */
OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX, /* XSUB XMPY XDIV .XADD */
OP_AXX, OP_A, OP_A, OP_AAX, /* .XSUB .XCOM ..DCM DDINT */
OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */
OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */
OP_RC, OP_AA, OP_N, OP_N, /* .PACK .CFER --- --- */
OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */
};
t_stat cpu_ffp (uint32 IR, uint32 intrq)
{
OP fpop;
OPS op, op2;
uint32 entry;
uint32 j, sa, sb, sc, da, dc, ra, MA;
int32 expon;
t_stat reason = SCPE_OK;
#if defined (HAVE_INT64) /* int64 support available */
int32 i;
#endif /* end of int64 support */
if ((cpu_unit.flags & UNIT_FFP) == 0) /* FFP option installed? */
return stop_inst;
entry = IR & 037; /* mask to entry point */
if (UNIT_CPU_MODEL != UNIT_1000_F) { /* 2100/M/E-Series? */
if (op_ffp_e[entry] != OP_N)
if (reason = cpu_ops (op_ffp_e[entry], op, intrq)) /* get instruction operands */
return reason;
}
#if defined (HAVE_INT64) /* int64 support available */
else { /* F-Series */
if (op_ffp_f[entry] != OP_N)
if (reason = cpu_ops (op_ffp_f[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<4:0> */
case 000: /* [tst] 105200 (OP_N) */
XR = 4; /* firmware revision */
SR = 0102077; /* test passed code */
AR = 0; /* test clears A/B */
BR = 0;
PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DBI */
return reason;
case 003: /* .DNG 105203 (OP_N) */
return cpu_dbi (0105323, intrq); /* remap to double int handler */
case 004: /* .DCO 105204 (OP_N) */
return cpu_dbi (0105324, intrq); /* remap to double int handler */
case 007: /* .BLE 105207 (OP_AAF) */
O = fp_cvt (&op[2], fp_f, fp_t); /* convert value and clear overflow */
WriteOp (op[1].word, op[2], fp_t); /* write double-precision value */
return reason;
case 010: /* .DIN 105210 (OP_N) */
return cpu_dbi (0105330, intrq); /* remap to double int handler */
case 011: /* .DDE 105211 (OP_N) */
return cpu_dbi (0105331, intrq); /* remap to double int handler */
case 012: /* .DIS 105212 (OP_N) */
return cpu_dbi (0105332, intrq); /* remap to double int handler */
case 013: /* .DDS 105213 (OP_N) */
return cpu_dbi (0105333, intrq); /* remap to double int handler */
case 014: /* .NGL 105214 (OP_AT) */
O = fp_cvt (&op[1], fp_t, fp_f); /* convert value */
AR = op[1].fpk[0]; /* move MSB to A */
BR = op[1].fpk[1]; /* move LSB to B */
return reason;
case 032: /* ..FCM 105232 (OP_R) */
O = fp_pcom (&op[0], fp_f); /* complement value */
AR = op[0].fpk[0]; /* return result */
BR = op[0].fpk[1]; /* to A/B registers */
return reason;
case 033: /* ..TCM 105233 (OP_A) */
fpop = ReadOp (op[0].word, fp_t); /* read 4-word value */
O = fp_pcom (&fpop, fp_t); /* complement it */
WriteOp (op[0].word, fpop, fp_t); /* write 4-word value */
return reason;
} /* fall thru if not special to F */
}
#endif /* end of int64 support */
switch (entry) { /* decode IR<4:0> */
/* FFP module 1 */
case 000: /* [nop] 105200 (OP_N) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 M/E-series */
return stop_inst; /* trap if not */
break;
#if defined (HAVE_INT64) /* int64 support available */
case 001: /* DBLE 105201 (OP_AAF) */
O = fp_cvt (&op[2], fp_f, fp_x); /* convert value and clear overflow */
WriteOp (op[1].word, op[2], fp_x); /* write extended-precision value */
break;
case 002: /* SNGL 105202 (OP_AX) */
O = fp_cvt (&op[1], fp_x, fp_f); /* convert value */
AR = op[1].fpk[0]; /* move MSB to A */
BR = op[1].fpk[1]; /* move LSB to B */
break;
case 003: /* .XMPY 105203 (OP_AXX) */
i = 0; /* params start at op[0] */
goto XMPY; /* process as XMPY */
case 004: /* .XDIV 105204 (OP_AXX) */
i = 0; /* params start at op[0] */
goto XDIV; /* process as XDIV */
#endif /* end of int64 support */
case 005: /* .DFER 105205 (OP_AA) */
BR = op[0].word; /* get destination address */
AR = op[1].word; /* get source address */
goto XFER; /* do transfer */
#if defined (HAVE_INT64) /* int64 support available */
case 006: /* .XPAK 105206 (OP_A) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
if (intrq) { /* interrupt pending? */
PC = err_PC; /* restart instruction */
break;
}
fpop = ReadOp (op[0].word, fp_x); /* read unpacked */
O = fp_nrpack (&fpop, fpop, (int16) AR, fp_x); /* nrm/rnd/pack mantissa, exponent */
WriteOp (op[0].word, fpop, fp_x); /* write result */
break;
case 007: /* XADD 105207 (OP_AAXX) */
i = 1; /* params start at op[1] */
XADD: /* enter here from .XADD */
if (intrq) { /* interrupt pending? */
PC = err_PC; /* restart instruction */
break;
}
O = fp_exec (001, &fpop, op[i + 1], op[i + 2]); /* three-word add */
WriteOp (op[i].word, fpop, fp_x); /* write sum */
break;
case 010: /* XSUB 105210 (OP_AAXX) */
i = 1; /* params start at op[1] */
XSUB: /* enter here from .XSUB */
if (intrq) { /* interrupt pending? */
PC = err_PC; /* restart instruction */
break;
}
O = fp_exec (021, &fpop, op[i + 1], op[i + 2]); /* three-word subtract */
WriteOp (op[i].word, fpop, fp_x); /* write difference */
break;
case 011: /* XMPY 105211 (OP_AAXX) */
i = 1; /* params start at op[1] */
XMPY: /* enter here from .XMPY */
if (intrq) { /* interrupt pending? */
PC = err_PC; /* restart instruction */
break;
}
O = fp_exec (041, &fpop, op[i + 1], op[i + 2]); /* three-word multiply */
WriteOp (op[i].word, fpop, fp_x); /* write product */
break;
case 012: /* XDIV 105212 (OP_AAXX) */
i = 1; /* params start at op[1] */
XDIV: /* enter here from .XDIV */
if (intrq) { /* interrupt pending? */
PC = err_PC; /* restart instruction */
break;
}
O = fp_exec (061, &fpop, op[i + 1], op[i + 2]); /* three-word divide */
WriteOp (op[i].word, fpop, fp_x); /* write quotient */
break;
case 013: /* .XADD 105213 (OP_AXX) */
i = 0; /* params start at op[0] */
goto XADD; /* process as XADD */
case 014: /* .XSUB 105214 (OP_AXX) */
i = 0; /* params start at op[0] */
goto XSUB; /* process as XSUB */
case 015: /* .XCOM 105215 (OP_A) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
fpop = ReadOp (op[0].word, fp_x); /* read unpacked */
AR = fp_ucom (&fpop, fp_x); /* complement and rtn exp adj */
WriteOp (op[0].word, fpop, fp_x); /* write result */
break;
case 016: /* ..DCM 105216 (OP_A) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
if (intrq) { /* interrupt pending? */
PC = err_PC; /* restart instruction */
break;
}
fpop = ReadOp (op[0].word, fp_x); /* read operand */
O = fp_pcom (&fpop, fp_x); /* complement (can't ovf neg) */
WriteOp (op[0].word, fpop, fp_x); /* write result */
break;
case 017: /* DDINT 105217 (OP_AAX) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
if (intrq) { /* interrupt pending? */
PC = err_PC; /* restart instruction */
break;
}
O = fp_trun (&fpop, op[2], fp_x); /* truncate operand (can't ovf) */
WriteOp (op[1].word, fpop, fp_x); /* write result */
break;
#endif /* end of int64 support */
/* FFP module 2 */
case 020: /* .XFER 105220 (OP_N) */
if (UNIT_CPU_TYPE == UNIT_TYPE_2100)
PC = (PC + 1) & VAMASK; /* 2100 .XFER returns to P+2 */
XFER: /* enter here from .DFER */
sc = 3; /* set count for 3-wd xfer */
goto CFER; /* do transfer */
case 021: /* .GOTO 105221 (OP_AK) */
if ((int16) op[1].word < 1) /* index < 1? */
op[1].word = 1; /* reset min */
sa = PC + op[1].word - 1; /* point to jump target */
if (sa >= op[0].word) /* must be <= last target */
sa = op[0].word - 1;
da = ReadW (sa); /* get jump target */
if (reason = resolve (da, &MA, intrq)) { /* resolve indirects */
PC = err_PC; /* irq restarts instruction */
break;
}
mp_dms_jmp (MA); /* validate jump addr */
PCQ_ENTRY; /* record last PC */
PC = MA; /* jump */
BR = op[0].word; /* (for 2100 FFP compat) */
break;
case 022: /* ..MAP 105222 (OP_KKKK) */
op[1].word = op[1].word - 1; /* decrement 1st subscr */
if ((AR & 1) == 0) /* 2-dim access? */
op[1].word = op[1].word + /* compute element offset */
(op[2].word - 1) * op[3].word;
else { /* 3-dim access */
if (reason = cpu_ops (OP_KK, op2, intrq)) { /* get 1st, 2nd ranges */
PC = err_PC; /* irq restarts instruction */
break;
}
op[1].word = op[1].word + /* offset */
((op[3].word - 1) * op2[1].word +
op[2].word - 1) * op2[0].word;
}
AR = (op[0].word + op[1].word * BR) & DMASK; /* return element address */
break;
case 023: /* .ENTR 105223 (OP_A) */
MA = PC - 3; /* get addr of entry point */
ENTR: /* enter here from .ENTP */
da = op[0].word; /* get addr of 1st formal */
dc = MA - da; /* get count of formals */
sa = ReadW (MA); /* get addr of return point */
ra = ReadW (sa++); /* get rtn, ptr to 1st actual */
WriteW (MA, ra); /* stuff rtn into caller's ent */
sc = ra - sa; /* get count of actuals */
if (sc > dc) /* use min (actuals, formals) */
sc = dc;
for (j = 0; j < sc; j++) {
MA = ReadW (sa++); /* get addr of actual */
if (reason = resolve (MA, &MA, intrq)) { /* resolve indirect */
PC = err_PC; /* irq restarts instruction */
break;
}
WriteW (da++, MA); /* put addr into formal */
}
AR = ra; /* return address */
BR = da; /* addr of 1st unused formal */
break;
case 024: /* .ENTP 105224 (OP_A) */
MA = PC - 5; /* get addr of entry point */
goto ENTR;
case 025: /* .PWR2 105225 (OP_RK) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */
expon = expon + (int16) (op[1].word); /* multiply by 2**n */
fp_pack (&fpop, fpop, expon, fp_f); /* repack value */
AR = fpop.fpk[0]; /* return result */
BR = fpop.fpk[1]; /* to A/B registers */
break;
case 026: /* .FLUN 105226 (OP_R) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */
AR = (int16) expon; /* return expon to A */
BR = fpop.fpk[1]; /* and low mant to B */
break;
case 027: /* $SETP 105227 (OP_K) */
j = sa = AR; /* save initial value */
sb = BR; /* save initial address */
AR = 0; /* AR will return = 0 */
BR = BR & VAMASK; /* addr must be direct */
do {
WriteW (BR, j); /* write value to address */
j = (j + 1) & DMASK; /* incr value */
BR = (BR + 1) & VAMASK; /* incr address */
op[0].word = op[0].word - 1; /* decr count */
if (op[0].word && intrq) { /* more and intr? */
AR = sa; /* restore A */
BR = sb; /* restore B */
PC = err_PC; /* restart instruction */
break;
}
}
while (op[0].word != 0); /* loop until count exhausted */
break;
case 030: /* .PACK 105230 (OP_RC) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
O = fp_nrpack (&fpop, op[0], /* nrm/rnd/pack value */
(int16) (op[1].word), fp_f);
AR = fpop.fpk[0]; /* return result */
BR = fpop.fpk[1]; /* to A/B registers */
break;
case 031: /* .CFER 105231 (OP_AA) */
if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */
(UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */
return stop_inst; /* trap if not */
BR = op[0].word; /* get destination address */
AR = op[1].word; /* get source address */
sc = 4; /* set for 4-wd xfer */
CFER: /* enter here from .XFER */
for (j = 0; j < sc; j++) { /* xfer loop */
WriteW (BR, ReadW (AR)); /* transfer word */
AR = (AR + 1) & VAMASK; /* bump source addr */
BR = (BR + 1) & VAMASK; /* bump destination addr */
}
E = 0; /* routine clears E */
if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 (and .DFER/.XFER)? */
AR = (AR + 1) & VAMASK; /* 2100 FFP returns X+4, Y+4 */
BR = (BR + 1) & VAMASK;
}
break;
default: /* others undefined */
reason = stop_inst;
}
return reason;
}
/* Double-Integer Instructions.
The double-integer instructions were added to the HP instruction set at
revision 1920 of the 1000-F. They were immediately adopted in a number of HP
software products, most notably the RTE file management package (FMP)
routines. As these routines are used in nearly every RTE program, F-Series
programs were almost always a few hundred bytes smaller than their M- and
E-Series counterparts. This became significant as RTE continued to grow in
size, and some customer programs ran out of address space on E-Series
machines.
While HP never added double-integer instructions to the standard E-Series, a
product from the HP "specials group," HP 93585A, provided microcoded
replacements for the E-Series. This could provide just enough address-space
savings to allow programs to load in E-Series systems, in addition to
accelerating these common operations.
M-Series microcode was never offered by HP. However, it costs us nothing to
enable double-integer instructions for M-Series simulations. This has the
concomitant advantage that it allows RTE-6/VM to run under SIMH (for
simulation, we must SET CPU 1000-M, because RTE-6/VM looks for the OS and VM
microcode -- which we do not implement yet -- if it detects an E- or F-Series
machine).
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A 93575A std
The routines are mapped to instruction codes as follows:
Instr. 1000-E 1000-F Description
------ ------ ------ -----------------------------------------
[test] 105320 -- [self test]
.DAD 105321 105014 Double integer add
.DMP 105322 105054 Double integer multiply
.DNG 105323 105203 Double integer negate
.DCO 105324 105204 Double integer compare
.DDI 105325 105074 Double integer divide
.DDIR 105326 105134 Double integer divide (reversed)
.DSB 105327 105034 Double integer subtract
.DIN 105330 105210 Double integer increment
.DDE 105331 105211 Double integer decrement
.DIS 105332 105212 Double integer increment and skip if zero
.DDS 105333 105213 Double integer decrement and skip if zero
.DSBR 105334 105114 Double integer subtraction (reversed)
On the F-Series, the double-integer instruction codes are split among the
floating-point processor and the Fast FORTRAN Processor ranges. They are
dispatched from those respective simulators for processing here.
Notes:
1. The E-Series opcodes are listed in Appendix C of the Macro/1000 manual.
These should be the same opcodes as given in the 93585A manual listed
below, but no copy of the reference below has been located to confirm
the proper opcodes. This module should be corrected if needed when such
documentation is found.
2. The action of the self-test instruction (105320) is unknown. At the
moment, we take an unimplemented instruction trap for this. When
documentation explaining the action is located, it will be implemented.
3. The F-Series firmware executes .DMP and .DDI/.DDIR by floating the
32-bit double integer to a 48-bit extended-precision number, calling the
FPP to execute the extended-precision multiply/divide, and then fixing
the product to a 32-bit double integer. We simulate these directly with
64- or 32-bit integer arithmetic.
Additional references:
- 93575A Double Integer Instructions Installation and Reference Manual
(93575-90007)
*/
static const OP_PAT op_dbi[16] = {
OP_N, OP_JD, OP_JD, OP_J, /* [test] .DAD .DMP .DNG */
OP_JD, OP_JD, OP_JD, OP_JD, /* .DCO .DDI .DDIR .DSB */
OP_J, OP_J, OP_A, OP_A, /* .DIN .DDE .DIS .DDS */
OP_JD, OP_N, OP_N, OP_N /* .DSBR --- --- --- */
};
t_stat cpu_dbi (uint32 IR, uint32 intrq)
{
OP din;
OPS op;
uint32 entry, t;
t_stat reason = SCPE_OK;
if ((cpu_unit.flags & UNIT_DBI) == 0) /* DBI option installed? */
return stop_inst;
entry = IR & 017; /* mask to entry point */
if (op_dbi[entry] != OP_N)
if (reason = cpu_ops (op_dbi[entry], op, intrq)) /* get instruction operands */
return reason;
switch (entry) { /* decode IR<3:0> */
case 000: /* [test] 105320 (OP_N) */
t = (AR << 16) | BR; /* set t for nop */
reason = stop_inst; /* function unknown; not impl. */
break;
case 001: /* .DAD 105321 (OP_JD) */
t = op[0].dword + op[1].dword; /* add values */
E = E | (t < op[0].dword); /* carry if result smaller */
O = (((~op[0].dword ^ op[1].dword) & /* overflow if sign wrong */
(op[0].dword ^ t) & SIGN32) != 0);
break;
case 002: /* .DMP 105322 (OP_JD) */
{
#if defined (HAVE_INT64) /* int64 support available */
t_int64 t64;
t64 = (t_int64) op[0].dword * /* multiply values */
(t_int64) op[1].dword;
O = ((t64 < -(t_int64) 0x80000000) || /* overflow if out of range */
(t64 > (t_int64) 0x7FFFFFFF));
if (O)
t = ~SIGN32; /* if overflow, rtn max pos */
else
t = (uint32) (t64 & DMASK32); /* else lower 32 bits of result */
#else /* int64 support unavailable */
uint32 sign, xu, yu, rh, rl;
sign = ((int32) op[0].dword < 0) ^ /* save sign of result */
((int32) op[1].dword < 0);
xu = (uint32) abs ((int32) op[0].dword); /* make operands pos */
yu = (uint32) abs ((int32) op[1].dword);
if ((xu & 0xFFFF0000) == 0 && /* 16 x 16 multiply? */
(yu & 0xFFFF0000) == 0) {
t = xu * yu; /* do it */
O = 0; /* can't overflow */
}
else if ((xu & 0xFFFF0000) != 0 && /* 32 x 32 multiply? */
(yu & 0xFFFF0000) != 0)
O = 1; /* always overflows */
else { /* 16 x 32 or 32 x 16 */
rl = (xu & 0xFFFF) * (yu & 0xFFFF); /* form 1st partial product */
if ((xu & 0xFFFF0000) == 0)
rh = xu * (yu >> 16) + (rl >> 16); /* 16 x 32 2nd partial */
else
rh = (xu >> 16) * yu + (rl >> 16); /* 32 x 16 2nd partial */
O = (rh > 0x7FFF + sign); /* check for out of range */
if (O == 0)
t = (rh << 16) | (rl & 0xFFFF); /* combine partials */
}
if (O)
t = ~SIGN32; /* if overflow, rtn max pos */
else if (sign)
t = ~t + 1; /* if result neg, 2s compl */
#endif /* end of int64 support */
}
break;
case 003: /* .DNG 105323 (OP_J) */
t = ~op[0].dword + 1; /* negate value */
O = (op[0].dword == SIGN32); /* overflow if max neg */
if (op[0].dword == 0) /* borrow if result zero */
E = 1;
break;
case 004: /* .DCO 105324 (OP_JD) */
t = op[0].dword; /* copy for later store */
if ((int32) op[0].dword < (int32) op[1].dword)
PC = (PC + 1) & VAMASK; /* < rtns to P+2 */
else if ((int32) op[0].dword > (int32) op[1].dword)
PC = (PC + 2) & VAMASK; /* > rtns to P+3 */
break; /* = rtns to P+1 */
case 005: /* .DDI 105325 (OP_JD) */
DDI:
O = ((op[1].dword == 0) || /* overflow if div 0 */
((op[0].dword == SIGN32) && /* or max neg div -1 */
((int32) op[1].dword == -1)));
if (O)
t = ~SIGN32; /* rtn max pos for ovf */
else
t = op[0].dword / op[1].dword; /* else return quotient */
break;
case 006: /* .DDIR 105326 (OP_JD) */
t = op[0].dword; /* swap operands */
op[0].dword = op[1].dword;
op[1].dword = t;
goto DDI; /* continue at .DDI */
case 007: /* .DSB 105327 (OP_JD) */
DSB:
t = op[0].dword - op[1].dword; /* subtract values */
E = E | (op[0].dword < op[1].dword); /* borrow if minu < subtr */
O = (((op[0].dword ^ op[1].dword) & /* overflow if sign wrong */
(op[0].dword ^ t) & SIGN32) != 0);
break;
case 010: /* .DIN 105330 (OP_J) */
t = op[0].dword + 1; /* increment value */
O = (t == SIGN32); /* overflow if sign flipped */
if (t == 0)
E = 1; /* carry if result zero */
break;
case 011: /* .DDE 105331 (OP_J) */
t = op[0].dword - 1; /* decrement value */
O = (t == ~SIGN32); /* overflow if sign flipped */
if ((int32) t == -1)
E = 1; /* borrow if result -1 */
break;
case 012: /* .DIS 105332 (OP_A) */
din = ReadOp (op[0].word, in_d); /* get value */
t = din.dword = din.dword + 1; /* increment value */
WriteOp (op[0].word, din, in_d); /* store it back */
if (t == 0)
PC = (PC + 1) & VAMASK; /* skip if result zero */
break;
case 013: /* .DDS 105333 (OP_A) */
din = ReadOp (op[0].word, in_d); /* get value */
t = din.dword = din.dword - 1; /* decrement value */
WriteOp (op[0].word, din, in_d); /* write it back */
if (t == 0)
PC = (PC + 1) & VAMASK; /* skip if result zero */
break;
case 014: /* .DSBR 105334 (OP_JD) */
t = op[0].dword; /* swap operands */
op[0].dword = op[1].dword;
op[1].dword = t;
goto DSB; /* continue at .DSB */
default: /* others undefined */
t = (AR << 16) | BR; /* set t for nop */
reason = stop_inst;
}
if (reason == SCPE_OK) { /* if return OK */
AR = (t >> 16) & DMASK; /* break result */
BR = t & DMASK; /* into A and B */
}
return reason;
}

1125
HP2100/hp2100_cpu4.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* hp2100_defs.h: HP 2100 simulator definitions
Copyright (c) 1993-2004, Robert M. Supnik
Copyright (c) 1993-2007, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,12 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
11-Jan-07 JDB Added 12578A DMA byte packing to DMA structure
28-Dec-06 JDB Added CRS backplane signal as I/O pseudo-opcode
Added DMASK32 32-bit mask value
21-Dec-06 JDB Changed MEM_ADDR_OK for 21xx loader support
12-Sep-06 JDB Define NOTE_IOG to recalc interrupts after instr exec
Rename STOP_INDINT to NOTE_INDINT (not a stop condition)
30-Dec-04 JDB Added IBL_DS_HEAD head number mask
19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF stop codes
25-Apr-04 RMS Added additional IBL definitions
@ -45,24 +51,25 @@
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
/* Simulator stop and notification codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_IODV 2 /* must be 2 */
#define STOP_HALT 3 /* HALT */
#define STOP_IBKPT 4 /* breakpoint */
#define STOP_IND 5 /* indirect loop */
#define STOP_INDINT 6 /* indirect intr */
#define NOTE_INDINT 6 /* indirect intr */
#define STOP_NOCONN 7 /* no connection */
#define STOP_OFFLINE 8 /* device offline */
#define STOP_PWROFF 9 /* device powered off */
#define NOTE_IOG 10 /* I/O instr executed */
#define ABORT_PRO 1 /* protection abort */
/* Memory */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
#define MEM_ADDR_OK(x) (((uint32) (x)) < fwanxm)
#define VA_N_SIZE 15 /* virtual addr size */
#define VASIZE (1 << VA_N_SIZE)
#define VAMASK 077777 /* virt addr mask */
@ -73,8 +80,10 @@
/* Architectural constants */
#define SIGN32 020000000000 /* 32b sign */
#define DMASK32 037777777777 /* 32b data mask */
#define SIGN 0100000 /* 16b sign */
#define DMASK 0177777 /* 16b data mask */
#define DMASK8 0377 /* 8b data mask */
#define AR ABREG[0] /* A = reg 0 */
#define BR ABREG[1] /* B = reg 1 */
#define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK)))
@ -101,7 +110,9 @@
/* DMA channels */
#define DMA_OE 020000000000 /* byte packing odd/even flag */
#define DMA1_STC 0100000 /* DMA - issue STC */
#define DMA1_PB 0040000 /* DMA - pack bytes */
#define DMA1_CLC 0020000 /* DMA - issue CLC */
#define DMA2_OI 0100000 /* DMA - output/input */
@ -109,6 +120,8 @@ struct DMA { /* DMA channel */
uint32 cw1; /* device select */
uint32 cw2; /* direction, address */
uint32 cw3; /* word count */
uint32 latency; /* 1st cycle delay */
uint32 packer; /* byte-packer holding reg */
};
/* Memory management */
@ -182,6 +195,7 @@ struct DMA { /* DMA channel */
#define ioOTX 6 /* output from A/B */
#define ioCTL 7 /* set/clear control */
#define ioEDT 8 /* DMA: end data transfer */
#define ioCRS 9 /* control reset ("CLC 0") */
/* I/O devices - fixed assignments */

View file

@ -1,18 +1,19 @@
SIMH/HP 21XX DIAGNOSTICS PERFORMANCE
====================================
Last update: 2005-03-22
Last update: 2007-01-12
The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation.
Diagnostic programs were obtained from magnetic tape, HP 24396-13601 Rev. 2040.
For each diagnostic, the recommended standard tests were selected, plus any
available optional tests that broadened the test coverage.
Diagnostic programs were obtained from two magnetic tapes, HP 24396-13601 Rev.
1713 and Rev. 2326, plus a few standalone paper tapes. For each diagnostic, the
recommended standard tests were selected, plus any available optional tests that
broadened the test coverage.
The test system configuration is the default SIMH configuration with these
alterations (except where noted in the individual diagnostic reports):
Except where noted in the individual diagnostic reports, the test system
configuration is the default SIMH configuration with these alterations:
* All I/O devices are enabled.
* The CPU is configured as a 21MX-E with 128KW of memory.
* The CPU is configured as a 1000-E with 128KW of memory.
Detailed diagnostic configuration, operation, and results are given after the
summary table. These may be used to duplicate the diagnostic results.
@ -33,19 +34,23 @@ The results of the diagnostic runs are summarized below:
101004 EAU Instruction Group 1431 3.2-3 Passed
101207 Floating Point Instruction Group 1551 3.2-3 Passed
102001 Memory Protect 1431 3.7-0 Passed
102002 Memory Parity Check 1431 - No simulation
102305 Memory Protect/Parity Error 1705 3.3-0 Partial
101206 Power Fail/Auto Restart 1635 - No simulation
141103 I/O Instruction Group 1810 3.2-3 Passed
143300 General Purpose Register 1813 3.2-3 Passed
101220 Direct Memory Access 1705 3.2-3 Passed
101105 Direct Memory Access (2114/15/16) 1502 3.7-0 Passed
101220 Direct Memory Access (2100/21MX) 1705 3.2-3 Passed
101011 Extended Instruction Group (Index) 1432 3.2-3 Passed
101112 Extended Instruction Group (Word, Byte) 1728 3.2-3 Passed
101110 2100 Fast FORTRAN Package 1632 3.4-0 Partial
101213 M/E-Series Fast FORTRAN Package 1 1822 3.4-0 Passed
101114 M/E-Series Fast FORTRAN Package 2 1632 3.4-0 Passed
101121 F-Series FPP/SIS/FFP 1926 - No simulation
101121 F-Series FPP/SIS/FFP 1926 3.7-0 Passed
101016 2000/Access Comm Processor for 2100 1526 3.2-3 Partial
102103 Memory Expansion Unit 1830 3.2-3 Passed
102103 Semiconductor Memory Microcoded 21MX 1644 - No simulation
@ -66,13 +71,26 @@ The results of the diagnostic runs are summarized below:
103121 12968 Asynchronous Comm. Interface 1602 - No simulation
103024 12821 ICD Disc Interface 1928 - No simulation
104000 2600 Keyboard Display Terminal 1615 - No simulation
104003 Teleprinter 1509 3.2-3 Partial
144105 2762A/B Terminal (Terminet) 1546 - No simulation
104007 2615 Video Terminal 1347 - No simulation
104011 2640 Interactive Terminal 1502 - No simulation
104012 2644 Mini Data Station (non CTU) 1542 - No simulation
104013 2644 Mini Data Station (CTU Only) 1542 - No simulation
104017 92900 Terminal Subsystem (3070, 40280) 1643 - No simulation
105000 2610/14 Line Printer 1451 - No simulation
105101 2767 Line Printer 1611 3.3-0 Passed
105102 2607 Line Printer 1446 3.3-0 Passed
145103 2613/17/18 Line Printer 1633 - No simulation
105104 9866 Line Printer 1541 - No simulation
105106 2631 Printer 1913 - No simulation
105107 2635 Printing Terminal 1913 - No simulation
105105 2608 Line Printer 2026 - No simulation
105104 9866 Line Printer 1541 - No simulation
111001 Disc File (2883) 1451 3.3-0 Partial
111104 12732 Flexible Disc Subsystem 1708 - No simulation
151302 7900/01 Cartridge Disc 1805 3.2-3 Partial
151403 7905/06/20/25 Disc 1805 3.3-1 Partial
@ -86,8 +104,7 @@ The results of the diagnostic runs are summarized below:
107000 Digital Plotter Interface (CALCOMP) 1540 - No simulation
113100 2892 Card Reader 1537 - No simulation
113001 2894 Card Reader Punch 1728 - No simulation
104003 Teleprinter 1509 3.2-3 Partial
104007 2615 Video Terminal 1347 - No simulation
113003 7261 Card Reader 1546 - No simulation
103006 12909B PROM Writer 1420 - No simulation
@ -97,12 +114,9 @@ not supported by the 24396 suite:
Paper Tape Date SIMH
Part Number DSN Diagnostic Name Code Vers. Result
----------- ------ --------------------------------------- ---- ----- ----------
12984-16001 105101 2767 Diagnostic 1611 3.3-0 Passed
24203-60001 -- HP2100A Cartridge Disc Memory (2871) A 3.3-0 Partial
12965-16001 111001 HP2100A Disc File (2883) 1451 3.3-0 Partial
22682-16017 177777 HP 2100 Fixed Head Disc/Drum (277x) 1612 3.3-0 Passed
13206-16001 101016 2100 2000/Access Comm. Proc. Firmware 1526 3.2-3 Partial
13207-16001 101217 21MX 2000/Access Comm. Proc. Firmware 1728 3.2-3 Passed
13207-16001 101217 2000/Access Comm Processor for 21MX 1728 3.2-3 Passed
20433-????? -- HP 3030 Magnetic Tape Subsystem -- - Not tested
@ -144,7 +158,7 @@ For all runs other than the diagnostic configurator pretest, the configurator
was used in automatic mode to load the target diagnostic via its Diagnostic
Serial Number (DSN), as follows:
sim> attach -r MSC0 24396-13601-REV-2040.tape
sim> attach -r MSC0 24396-13601_Rev-2326.abin.tape
sim> deposit S 000000
sim> boot MSC0
@ -233,6 +247,7 @@ TESTED DEVICE: CPU (hp2100_cpu.c)
CONFIGURATION: sim> set CPU 2100
sim> set CPU 32K
sim> deposit S 000000
sim> reset
sim> go 100
@ -273,7 +288,7 @@ TEST NOTES: The standard tests 00-10, plus optional tests 13, 14, and 16 are
DSN 101004 - EAU Instruction Group
----------------------------------
TESTED DEVICE: CPU (hp2100_cpu.c)
TESTED DEVICE: CPU (hp2100_cpu1.c)
CONFIGURATION: sim> deposit S 000000
sim> reset
@ -292,7 +307,7 @@ TEST RESULT: Passed.
DSN 101207 - Floating Point Instruction Group
---------------------------------------------
TESTED DEVICE: CPU (hp2100_fp.c)
TESTED DEVICE: CPU (hp2100_cpu2.c)
CONFIGURATION: sim> deposit S 000000
sim> reset
@ -307,6 +322,44 @@ TEST RESULT: Passed.
---------------------------
DSN 102001 - Memory Protect
---------------------------
TESTED DEVICE: MP (hp2100_cpu.c)
CONFIGURATION: sim> set CPU 2100
sim> set CPU 32K
sim> deposit S 000000
sim> reset
sim> go 100
TEST REPORT: HP 2100 SERIES MEMORY PROTECT DIAGNOSTIC
H07. PRESS PRESET (EXT/INT), RUN
HALT instruction 102007
sim> reset
sim> go
H13. PRESS HALT, PRESET(INT), RUN
IN LESS THAN 15 SEC.
[CTRL+E]
Simulation stopped
sim> reset
sim> go
PASS 000001
HALT instruction 102077
TEST RESULT: Passed.
----------------------------------------
DSN 102305 - Memory Protect/Parity Error
----------------------------------------
@ -454,12 +507,47 @@ TEST RESULT: Passed.
---------------------------------
DSN 101220 - Direct Memory Access
---------------------------------
----------------------------------------------
DSN 101105 - Direct Memory Access (2114/15/16)
----------------------------------------------
TESTED DEVICE: DMA0/DMA1 (hp2100_cpu.c)
CONFIGURATION: sim> set CPU 2116
sim> set CPU 16K
sim> set LPS diag
sim> deposit S 000014
sim> reset
sim> go 100
HALT instruction 102074
sim> deposit S 040000
sim> reset
sim> go
TEST REPORT: H0. START DMA DIAGNOSTIC
HALT instruction 102027
sim> reset
sim> go
H77. END DIAGNOSTIC
HALT instruction 102077
TEST RESULT: Passed.
---------------------------------------------
DSN 101220 - Direct Memory Access (2100/21MX)
---------------------------------------------
TESTED DEVICE: DCPC0/DCPC1 (hp2100_cpu.c)
CONFIGURATION: sim> set LPS diag
sim> deposit S 000014
sim> reset
@ -492,7 +580,7 @@ TEST RESULT: Passed.
DSN 101011 - Extended Instruction Group (Index)
-----------------------------------------------
TESTED DEVICE: CPU (hp2100_cpu1.c)
TESTED DEVICE: CPU (hp2100_cpu2.c)
CONFIGURATION: sim> deposit S 000000
sim> reset
@ -511,7 +599,7 @@ TEST RESULT: Passed.
DSN 101112 - Extended Instruction Group (Word, Byte, Bit)
---------------------------------------------------------
TESTED DEVICE: CPU (hp2100_cpu1.c)
TESTED DEVICE: CPU (hp2100_cpu2.c)
CONFIGURATION: sim> set LPS diag
sim> deposit S 000014
@ -537,7 +625,7 @@ TEST RESULT: Passed.
DSN 101110 - 2100 Fast FORTRAN Package
--------------------------------------
TESTED DEVICE: CPU (hp2100_cpu1.c)
TESTED DEVICE: CPU (hp2100_cpu3.c)
CONFIGURATION: sim> set CPU 2100
sim> set CPU 32K
@ -598,7 +686,7 @@ TEST NOTES: Tests 07 and 11 test the interruptibility of the .XADD and .XMPY
DSN 101213 - M/E-Series Fast FORTRAN Package 1
----------------------------------------------
TESTED DEVICE: CPU (hp2100_cpu1.c)
TESTED DEVICE: CPU (hp2100_cpu3.c)
CONFIGURATION: sim> set CPU FFP
sim> set LPS diag
@ -636,10 +724,10 @@ TEST RESULT: Passed.
----------------------------------------------
DSN 101115 - M/E-Series Fast FORTRAN Package 2
DSN 101114 - M/E-Series Fast FORTRAN Package 2
----------------------------------------------
TESTED DEVICE: CPU (hp2100_cpu1.c)
TESTED DEVICE: CPU (hp2100_cpu3.c)
CONFIGURATION: sim> set CPU FFP
sim> set LPS diag
@ -675,11 +763,127 @@ TEST RESULT: Passed.
---------------------------------
DSN 101121 - F-Series FPP/SIS/FFP
---------------------------------
TESTED DEVICE: CPU (hp2100_cpu3.c)
CONFIGURATION: sim> set CPU 1000-F
sim> set LPS diag
sim> deposit S 000014
sim> reset
sim> go 100
HALT instruction 102074
sim> deposit S 000000
sim> reset
sim> go
TEST REPORT: FPP-SIS-FFP DIAGNOSTIC DSN 101121
BEGIN BASIC CONTROL TEST
OVFL TEST
CONF TEST
BASE RETN TEST
SIS1 RETN TEST
SIS2 RETN TEST
SIS3 RETN TEST
FPP1 RETN TEST
FFP2 RETN TEST
FFP3 RETN TEST
END BASIC CONTROL TEST
LONG PASSES
FIXS TEST
FIXD TEST
FLTS TEST
FLTD TEST
ADD TEST
SUB TEST
MPY TEST
DIV TEST
ACC TEST
SIS1 TEST
SIS2 TEST
SIS3 TEST
FFP1 TEST
FFP2 TEST
FFP3 TEST
PASS 00001
HALT instruction 102077
TEST RESULT: Passed.
------------------------------------------------
DSN 101016 - 2000/Access Comm Processor for 2100
------------------------------------------------
TESTED DEVICE: CPU (hp2100_cpu2.c)
BINARY TAPE: 13206-16001 Rev. 1526
CONFIGURATION: sim> set CPU 2100
sim> set CPU 32K
sim> set CPU IOP
sim> deposit S 000013
sim> reset
sim> go 100
HALT instruction 102074
sim> deposit S 000000
sim> reset
sim> go
TEST REPORT: 2100 2000-ACCESS COMM. PROC. FIRMWARE DIAGNOSTIC
H030 CRC TEST
H040 ENQ, DEQ AND PENQ TESTS
H060 IAL TEST
H110 READF, SAVE AND RESTR TESTS
H120 LAI AND SAI TESTS
H130 PFREX TEST
H140 PFREI TEST
H150 PFRIO TEST
H160 STORE-LOAD BYTE, TRSLT
AND BYTE MOVE TEST
TEST 10
E165 TRSLT NOT INTERRUPTIBLE
HALT instruction 106065
sim> go
H230 WORD MOVE TEST
TEST 11
E234 WORD MOVE NOT INTERRUPTIBLE
HALT instruction 103034
sim> go
PASS 000001
HALT instruction 102077
TEST RESULT: Partially passed.
TEST NOTES: Tests 10 and 11 test the interruptibility of the TRSLT and MWORD
instructions. These features are not simulated.
----------------------------------
DSN 102103 - Memory Expansion Unit
----------------------------------
TESTED DEVICE: CPU (hp2100_cpu.c)
TESTED DEVICE: CPU (hp2100_cpu2.c)
CONFIGURATION: sim> set LPS diag
sim> deposit S 000014
@ -812,6 +1016,109 @@ TEST RESULT: Not tested.
------------------------------
DSN 105101 - 2767 Line Printer
------------------------------
TESTED DEVICE: LPS (hp2100_lps.c)
BINARY TAPE: 12984-16001 Rev. 1611
CONFIGURATION: sim> set LPS realtime
sim> attach LPS scratch.2767.printer
sim> deposit S 000014
sim> reset
sim> go 100
HALT instruction 102074
sim> deposit S 000000
sim> reset
sim> go
TEST REPORT: 2767 L.P. DIAGNOSTIC
H024 PRESS PRESET (EXT&INT),RUN
HALT instruction 102024
sim> reset
sim> go
H025 BI-O COMP
H035 TURN OFF L.P. POWER
HALT instruction 102035
sim> set LPS poweroff
sim> go
H036 TURN ON L.P. POWER
HALT instruction 102036
sim> set LPS poweron
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
H034 MASTER CLEAR L.P.
HALT instruction 102034
sim> set LPS offline
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
H040 PUT L.P. OFF-LINE. TOGGLE TOP-OF-FORM SWITCH
HALT instruction 102040
sim> set LPS offline
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
H041 PUT L.P. OFF-LINE. TOGGLE PAPER-STEP 5 TIMES
HALT instruction 102041
sim> set LPS offline
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
PASS 000001
HALT instruction 102077
TEST RESULT: Passed.
TEST NOTES: The simulation provides no manual Master Clear, Top of Form, or
Paper Step functions, so these are merely presumed above.
------------------------------
DSN 105102 - 2607 Line Printer
------------------------------
@ -2125,7 +2432,7 @@ Each execution note below presumes that the target diagnostic has been loaded.
For all runs, the diagnostic configurator was used in automatic mode to load the
target diagnostic from a paper tape image, as follows:
sim> attach -r MSC0 24396-13601-REV-2040.tape
sim> attach -r MSC0 24396-13601_Rev-2236.abin.tape
sim> deposit S 000000
sim> boot MSC0
@ -2138,109 +2445,6 @@ target diagnostic from a paper tape image, as follows:
------------------------------
DSN 105101 - 2767 Line Printer
------------------------------
TESTED DEVICE: LPS (hp2100_lps.c)
BINARY TAPE: 12984-16001 Rev. 1611
CONFIGURATION: sim> set LPS realtime
sim> attach LPS scratch.2767.printer
sim> deposit S 000014
sim> reset
sim> go 100
HALT instruction 102074
sim> deposit S 000000
sim> reset
sim> go
TEST REPORT: 2767 L.P. DIAGNOSTIC
H024 PRESS PRESET (EXT&INT),RUN
HALT instruction 102024
sim> reset
sim> go
H025 BI-O COMP
H035 TURN OFF L.P. POWER
HALT instruction 102035
sim> set LPS poweroff
sim> go
H036 TURN ON L.P. POWER
HALT instruction 102036
sim> set LPS poweron
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
H034 MASTER CLEAR L.P.
HALT instruction 102034
sim> set LPS offline
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
H040 PUT L.P. OFF-LINE. TOGGLE TOP-OF-FORM SWITCH
HALT instruction 102040
sim> set LPS offline
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
H041 PUT L.P. OFF-LINE. TOGGLE PAPER-STEP 5 TIMES
HALT instruction 102041
sim> set LPS offline
sim> go
H033 PUT L.P. ON-LINE
HALT instruction 102033
sim> set LPS online
sim> go
PASS 000001
HALT instruction 102077
TEST RESULT: Passed.
TEST NOTES: The simulation provides no manual Master Clear, Top of Form, or
Paper Step functions, so these are merely presumed above.
-----------------------------------------------------------------
DSN (none) - HP2100A Cartridge Disc Memory (2871) (multiple unit)
-----------------------------------------------------------------
@ -2876,75 +3080,16 @@ TEST RESULT: Passed.
-------------------------------------------------
DSN 101016 - 2000/Access Comm. Processor Firmware
-------------------------------------------------
------------------------------------------------
DSN 101217 - 2000/Access Comm Processor for 21MX
------------------------------------------------
TESTED DEVICE: CPU (hp2100_cpu.c)
BINARY TAPE: 13206-16001 Rev. 1526
CONFIGURATION: sim> set CPU 2100
sim> set CPU 32K
sim> set CPU IOP
sim> deposit S 000013
sim> reset
sim> go 100
HALT instruction 102074
sim> deposit S 000000
sim> reset
sim> go
TEST REPORT: 2100 2000-ACCESS COMM. PROC. FIRMWARE DIAGNOSTIC
H030 CRC TEST
H040 ENQ, DEQ AND PENQ TESTS
H060 IAL TEST
H110 READF, SAVE AND RESTR TESTS
H120 LAI AND SAI TESTS
H130 PFREX TEST
H140 PFREI TEST
H150 PFRIO TEST
H160 STORE-LOAD BYTE, TRSLT
AND BYTE MOVE TEST
TEST 10
E165 TRSLT NOT INTERRUPTIBLE
HALT instruction 106065
sim> go
H230 WORD MOVE TEST
TEST 11
E234 WORD MOVE NOT INTERRUPTIBLE
HALT instruction 103034
sim> go
PASS 000001
HALT instruction 102077
TEST RESULT: Partially passed.
TEST NOTES: Tests 10 and 11 test the interruptibility of the TRSLT and MWORD
instructions. These features are not simulated.
-------------------------------------------------
DSN 101217 - 2000/Access Comm. Processor Firmware
-------------------------------------------------
TESTED DEVICE: CPU (hp2100_cpu.c)
TESTED DEVICE: CPU (hp2100_cpu2.c)
BINARY TAPE: 13207-16001 Rev. 1728
CONFIGURATION: sim> set CPU IOP
sim> deposit S 000013
sim> reset
sim> go 100

View file

@ -1,6 +1,6 @@
/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@
dp 12557A 2871 disk subsystem
13210A 7900 disk subsystem
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
01-Mar-05 JDB Added SET UNLOAD/LOAD
07-Oct-04 JDB Fixed enable/disable from either device
Fixed ANY ERROR status for 12557A interface
@ -395,6 +396,7 @@ switch (inst) { /* case on opcode */
dat = dpd_ibuf;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCTL (devd); /* clr ctl, cmd */
@ -449,6 +451,7 @@ switch (inst) { /* case on opcode */
if (!dp_ctype) break;
IR = IR | I_CTL; /* 13210 OTx causes CLC */
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC? */
clrCTL (devc); /* clr cmd, ctl */

View file

@ -1,6 +1,6 @@
/* hp2100_dq.c: HP 2100 12565A disk simulator
Copyright (c) 1993-2005, Bill McDermith
Copyright (c) 1993-2006, Bill McDermith
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
dq 12565A 2883 disk system
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
01-Mar-05 JDB Added SET UNLOAD/LOAD
07-Oct-04 JDB Fixed enable/disable from either device
Shortened xtime from 5 to 3 (drive avg 156KW/second)
@ -313,6 +314,7 @@ switch (inst) { /* case on opcode */
dat = dqd_ibuf;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCTL (devd); /* clr ctl, cmd */
@ -363,6 +365,7 @@ switch (inst) { /* case on opcode */
case ioMIX: /* merge */
break; /* no data */
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC? */
clrCMD (devc); /* clr cmd, ctl */

View file

@ -1,6 +1,6 @@
/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@
dr 12606B 2770/2771 fixed head disk
12610B 2773/2774/2775 drum
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
07-Oct-04 JDB Fixed enable/disable from either device
Fixed sector return in status word
Provided protected tracks and "Writing Enabled" status bit
@ -331,6 +332,7 @@ switch (inst) { /* case on opcode */
dat = drd_ibuf;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_AB) { /* CLC */
clrCMD (devd); /* clr "ctl" */

View file

@ -1,6 +1,6 @@
/* hp2100_ds.c: HP 2100 13037 disk controller simulator
Copyright (c) 2004-2005, Robert M. Supnik
Copyright (c) 2004-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,9 @@
ds 13037 disk controller
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
03-Aug-06 JDB Fixed REQUEST STATUS command to clear status-1
Removed redundant attached test in "ds_detach"
18-Mar-05 RMS Added attached test to detach routine
01-Mar-05 JDB Added SET UNLOAD/LOAD
@ -595,6 +598,7 @@ switch (inst) { /* case on opcode */
dat = ds_fifo_read ();
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCTL (dev); /* clear control */
@ -705,7 +709,8 @@ switch (op) {
case DSC_RSTA: /* read status */
dsxb[1] = ds_sr1; /* return SR1 */
if (unum < DS_NUMDR) { /* and SR2 */
ds_sr1 = 0; /* clear SR1 */
if (unum < DS_NUMDR) { /* return SR2 */
dsxb[0] = ds_updds2 (&ds_unit[unum]);
ds_unit[unum].STA &= ~DS2_FS; /* clear 1st */
}
@ -1460,8 +1465,7 @@ return SCPE_OK;
t_stat ds_detach (UNIT *uptr)
{
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
ds_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */
ds_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads if attached */
return detach_unit (uptr);
}

View file

@ -1,6 +1,6 @@
/* hp2100_fp.c: HP 2100 floating point instructions
Copyright (c) 2002-2005, Robert M. Supnik
Copyright (c) 2002-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2
22-Jul-05 RMS Fixed compiler warning in Solaris (from Doug Glyn)
25-Feb-05 JDB Added FFP helpers f_pack, f_unpack, f_pwr2
11-Feb-05 JDB Fixed missing negative overflow renorm in StoreFP
@ -30,6 +31,16 @@
15-Jul-03 RMS Fixed signed/unsigned warning
21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms
Implementation note: The 2100/1000-M/E Fast FORTRAN Processor (FFP) and 1000
F-Series Floating Point Processor (FPP) simulations require that the host
compiler support 64-bit integers and the HAVE_INT64 symbol be defined during
compilation. If this symbol is defined, two-word floating-point operations
are handled in the FPP code, and this module is not used. If it is not
defined, then FFP and FPP operations are not available, and this module
provides the floating-point support.
The HP2100 uses a unique binary floating point format:
15 14 0
@ -69,6 +80,10 @@
*/
#include "hp2100_defs.h"
#include "hp2100_cpu1.h"
#include "hp2100_fp.h"
#if !defined (HAVE_INT64) /* int64 support unavailable */
struct ufp { /* unpacked fp */
int32 exp; /* exp */
@ -98,8 +113,6 @@ struct ufp { /* unpacked fp */
#define FPAB ((((uint32) AR) << 16) | ((uint32) BR))
#define DMASK32 0xFFFFFFFF
/* Fraction shift; 0 < shift < 32 */
#define FR_ARS(v,s) (((v) >> (s)) | (((v) & FP_SIGN)? \
@ -112,6 +125,7 @@ extern uint16 ABREG[2];
uint32 UnpackFP (struct ufp *fop, uint32 opnd);
void NegFP (struct ufp *fop);
void NormFP (struct ufp *fop);
uint32 PackFP (struct ufp *fop);
uint32 StoreFP (struct ufp *fop);
/* Floating to integer conversion */
@ -275,47 +289,6 @@ if (fop1.fr) { /* dvd != 0? */
return StoreFP (&quo); /* store result */
}
/* Fast FORTRAN Processor helpers. */
/* Pack mantissa in A/B and exponent and return fp in A/B */
uint32 f_pack (int32 expon)
{
struct ufp fop;
fop.fr = FPAB;
fop.exp = expon;
return StoreFP (&fop);
}
/* Unpack fp number in A/B into A (exponent) and B (lower mantissa) */
void f_unpack (void)
{
AR = FP_GETEXP (BR); /* get exponent */
if (FP_GETEXPS (BR)) AR = (AR | ~FP_M_EXP) & DMASK; /* < 0? sext */
BR = BR & (uint16) ~(FP_EXP | FP_EXPS); /* clear exp */
return;
}
/* Multiply fp number in A/B by 2**n and return in A/B.
Exponent overflow or underflow wraps around. */
void f_pwr2 (int32 n)
{
uint32 save_a;
if (AR | BR) { /* microcode test */
save_a = AR;
f_unpack (); /* unpack exponent */
AR = AR + n; /* multiply */
BR = BR | ((AR & FP_M_EXP) << FP_V_EXP) | /* merge exponent */
((AR & SIGN)? (1 << FP_V_EXPS): 0); /* and exponent sign */
AR = save_a;
}
return;
}
/* Utility routines */
/* Unpack operand */
@ -343,6 +316,15 @@ else fop->exp = 0; /* clean 0 */
return;
}
/* Pack fp number */
uint32 PackFP (struct ufp *fop)
{
return (fop->fr & FP_FR) | /* merge frac */
((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */
((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */
}
/* Round fp number, store, generate overflow */
uint32 StoreFP (struct ufp *fop)
@ -367,10 +349,58 @@ else if (fop->exp > FP_M_EXP) { /* overflow? */
hi = 0x7FFFFFFE; /* all 1's */
ov = 1;
}
else hi = (fop->fr & FP_FR) | /* merge frac */
((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */
((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */
else hi = PackFP (fop); /* pack mant and exp */
AR = (hi >> 16) & DMASK;
BR = hi & DMASK;
return ov;
}
/* Single-precision Fast FORTRAN Processor helpers. */
/* Pack mantissa and exponent and return fp value. */
uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision)
{
struct ufp fop;
uint32 val;
fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1];
fop.exp = exponent;
val = PackFP (&fop);
result->fpk[0] = (int16) (val >> 16);
result->fpk[1] = (int16) val;
return 0;
}
/* Normalize, round, and pack mantissa and exponent and return fp value. */
uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision)
{
struct ufp fop;
uint32 ovf;
fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1];
fop.exp = exponent;
ovf = StoreFP (&fop);
result->fpk[0] = AR;
result->fpk[1] = BR;
return ovf;
}
/* Unpack fp number in into mantissa and exponent. */
uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision)
{
struct ufp fop;
uint32 operand;
operand = ((uint32) packed.fpk[0] << 16) | packed.fpk[1];
UnpackFP (&fop, operand);
mantissa->fpk[0] = (uint16) fop.fr >> 16;
mantissa->fpk[1] = (uint16) fop.fr;
*exponent = fop.exp;
return 0;
}
#endif /* int64 support unavailable */

47
HP2100/hp2100_fp.h Normal file
View file

@ -0,0 +1,47 @@
/* hp2100_fp.h: HP 2100/21MX floating point definitions
Copyright (c) 2002-2006, Robert M. Supnik
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 Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2
26-Sep-06 JDB Moved from hp2100_fp.c to simplify extensions
*/
#ifndef _HP2100_FP_H_
#define _HP2100_FP_H_
/* Firmware floating-point routines */
uint32 f_as (uint32 op, t_bool sub); /* FAD/FSB */
uint32 f_mul (uint32 op); /* FMP */
uint32 f_div (uint32 op); /* FDV */
uint32 f_fix (void); /* FIX */
uint32 f_flt (void); /* FLT */
/* Firmware FFP helpers */
uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision);
uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision);
uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* hp2100_fp1.h: HP 2100/21MX extended-precision floating point definitions
/* hp2100_fp1.h: HP 2100/1000 multiple-precision floating point definitions
Copyright (c) 2005, J. David Bryan
Copyright (c) 2005-2006, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -15,38 +15,39 @@
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
THE AUTHOR 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 the author shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
Except as contained in this notice, the name of the author shall not be used
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
16-Oct-06 JDB Generalized FP calling sequences for F-Series
12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility
*/
#ifndef _HP2100_FP1_H_
#define _HP2100_FP1_H_ 0
/* HP memory representation of an extended-precision number */
typedef struct {
uint32 high;
uint32 low;
} XPN;
/* Special operands. */
#define ACCUM NULL /* result not returned */
static const OP NOP = { { 0, 0, 0, 0, 0 } }; /* unneeded operand */
#define AS_XPN(x) (*(XPN *) &(x)) /* view as XPN */
/* Generalized floating-point handlers. */
XPN ReadX (uint32 va);
void WriteX (uint32 va, XPN packed);
uint32 x_add (XPN *sum, XPN augend, XPN addend);
uint32 x_sub (XPN *difference, XPN minuend, XPN subtrahend);
uint32 x_mpy (XPN *product, XPN multiplicand, XPN multiplier);
uint32 x_div (XPN *quotient, XPN dividend, XPN divisor);
uint32 x_pak (XPN *result, XPN mantissa, int32 exponent);
uint32 x_com (XPN *mantissa);
uint32 x_dcm (XPN *packed);
void x_trun (XPN *result, XPN source);
void fp_prec (uint16 opcode, OPSIZE *operand_l, OPSIZE *operand_r, OPSIZE *result);
uint32 fp_exec (uint16 opcode, OP *result, OP operand_l, OP operand_r);
OP fp_accum (const OP *operand, OPSIZE precision);
uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision);
uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision);
uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision);
uint32 fp_ucom (OP *mantissa, OPSIZE precision);
uint32 fp_pcom (OP *packed, OPSIZE precision);
uint32 fp_trun (OP *result, OP source, OPSIZE precision);
uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision);
#endif

View file

@ -1,6 +1,6 @@
/* hp2100_ipl.c: HP 2000 interprocessor link simulator
Copyright (c) 2002-2005, Robert M Supnik
Copyright (c) 2002-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
ipli, iplo 12566B interprocessor link pair
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
16-Aug-05 RMS Fixed C++ declaration and cast problems
07-Oct-04 JDB Fixed enable/disable from either device
26-Apr-04 RMS Fixed SFS x,C and SFC x,C
@ -201,6 +202,7 @@ switch (inst) { /* case on opcode */
dat = dat | uptr->IBUF; /* get return data */
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear ctl, cmd */

View file

@ -1,6 +1,6 @@
/* hp2100_lps.c: HP 2100 12653A line printer simulator
/* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2007, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -24,8 +24,10 @@
in this Software without prior written authorization from Robert M Supnik.
lps 12653A 2767 line printer
(based on 12566B microcircuit interface)
12566B microcircuit interface with loopback diagnostic connector
11-Jan-07 JDB CLC cancels I/O event if DIAG (jumper W9 in "A" pos)
Added ioCRS state to I/O decoders
19-Nov-04 JDB Added restart when set online, etc.
Fixed col count for non-printing chars
01-Oct-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON
@ -47,6 +49,18 @@
Added command flop
15-Oct-00 RMS Added variable device number support
This module simulates two different devices. In "diagnostic mode," it
simulates a 12566B microcircuit interface card with a loopback connector and
the jumpers set as required for execution of the General Purpose Register
diagnostic. In non-diagnostic mode, it simulates a 12653A line printer
interface card and a 2767 line printer.
The 12566B interface with the loopback connector ties the device command
output to the device flag input. Setting control therefore causes device
flag to set almost immediately. Device command is active only during that
interim. Under simulation, the loopback occurs within the STC handler, and
CMD is never set.
The 2767 impact printer has a rotating drum with 80 columns of 64 raised
characters. ASCII codes 32 through 95 (SPACE through "_") form the print
repertoire. The printer responds to the control characters FF, LF, and CR.
@ -103,6 +117,7 @@
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#define LPS_ZONECNT 20 /* zone char count */
#define LPS_PAGECNT 80 /* page char count */
@ -148,6 +163,13 @@ uint32 lps_power = LPS_ON; /* power state */
NOTE: the printer acknowledges before the print motion has stopped to allow
for continuous slew, so the set times are a bit less than the calculated
operation time from the manual.
NOTE: the 2767 diagnostic checks completion times, so the realistic timing
must be used. Because simulator timing is in instructions, and because the
diagnostic uses the TIMER instruction (~1580 executions per millisecond) when
running on a 1000-E/F but a software timing loop (~400-600 executions per
millisecond) when running on anything else, realistic timings are decreased by
three-fourths when not executing on an E/F.
*/
int32 lps_ctime = 0; /* char xfer time */
@ -280,16 +302,28 @@ switch (inst) { /* case on opcode */
fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", dat);
break;
case ioCRS: /* control reset */
clrCTL (dev); /* clear control */
clrCMD (dev); /* clear command */
sim_cancel (&lps_unit); /* deactivate unit */
break;
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear ctl, cmd */
clrCTL (dev);
clrCTL (dev); /* clear control */
if (lps_unit.flags & UNIT_DIAG) { /* diagnostic mode? */
clrCMD (dev); /* clear command (jumper W9-A) */
if (IR & I_HC) /* clear flag too? */
sim_cancel (&lps_unit); /* prevent FLG/SRQ */
}
}
else { /* STC */
setCMD (dev); /* set ctl, cmd */
setCTL (dev);
if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */
sim_activate (&lps_unit, 1); /* loop back */
setCTL (dev); /* set ctl */
setCMD (dev); /* set cmd */
if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */
lps_sta = lps_unit.buf; /* loop back data */
sim_activate (&lps_unit, 2); /* schedule flag */
}
else { /* real lpt, sched */
if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,
">>LPS STC: Character %06o scheduled for line %d, column %d, ",
@ -349,7 +383,6 @@ if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */
}
dev = lps_dib.devno; /* get dev no */
if (uptr->flags & UNIT_DIAG) { /* diagnostic? */
lps_sta = uptr->buf; /* loop back */
clrCMD (dev); /* clear cmd */
setFSR (dev); /* set flag, fbf */
return SCPE_OK; /* done */
@ -465,15 +498,22 @@ lps_restart (uptr, 0, NULL, NULL); /* restart I/O if hung *
return attach_unit (uptr, cptr);
}
/* Set printer timing */
/* Set printer timing
Realistic timing is factored, depending on CPU model, to account for the
timing method employed by the diagnostic. */
t_stat lps_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i;
uint32 i, factor = 1;
lps_timing = (val != 0); /* determine choice */
if ((lps_timing == 0) && /* calc speed factor */
(UNIT_CPU_MODEL != UNIT_1000_E) &&
(UNIT_CPU_MODEL != UNIT_1000_F))
factor = 4;
for (i = 0; i < (sizeof (lps_timers) / sizeof (lps_timers[0])); i++)
*lps_timers[i] = lps_times[lps_timing][i]; /* assign times */
*lps_timers[i] = lps_times[lps_timing][i] / factor; /* assign times */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* hp2100_lpt.c: HP 2100 12845B line printer simulator
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
lpt 12845B 2607 line printer
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
19-Nov-04 JDB Added restart when set online, etc.
29-Sep-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON
Fixed status returns for error conditions
@ -190,6 +191,7 @@ switch (inst) { /* case on opcode */
}
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear ctl, cmd */

View file

@ -26,6 +26,11 @@
ms 13181A 7970B 800bpi nine track magnetic tape
13183A 7970E 1600bpi nine track magnetic tape
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
18-Sep-06 JDB Fixed 2nd CLR after WC causing another write
Improve debug reporting, add debug flags
14-Sep-06 JDB Removed local BOT flag, now uses sim_tape_bot
30-Aug-06 JDB Added erase gap support, improved tape lib err reporting
07-Jul-06 JDB Added CAPACITY as alternate for REEL
Fixed EOT test for unlimited reel size
16-Feb-06 RMS Revised for new EOT test
@ -90,8 +95,18 @@
#define UST u4 /* unit status */
#define REEL u5 /* tape reel size */
#define BPI_13181 800 /* 800 bpi for 13181 cntlr */
#define BPI_13183 1600 /* 1600 bpi for 13183 cntlr */
#define GAP_13181 48 /* gap is 4.8 inches for 13181 cntlr */
#define GAP_13183 30 /* gap is 3.0 inches for 13183 cntlr */
#define TCAP (300 * 12 * 800) /* 300 ft capacity at 800 bpi */
/* Debug flags */
#define DEB_CMDS (1 << 0) /* command init and compl */
#define DEB_CPU (1 << 1) /* CPU I/O */
#define DEB_RWS (1 << 2) /* tape reads, writes, status */
/* Command - msc_fnc */
#define FNC_CLR 00110 /* clear */
@ -106,7 +121,8 @@
#define FNC_REW 00101 /* rewind */
#define FNC_RWS 00105 /* rewind and offline */
#define FNC_WFM 00211 /* write file mark */
#define FNC_RFF 00223 /* "read file fwd" */
#define FNC_RFF 00223 /* read file fwd (diag) */
#define FNC_RRR 00061 /* read record rev (diag) */
#define FNC_CMPL 00400 /* completion state */
#define FNC_V_SEL 9 /* select */
#define FNC_M_SEL 017
@ -132,14 +148,15 @@
#define STA_TBSY 0001000 /* transport busy (d) */
#define STA_BUSY 0000400 /* ctrl busy */
#define STA_EOF 0000200 /* end of file */
#define STA_BOT 0000100 /* beg of tape (u) */
#define STA_BOT 0000100 /* beg of tape (d) */
#define STA_EOT 0000040 /* end of tape (d) */
#define STA_TIM 0000020 /* timing error */
#define STA_REJ 0000010 /* programming error */
#define STA_WLK 0000004 /* write locked (d) */
#define STA_PAR 0000002 /* parity error */
#define STA_LOCAL 0000001 /* local (d) */
#define STA_DYN (STA_PE|STA_SEL|STA_TBSY|STA_WLK|STA_LOCAL)
#define STA_DYN (STA_PE | STA_SEL | STA_TBSY | STA_BOT | \
STA_EOT | STA_WLK | STA_LOCAL)
extern uint32 PC, SR;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];
@ -151,7 +168,7 @@ int32 ms_timing = 1; /* timing type */
int32 msc_sta = 0; /* status */
int32 msc_buf = 0; /* buffer */
int32 msc_usl = 0; /* unit select */
int32 msc_1st = 0;
int32 msc_1st = 0; /* first service */
int32 msc_stopioe = 1; /* stop on error */
int32 msd_buf = 0; /* data buffer */
uint8 msxb[DBSIZE] = { 0 }; /* data buffer */
@ -201,6 +218,7 @@ t_stat msc_attach (UNIT *uptr, char *cptr);
t_stat msc_detach (UNIT *uptr);
t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc);
t_stat msc_boot (int32 unitno, DEVICE *dptr);
t_stat ms_write_gap (UNIT *uptr);
t_stat ms_map_err (UNIT *uptr, t_stat st);
t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
@ -209,6 +227,7 @@ t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc);
void ms_config_timing (void);
char *ms_cmd_name (uint32 cmd);
/* MSD data structures
@ -261,6 +280,7 @@ DEVICE msd_dev = {
msc_unit MSC unit list
msc_reg MSC register list
msc_mod MSC modifier list
msc_deb MSC debug flags
*/
UNIT msc_unit[] = {
@ -329,12 +349,20 @@ MTAB msc_mod[] = {
{ 0 }
};
DEBTAB msc_deb[] = {
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "RWS", DEB_RWS },
{ NULL, 0 }
};
DEVICE msc_dev = {
"MSC", msc_unit, msc_reg, msc_mod,
MS_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &msc_reset,
&msc_boot, &msc_attach, &msc_detach,
&msc_dib, DEV_DISABLE | DEV_DEBUG
&msc_dib, DEV_DISABLE | DEV_DEBUG,
0, msc_deb, NULL, NULL
};
/* IO instructions */
@ -370,6 +398,7 @@ switch (inst) { /* case on opcode */
dat = msd_buf;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCTL (devd); /* clr ctl, cmd */
@ -420,7 +449,7 @@ switch (inst) { /* case on opcode */
break;
case ioOTX: /* output */
if (DEBUG_PRS (msc_dev))
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", dat);
msc_buf = dat;
msc_sta = msc_sta & ~STA_REJ; /* clear reject */
@ -432,9 +461,11 @@ switch (inst) { /* case on opcode */
if (dat & FNF_CHS) { /* select change */
msc_usl = map_sel[FNC_GETSEL (dat)]; /* is immediate */
uptr = msc_dev.units + msc_usl;
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl);
}
if (((dat & FNF_MOT) && sim_is_active (uptr)) ||
((dat & FNF_REV) && (uptr->UST & STA_BOT)) ||
((dat & FNF_REV) && sim_tape_bot (uptr)) ||
((dat & FNF_WRT) && sim_tape_wrp (uptr)))
msc_sta = msc_sta | STA_REJ; /* reject? */
break;
@ -445,30 +476,39 @@ switch (inst) { /* case on opcode */
dat = dat | (msc_sta & ~STA_DYN); /* get card status */
if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */
dat = dat | uptr->UST; /* add unit status */
if (sim_tape_bot (uptr)) /* BOT? */
dat = dat | STA_BOT;
if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */
!((uptr->FNC & FNF_RWD) && (uptr->UST & STA_BOT)))
!((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr)))
dat = dat | STA_TBSY;
if (sim_tape_wrp (uptr)) /* write prot? */
dat = dat | STA_WLK;
if (sim_tape_eot (uptr))
if (sim_tape_eot (uptr)) /* EOT? */
dat = dat | STA_EOT;
}
else dat = dat | STA_TBSY | STA_LOCAL;
if (ms_ctype) dat = dat | STA_PE | /* 13183A? */
(msc_usl << STA_V_SEL);
if (DEBUG_PRS (msc_dev))
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", dat);
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { clrCTL (devc); } /* CLC */
else if (!(msc_sta & STA_REJ)) { /* STC, last cmd rejected? */
if ((msc_buf & 0377) == FNC_CLR) { /* clear? */
for (i = 0; i < MS_NUMDR; i++) { /* loop thru units */
if (sim_is_active (&msc_unit[i]) && /* write in prog? */
(msc_unit[i].FNC == FNC_WC) && (ms_ptr > 0)) {
for (i = 0; i < MS_NUMDR; i++) { /* look for write in progr */
if (sim_is_active (&msc_unit[i]) && /* unit active? */
(msc_unit[i].FNC == FNC_WC) && /* last cmd write? */
(ms_ptr > 0)) { /* partial buffer? */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC STC: Unit %d wrote %d word partial record\n",
i, ms_ptr / 2);
if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF))
ms_map_err (uptr, st);
ms_map_err (uptr, st); /* discard any error */
ms_ptr = 0; /* clear partial */
}
if ((msc_unit[i].UST & STA_REW) == 0)
sim_cancel (&msc_unit[i]); /* stop if not rew */
@ -476,34 +516,35 @@ switch (inst) { /* case on opcode */
setCTL (devc); /* set CTL for STC */
setFSR (devc); /* set FLG for completion */
msc_sta = msc_1st = 0; /* clr ctlr status */
if (DEBUG_PRS (msc_dev))
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Controller cleared\n", sim_deb);
return SCPE_OK;
}
uptr->FNC = msc_buf & 0377; /* save function */
if (uptr->FNC & FNF_RWD) { /* rewind? */
if (!(uptr->UST & STA_BOT)) /* not at BOT? */
if (!sim_tape_bot (uptr)) /* not at BOT? */
uptr->UST = STA_REW; /* set rewinding */
sched_time = msc_rtime; /* set response time */
}
else {
if (uptr-> UST & STA_BOT) /* at BOT? */
if (sim_tape_bot (uptr)) /* at BOT? */
sched_time = msc_btime; /* use BOT start time */
else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM))
sched_time = msc_gtime; /* use gap traversal time */
else sched_time = 0;
if (uptr->FNC != FNC_GAP)
sched_time += msc_ctime; /* add base command time */
if (uptr->FNC & FNF_MOT) /* motion command? */
uptr->UST = 0; /* clear BOT status */
}
if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */
sim_activate (uptr, sched_time); /* else schedule op */
if (DEBUG_PRS (msc_dev)) fprintf (sim_deb,
">>MSC STC: Unit %d command %03o scheduled, time = %d\n",
msc_usl, uptr->FNC, sched_time);
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC STC: Unit %d command %03o (%s) scheduled, "
"pos = %d, time = %d\n",
msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC),
uptr->pos, sched_time);
}
else if (DEBUG_PRS (msc_dev))
else if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Unit select (NOP)\n", sim_deb);
msc_sta = STA_BUSY; /* ctrl is busy */
msc_1st = 1;
@ -526,9 +567,17 @@ return dat;
/* Unit service
If rewind done, reposition to start of tape, set status
else, do operation, set done, interrupt
else, do operation, set done, interrupt.
Can't be write locked, can only write lock detached unit
In addition to decreasing the timing intervals, the FASTTIME option enables
two additional optimizations: WFM for GFM substitution, and BOT gap
elimination. If FASTTIME is selected, gap and file mark (GFM) commands are
processed as WFM (write file mark) commands. That is, the preceding GAP is
not performed. Also, the initial gap that normally precedes the first data
record or EOF mark at the beginning of the tape is omitted. These omissions
result in smaller tape image files. If REALTIME is selected, the gaps are
included. Note that the gaps (and realistic timing) are necessary to pass
the 7970 diagnostics.
*/
t_stat msc_svc (UNIT *uptr)
@ -552,7 +601,7 @@ switch (uptr->FNC) { /* case on function */
case FNC_RWS: /* rewind offline */
sim_tape_rewind (uptr); /* rewind tape */
uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */
uptr->UST = STA_BOT; /* BOT when online again */
uptr->UST = 0; /* clear REW status */
break; /* we're done */
case FNC_REW: /* rewind */
@ -564,19 +613,43 @@ switch (uptr->FNC) { /* case on function */
case FNC_REW | FNC_CMPL: /* complete rewind */
sim_tape_rewind (uptr); /* rewind tape */
uptr->UST = STA_BOT; /* set BOT status */
uptr->UST = 0; /* clear REW status */
return SCPE_OK; /* drive is free */
case FNC_GFM: /* gap file mark */
case FNC_GFM: /* gap + file mark */
if (ms_timing == 1) /* fast timing? */
goto DO_WFM; /* do plain file mark */
/* else fall into GAP */
case FNC_GAP: /* erase gap */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote gap\n",
unum);
if ((r = ms_write_gap (uptr)) || /* write tape gap; error? */
(uptr->FNC != FNC_GFM)) /* not GFM? */
break; /* bail out now */
/* else drop into WFM */
case FNC_WFM: /* write file mark */
if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote initial gap\n",
unum);
if (st = ms_write_gap (uptr)) { /* write initial gap; error? */
r = ms_map_err (uptr, st); /* map error */
break; /* terminate operation */
}
}
DO_WFM:
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote file mark\n",
unum);
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
r = ms_map_err (uptr, st); /* map error */
msc_sta = STA_EOF; /* set EOF status */
break;
case FNC_GAP: /* erase gap */
break;
case FNC_FSR: /* space forward */
if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */
r = ms_map_err (uptr, st); /* map error */
@ -606,8 +679,12 @@ switch (uptr->FNC) { /* case on function */
case FNC_RFF: /* diagnostic read */
case FNC_RC: /* read */
if (msc_1st) { /* first svc? */
msc_1st = ms_ptr = 0; /* clr 1st flop */
msc_1st = ms_ptr = ms_max = 0; /* clr 1st flop */
st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d read %d word record\n",
unum, ms_max / 2);
if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR; /* rec in err? */
else if (st != MTSE_OK) { /* other error? */
r = ms_map_err (uptr, st); /* map error */
@ -619,8 +696,6 @@ switch (uptr->FNC) { /* case on function */
break; /* err, done */
}
if (ms_ctype) msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */
if (DEBUG_PRS (msc_dev)) fprintf (sim_deb,
">>MSC svc: Unit %d read %d word record\n", unum, ms_max / 2);
}
if (CTL (devd) && (ms_ptr < ms_max)) { /* DCH on, more data? */
if (FLG (devd)) msc_sta = msc_sta | STA_TIM | STA_PAR;
@ -638,14 +713,29 @@ switch (uptr->FNC) { /* case on function */
else uptr->FNC |= FNC_CMPL; /* set completion */
return SCPE_OK;
case FNC_RFF | FNC_CMPL: /* diagnostic read completion */
case FNC_RC | FNC_CMPL: /* read completion */
break;
case FNC_WC: /* write */
if (msc_1st) msc_1st = ms_ptr = 0; /* no xfer on first */
if (msc_1st) { /* first service? */
msc_1st = ms_ptr = 0; /* no data xfer on first svc */
if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote initial gap\n",
unum);
if (st = ms_write_gap (uptr)) { /* write initial gap; error? */
r = ms_map_err (uptr, st); /* map error */
break; /* terminate operation */
}
}
}
else { /* not 1st, next char */
if (ms_ptr < DBSIZE) { /* room in buffer? */
msxb[ms_ptr] = msd_buf >> 8; /* store 2 char */
msxb[ms_ptr + 1] = msd_buf & 0377;
ms_ptr = ms_ptr + 2;
uptr->UST = 0;
}
else msc_sta = msc_sta | STA_PAR;
}
@ -655,8 +745,10 @@ switch (uptr->FNC) { /* case on function */
return SCPE_OK;
}
if (ms_ptr) { /* any data? write */
if (DEBUG_PRS (msc_dev)) fprintf (sim_deb,
">>MSC svc: Unit %d wrote %d word record\n", unum, ms_ptr / 2);
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote %d word record\n",
unum, ms_ptr / 2);
if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr)) { /* write, err? */
r = ms_map_err (uptr, st); /* map error */
break;
@ -666,31 +758,63 @@ switch (uptr->FNC) { /* case on function */
uptr->FNC |= FNC_CMPL; /* set completion */
return SCPE_OK;
default: /* unknown */
case FNC_WC | FNC_CMPL: /* write completion */
break;
case FNC_RRR: /* not supported */
default: /* unknown command */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC svc: Unit %d command %03o is unknown (NOP)\n",
unum, uptr->FNC);
break;
}
setFSR (devc); /* set cch flg */
msc_sta = msc_sta & ~STA_BUSY; /* update status */
if (DEBUG_PRS (msc_dev)) fprintf (sim_deb,
">>MSC svc: Unit %d command %03o complete\n", unum, uptr->FNC & 0377);
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC svc: Unit %d command %03o (%s) complete\n",
unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC));
return r;
}
/* Write an erase gap */
t_stat ms_write_gap (UNIT *uptr)
{
t_stat st;
uint32 gap_len = ms_ctype ? GAP_13183 : GAP_13181; /* establish gap length */
uint32 tape_bpi = ms_ctype ? BPI_13183 : BPI_13181; /* establish nominal bpi */
if (st = sim_tape_wrgap (uptr, gap_len, tape_bpi)) /* write gap */
return ms_map_err (uptr, st); /* map error if failure */
else
return SCPE_OK;
}
/* Map tape error status */
t_stat ms_map_err (UNIT *uptr, t_stat st)
{
int32 unum = uptr - msc_dev.units; /* get unit number */
if (DEBUG_PRS (msc_dev)) fprintf (sim_deb,
">>MSC err: Unit %d tape library status = %d\n", unum, st);
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC err: Unit %d tape library status = %d\n",
unum, st);
switch (st) {
case MTSE_FMT: /* illegal fmt */
msc_sta = msc_sta | STA_REJ; /* reject cmd */
return SCPE_FMT; /* format error */
case MTSE_UNATT: /* unattached */
msc_sta = msc_sta | STA_REJ; /* reject */
msc_detach (uptr); /* resync status (ignore rtn) */
msc_sta = msc_sta | STA_REJ; /* reject cmd */
return SCPE_UNATT; /* unit unattached */
case MTSE_OK: /* no error */
return SCPE_IERR; /* never get here! */
@ -712,10 +836,6 @@ switch (st) {
msc_sta = msc_sta | STA_PAR; /* error */
break;
case MTSE_BOT: /* reverse into BOT */
msc_sta = msc_sta | STA_BOT; /* set BOT status */
break;
case MTSE_WRP: /* write protect */
msc_sta = msc_sta | STA_REJ; /* reject */
break;
@ -745,9 +865,7 @@ for (i = 0; i < MS_NUMDR; i++) {
uptr = msc_dev.units + i;
sim_tape_reset (uptr);
sim_cancel (uptr);
if ((uptr->flags & UNIT_ATT) && sim_tape_bot (uptr))
uptr->UST = STA_BOT;
else uptr->UST = 0;
uptr->UST = 0;
}
ms_config_timing ();
return SCPE_OK;
@ -760,10 +878,8 @@ t_stat msc_attach (UNIT *uptr, char *cptr)
t_stat r;
r = sim_tape_attach (uptr, cptr); /* attach unit */
if (r == SCPE_OK) {
if (r == SCPE_OK)
uptr->flags = uptr->flags & ~UNIT_OFFLINE; /* set online */
uptr->UST = STA_BOT; /* tape starts at BOT */
}
return r;
}
@ -771,7 +887,7 @@ return r;
t_stat msc_detach (UNIT* uptr)
{
uptr->UST = 0; /* update status */
uptr->UST = 0; /* clear status */
uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */
return sim_tape_detach (uptr); /* detach unit */
}
@ -788,7 +904,7 @@ else return SCPE_UNATT;
void ms_config_timing (void)
{
int32 i, tset;
uint32 i, tset;
tset = (ms_timing << 1) | (ms_timing? 0 : ms_ctype); /* select timing set */
for (i = 0; i < (sizeof (timers) / sizeof (timers[0])); i++)
@ -898,6 +1014,34 @@ if (val == 1) fputc ('\n', st); /* MTAB_NMO omits \n */
return status;
}
/* Translate command to mnemonic for debug logging
The command names and descriptions are taken from the 13181 interface
manual. */
char *ms_cmd_name (uint32 cmd)
{
switch (cmd & 0377) {
case FNC_WC: return "WCC"; /* Write command */
case FNC_WFM: return "WFM"; /* Write file mark */
case FNC_RC: return "RRF"; /* Read record forward */
case FNC_FSR: return "FSR"; /* Forward space record */
case FNC_FSF: return "FSF"; /* Forward space file */
case FNC_GAP: return "GAP"; /* Write gap */
case FNC_BSR: return "BSR"; /* Backspace record */
case FNC_BSF: return "BSF"; /* Backspace file */
case FNC_REW: return "REW"; /* Rewind */
case FNC_RWS: return "RWO"; /* Rewind off-line */
case FNC_CLR: return "CLR"; /* Clear controller */
case FNC_GFM: return "GFM"; /* Gap file mark */
case FNC_RFF: return "RFF"; /* Read forward until file mark (diag) */
case FNC_RRR: return "RRR"; /* Read record in reverse (diag) */
default: return "???"; /* Unknown command */
}
}
/* 7970B/7970E bootstrap routine (HP 12992D ROM) */
const uint16 ms_rom[IBL_LNT] = {

View file

@ -1,6 +1,6 @@
/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator
Copyright (c) 1993-2004, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
mt 12559A 3030 nine track magnetic tape
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
07-Oct-04 JDB Allow enable/disable from either device
14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan)
06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan)
@ -243,6 +244,7 @@ switch (inst) { /* case on opcode */
dat = mtc_unit.buf;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) mtc_dtf = 0; /* CLC: clr xfer flop */
break;
@ -257,7 +259,8 @@ return dat;
int32 mtcio (int32 inst, int32 IR, int32 dat)
{
int32 i, devc, devd, valid;
uint32 i;
int32 devc, devd, valid;
t_stat st;
devc = IR & I_DEVMASK; /* get device no */
@ -325,6 +328,7 @@ switch (inst) { /* case on opcode */
else dat = dat | STA_BUSY | STA_LOCAL;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { clrCTL (devc); } /* CLC */
else { setCTL (devc); } /* STC */

View file

@ -1,6 +1,6 @@
/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator
Copyright (c) 2002-2005, Robert M Supnik
Copyright (c) 2002-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
mux,muxl,muxc 12920A terminal multiplexor
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
02-Jun-06 JDB Fixed compiler warning for mux_ldsc init
22-Nov-05 RMS Revised for new terminal processing routines
29-Jun-05 RMS Added SET MUXLn DISCONNECT
07-Oct-04 JDB Allow enable/disable from any device
@ -157,7 +159,7 @@ uint32 muxu_obuf = 0; /* upr out: chan */
uint32 muxc_chan = 0; /* ctrl chan */
uint32 muxc_scan = 0; /* ctrl scan */
TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */
TMLN mux_ldsc[MUX_LINES] = { { 0 } }; /* line descriptors */
TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc }; /* mux descriptor */
DEVICE muxl_dev, muxu_dev, muxc_dev;
@ -393,6 +395,7 @@ switch (inst) { /* case on opcode */
dat = muxl_ibuf;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
else { /* STC */
@ -503,6 +506,7 @@ switch (inst) { /* case on opcode */
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* ctrl clear/set */
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
else { setCTL (dev); } /* STC */

View file

@ -1,6 +1,6 @@
/* hp2100_stddev.c: HP2100 standard devices simulator
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -28,6 +28,7 @@
tty 12531C buffered teleprinter interface
clk 12539C time base generator
28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
22-Nov-05 RMS Revised for new terminal processing routines
13-Sep-04 JDB Added paper tape loop mode, DIAG/READER modifiers to PTR
Added PV_LEFT to PTR TRLLIM register
@ -383,6 +384,7 @@ switch (inst) { /* case on opcode */
dat = ptr_unit.buf;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear cmd, ctl */
@ -560,6 +562,7 @@ switch (inst) { /* case on opcode */
ptp_unit.buf = dat;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear cmd, ctl */
@ -645,6 +648,7 @@ switch (inst) { /* case on opcode */
tty_buf = dat & 0377;
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
else { /* STC */
@ -783,9 +787,9 @@ t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc)
int32 u = uptr - tty_dev.units;
if (u > TTO) return SCPE_NOFNC;
tty_unit[TTO].flags = (tty_unit[TTO].flags & ~TT_MODE) | val;
if (val == TT_MODE_7P) val = TT_MODE_7B;
tty_unit[TTI].flags = (tty_unit[TTI].flags & ~TT_MODE) | val;
if ((u == TTI) && (val == TT_MODE_7P))
val = TT_MODE_7B;
tty_unit[u].flags = (tty_unit[u].flags & ~TT_MODE) | val;
return SCPE_OK;
}
@ -832,6 +836,7 @@ switch (inst) { /* case on opcode */
clrCTL (dev); /* clear control */
break;
case ioCRS: /* control reset (action unverif) */
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCTL (dev); /* turn off clock */

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
21-Dec-06 JDB Added "fwanxm" external for sim_load check
19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF messages
25-Sep-04 JDB Added memory protect device
Fixed display of CCA/CCB/CCE instructions
@ -61,6 +62,7 @@ extern DEVICE muxl_dev, muxu_dev, muxc_dev;
extern DEVICE ipli_dev, iplo_dev;
extern REG cpu_reg[];
extern uint16 *M;
extern uint32 fwanxm;
/* SCP data structures and interface routines

View file

@ -1569,7 +1569,8 @@ int32 a, b, c, r;
c = 0; /* init carry */
do {
a = M[ap]; b = M[bp]; /* get operands */
a = M[ap]; /* get operands */
b = M[bp];
r = bcd_to_bin[b & DIGIT] + /* sum digits + c */
bcd_to_bin[a & DIGIT] + c;
c = (r >= 10); /* set carry out */
@ -1671,8 +1672,10 @@ for (i = 0; i < 64; i++) { /* clr indicators */
if ((i < IN_SSB) || (i > IN_SSG)) ind[i] = 0; /* except SSB-SSG */
}
ind[IN_UNC] = 1; /* ind[0] always on */
AS = 0; as_err = 1; /* clear AS */
BS = 0; bs_err = 1; /* clear BS */
AS = 0; /* clear AS */
BS = 0; /* clear BS *
as_err = 1;
bs_err = 1;/
D = 0; /* clear D */
hb_pend = 0; /* no halt br */
pcq_r = find_reg ("ISQ", NULL, dptr);

View file

@ -25,6 +25,8 @@
cpu 7094 central processor
29-Oct-06 RMS Added additional expanded core instructions
17-Oct-06 RMS Fixed the fix in halt IO wait loop
16-Jun-06 RMS Fixed bug in halt IO wait loop
The register state for the 7094 is:
@ -1576,11 +1578,22 @@ while (reason == SCPE_OK) { /* loop until error */
reason = op_mse (ea);
break;
case 01761: /* (CTSS) SEA, SEB */
case 01761: /* (CTSS) ext core */
if (prot_trap (0)) break; /* user mode? */
if (ea == 041) data_base = 0;
else if (ea == 042) data_base = BCORE_BASE;
else if (stop_illop) reason = STOP_ILLEG;
if (ea == 041) /* SEA? */
data_base = 0;
else if (ea == 042) /* SEB? */
data_base = BCORE_BASE;
else if (ea == 043) { /* IFT? */
if (inst_base == 0)
PC = (PC + 1) & eamask;
}
else if (ea == 044) { /* EFT? */
if (data_base == 0)
PC = (PC + 1) & eamask;
}
else if (stop_illop)
reason = STOP_ILLEG;
break;
case 01763: /* LGL */
@ -1775,7 +1788,7 @@ while (reason == SCPE_OK) { /* loop until error */
if (r = sim_process_event ()) return r; /* process events */
chtr_pend = chtr_eval (NULL); /* eval chan traps */
while (ch_req) { /* until no ch req */
for (j = 0; i < NUM_CHAN; j++) { /* loop thru channels */
for (j = 0; j < NUM_CHAN; j++) { /* loop thru channels */
if (ch_req & REQ_CH (j)) { /* channel request? */
if (r = ch_proc (j)) return r;
}

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
29-Oct-06 RMS Added additional expanded core instructions
08-Jun-06 RMS Added Dave Pitts' binary loader
*/
@ -362,6 +363,7 @@ static const char *opcode[] = {
"TIA", "TIB",
"LRI", "LPI",
"SEA", "SEB",
"IFT", "EFT",
"IOCD", "IOCDN", "TCH",
"IORP", "IORPN",
@ -523,6 +525,7 @@ static const t_uint64 opc_v[] = {
0010100000000+I_MXN, 0410100000000+I_MXN,
0056200000000+I_MXN, 0456400000000+I_MXN,
0476100000041+I_SNS, 0476100000042+I_SNS,
0476100000043+I_SNS, 0476100000044+I_SNS,
01000000000000+I_IOX, 01000000200000+I_IOX, 01100000000000+I_TCH,
01200000000000+I_IOX, 01200000200000+I_IOX,

View file

@ -1,4 +1,4 @@
// DMS R2V12 SLET without RPG, for debugging only
/* DMS R2V12 SLET without RPG, for debugging only */
0x0001, 0x7c50, 0x032f, 0x0008,
0x0002, 0x11de, 0x05a2, 0x000b,

View file

@ -9,15 +9,17 @@
* Mail to sim@ibm1130.org
*/
// 03 ctrl-C => Program stop (not handled here)
// 05 ctrl-E => Simulator stop (not handled here)
// 08 ctrl-H => Backspace
// 0D ctrl-M (Enter) => EOF
// 11 ctrl-Q => Interrupt request (not handled here)
// 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard)
// 15 ctrl-U => Erase Field
// 7E ~ => "not"
// FF Del => Backspace again
/*
* 03 ctrl-C => Program stop (not handled here)
* 05 ctrl-E => Simulator stop (not handled here)
* 08 ctrl-H => Backspace
* 0D ctrl-M (Enter) => EOF
* 11 ctrl-Q => Interrupt request (not handled here)
* 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard)
* 15 ctrl-U => Erase Field
* 7E ~ => "not"
* FF Del => Backspace again
*/
static uint16 ascii_to_conin[] = /* ASCII to ((hollerith << 4) | special key flags) */
{

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -27,11 +27,11 @@
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
#ifndef _WIN32
int strnicmp (char *a, char *b, int n);
int strcmpi (char *a, char *b);
int strnicmp (const char *a, const char *b, int n);
int strcmpi (const char *a, const char *b);
#endif
// #define GUI_SUPPORT // uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile
/* #define GUI_SUPPORT uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile */
/* ------------------------------------------------------------------------ */
/* Architectural constants */
@ -40,14 +40,13 @@
#define INIMEMSIZE (16384) /* 16Kwords */
#define MEMSIZE (cpu_unit.capac)
#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* flag for memory size setting */
#define ILL_ADR_FLAG 0x40000000 /* an impossible 1130 address */
/* ------------------------------------------------------------------------ */
/* Global state */
extern int cgi; // TRUE if we are running as a CGI program
extern int cgi; /* TRUE if we are running as a CGI program */
extern int cgiwritable; /* TRUE if we can write the disk images back to the image file in CGI mode */
extern int sim_gui;
extern uint16 M[]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */
@ -58,6 +57,7 @@ extern int32 SAR, SBR; /* storage address/buffer registers */
extern int32 OP, TAG, CCC; /* instruction decoded pieces */
extern int32 CES; /* console entry switches */
extern int32 ACC, EXT; /* accumulator and extension */
extern int32 ARF; /* arithmetic factor register, a nonaddressable internal CPU register */
extern int32 RUNMODE; /* processor run/step mode */
extern int32 ipl; /* current interrupt level (-1 = not handling irq) */
extern int32 iplpending; /* interrupted IPL's */
@ -71,9 +71,11 @@ extern int32 int_mask; /* current active interrupt mask (ipl sensitive) */
extern int32 mem_mask;
extern int32 cpu_dsw; /* CPU device status word */
extern int32 sim_int_char; /* interrupt character */
extern int32 con_dsw; /* has program stop and int run bits */
extern t_bool running;
extern t_bool power;
extern t_bool cgi; /* TRUE if we are running as a CGI program */
extern t_bool cgiwritable; /* TRUE if we can write to the disk image file in CGI mode */
extern t_stat reason; /* CPU execution loop control */
#define WAIT_OP 1 /* wait state causes: wait instruction, invalid instruction*/
@ -131,15 +133,19 @@ void WriteW (int32 a, int32 d);
#define STOP_PHASE_BREAK 7 /* phase load break */
#define STOP_CRASH 8 /* program has crashed badly */
#define STOP_TIMED_OUT 9 /* simulation time limit exceeded */
#define STOP_IMMEDIATE 10 /* simulator stop key pressed (immediate stop) */
#define STOP_BREAK 11 /* simulator break key pressed */
#define STOP_STEP 12 /* step count expired */
#define STOP_OTHER 13 /* other reason, probably error returned by sim_process_event() */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
#define INT_REQ_0 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */
#define INT_REQ_1 0x02
#define INT_REQ_2 0x04
#define INT_REQ_3 0x08
#define INT_REQ_4 0x10
#define INT_REQ_5 0x20
#define INT_REQ_5 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */
#define INT_REQ_4 0x02
#define INT_REQ_3 0x04
#define INT_REQ_2 0x08
#define INT_REQ_1 0x10
#define INT_REQ_0 0x20
#define XIO_UNUSED 0x00 /* XIO commands */
#define XIO_WRITE 0x01
@ -156,7 +162,7 @@ void WriteW (int32 a, int32 d);
#define ILSW_0_1442_CARD 0x8000 /* ILSW 0 is not really defined on the 1130 */
#define ILSW_1_1132_PRINTER 0x8000 // had these backwards!
#define ILSW_1_1132_PRINTER 0x8000 /* had these backwards! */
#define ILSW_1_SCA 0x4000
#define ILSW_2_1131_DISK 0x8000
@ -215,13 +221,13 @@ void WriteW (int32 a, int32 d);
#define ILSW_4_SAC_BIT_09 0x0040
#define ILSW_4_SAC_BIT_10 0x0020
#define ILSW_4_SAC_BIT_11 0x0010
#define ILSW_4_T2741_TERMINAL 0x0010 /* APL\1130 nonstandard serial interface uses this bit */
#define ILSW_4_SAC_BIT_12 0x0008
#define ILSW_4_SAC_BIT_13 0x0004
#define ILSW_4_SAC_BIT_14 0x0002
#define ILSW_4_SAC_BIT_15 0x0001
#define ILSW_5_INT_RUN 0x8000
#define ILSW_5_PROGRAM_STOP 0x8000
#define ILSW_5_INT_RUN_PROGRAM_STOP 0x8000 /* this replaces both ILSW_5_INT_RUN and ILSW_5_PROGRAM_STOP */
#define ILSW_5_SAC_BIT_01 0x4000
#define ILSW_5_SAC_BIT_02 0x2000
#define ILSW_5_SAC_BIT_03 0x1000
@ -238,26 +244,27 @@ void WriteW (int32 a, int32 d);
#define ILSW_5_SAC_BIT_14 0x0002
#define ILSW_5_SAC_BIT_15 0x0001
//* CPU DSW bits
/* CPU DSW bits */
#define CPU_DSW_PROGRAM_STOP 0x8000
#define CPU_DSW_INT_RUN 0x4000
/* prototypes: xio handlers */
void xio_1131_console (int32 addr, int32 func, int32 modify); // console keyboard and printer
void xio_1142_card (int32 addr, int32 func, int32 modify); // standard card reader/punch
void xio_1134_papertape (int32 addr, int32 func, int32 modify); // paper tape reader/punch
void xio_disk (int32 addr, int32 func, int32 modify, int drv); // internal CPU disk
void xio_1627_plotter (int32 addr, int32 func, int32 modify); // XY plotter
void xio_1132_printer (int32 addr, int32 func, int32 modify); // standard line printer
void xio_1131_switches (int32 addr, int32 func, int32 modify); // console buttons & switches
void xio_1231_optical (int32 addr, int32 func, int32 modify); // optical mark page reader
void xio_2501_card (int32 addr, int32 func, int32 modify); // alternate high-speed card reader
void xio_1131_synch (int32 addr, int32 func, int32 modify); // synchronous communications adapter
void xio_system7 (int32 addr, int32 func, int32 modify); // system/7 interprocessor IO link
void xio_1403_printer (int32 addr, int32 func, int32 modify); // alternate high-speed printer
void xio_2250_display (int32 addr, int32 func, int32 modify); // vector display processor
void xio_1131_console (int32 addr, int32 func, int32 modify); /* console keyboard and printer */
void xio_1142_card (int32 addr, int32 func, int32 modify); /* standard card reader/punch */
void xio_1134_papertape (int32 addr, int32 func, int32 modify); /* paper tape reader/punch */
void xio_disk (int32 addr, int32 func, int32 modify, int drv); /* internal CPU disk */
void xio_1627_plotter (int32 addr, int32 func, int32 modify); /* XY plotter */
void xio_1132_printer (int32 addr, int32 func, int32 modify); /* standard line printer */
void xio_1131_switches (int32 addr, int32 func, int32 modify); /* console buttons & switches */
void xio_1231_optical (int32 addr, int32 func, int32 modify); /* optical mark page reader */
void xio_2501_card (int32 addr, int32 func, int32 modify); /* alternate high-speed card reader */
void xio_sca (int32 addr, int32 func, int32 modify); /* synchronous communications adapter */
void xio_system7 (int32 addr, int32 func, int32 modify); /* system/7 interprocessor IO link */
void xio_1403_printer (int32 addr, int32 func, int32 modify); /* alternate high-speed printer */
void xio_2250_display (int32 addr, int32 func, int32 modify); /* vector display processor */
void xio_t2741_terminal (int32 addr, int32 func, int32 modify); /* IO selectric via nonstandard serial interface for APL */
void xio_error (char *msg);
void bail (char *msg);
@ -267,6 +274,8 @@ t_stat cr_rewind (void);
t_stat cr_detach (UNIT *uptr);
void calc_ints (void); /* recalculate interrupt bitmask */
void trace_io (char *fmt, ...); /* debugging printout */
void trace_both (char *fmt, ...); /* debugging printout */
t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help);
void scp_panic (char *msg); /* bail out of simulator */
char *upcase(char *str);
void break_simulation (t_stat reason); /* let a device halt the simulation */

View file

@ -14,6 +14,13 @@ commands may NOT be accurate. This should probably be fixed.
* or modifications.
*
* Revision History
* 05-dec-06 Added cgiwritable mode
*
* 19-Dec-05 We no longer issue an operation complete interrupt if an INITR, INITW
* or CONTROL operation is attemped on a drive that is not online. DATA_ERROR
* is now only indicated in the DSW when
*
* 02-Nov-04 Addes -s option to boot to leave switches alone.
* 15-jun-03 moved actual read on XIO read to end of time interval,
* as the APL boot card required 2 instructions to run between the
* time read was initiated and the time the data was read (a jump and a wait)
@ -29,7 +36,7 @@ commands may NOT be accurate. This should probably be fixed.
#include "ibm1130_defs.h"
#include "memory.h"
#define TRACE_DMS_IO // define to enable debug of DMS phase IO
#define TRACE_DMS_IO /* define to enable debug of DMS phase IO */
#ifdef TRACE_DMS_IO
extern int32 sim_switches;
@ -86,7 +93,7 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr);
static t_stat dsk_detach (UNIT *uptr);
static t_stat dsk_boot (int unitno, DEVICE *dptr);
static void diskfail (UNIT *uptr, int errflag);
static void diskfail (UNIT *uptr, int dswflag, int unitflag, t_bool do_interrupt);
/* DSK data structures
@ -180,16 +187,17 @@ extern void void_backtrace (int afrom, int ato);
void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
{
int i, rev, nsteps, newcyl, sec, nwords;
uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development
uint32 newpos; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */
char msg[80];
UNIT *uptr = dsk_unit+drv;
int16 buf[DSK_NUMWD];
if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { // hmmm, invalid drive */
if (func != XIO_SENSE_DEV) { // tried to use it, too
// just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads
// sprintf(msg, "Op %x on invalid drive number %d", func, drv);
// xio_error(msg);
if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { /* hmmm, invalid drive */
if (func != XIO_SENSE_DEV) { /* tried to use it, too */
/* just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads
sprintf(msg, "Op %x on invalid drive number %d", func, drv);
xio_error(msg);
*/
}
return;
}
@ -199,7 +207,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
switch (func) {
case XIO_INITR:
if (! IS_ONLINE(uptr)) { /* disk is offline */
diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */
diskfail(uptr, 0, 0, FALSE);
break;
}
@ -219,11 +227,12 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
sec = modify & 0x07; /* get sector on cylinder */
if ((modify & 0x0080) == 0) { /* it's a real read if it's not a read check */
// ah. We have a problem. The APL boot card counts on there being time for at least one
// more instruction to execute between the XIO read and the time the data starts loading
// into core. So, we have to defer the actual read operation a bit. Might as well wait
// until it's time to issue the operation complete interrupt. This means saving the
// IO information, then performing the actual read in dsk_svc.
/* ah. We have a problem. The APL boot card counts on there being time for at least one
* more instruction to execute between the XIO read and the time the data starts loading
* into core. So, we have to defer the actual read operation a bit. Might as well wait
* until it's time to issue the operation complete interrupt. This means saving the
* IO information, then performing the actual read in dsk_svc.
*/
newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD;
@ -248,12 +257,12 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
case XIO_INITW:
if (! IS_ONLINE(uptr)) { /* disk is offline */
diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */
diskfail(uptr, 0, 0, FALSE);
break;
}
if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error */
diskfail(uptr, UNIT_HARDERR);
if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error until disk is powered off/on */
diskfail(uptr, DSK_DSW_DATA_ERROR, UNIT_HARDERR, FALSE);
break;
}
@ -312,7 +321,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
case XIO_CONTROL: /* step fwd/rev */
if (! IS_ONLINE(uptr)) {
diskfail(uptr, UNIT_HARDERR);
diskfail(uptr, 0, 0, FALSE);
break;
}
@ -364,11 +373,16 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
/* diskfail - schedule an operation complete that sets the error bit */
static void diskfail (UNIT *uptr, int errflag)
static void diskfail (UNIT *uptr, int dswflag, int unitflag, t_bool do_interrupt)
{
int drv = uptr - dsk_unit;
sim_cancel(uptr); /* cancel any pending ops */
SETBIT(uptr->flags, errflag); /* set the error flag */
SETBIT(dsk_dsw[drv], dswflag); /* set any specified DSW bits */
SETBIT(uptr->flags, unitflag); /* set any specified unit flag bits */
uptr->FUNC = DSK_FUNC_FAILED; /* tell svc routine why it failed */
if (do_interrupt)
sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */
}
@ -376,7 +390,7 @@ t_stat dsk_svc (UNIT *uptr)
{
int drv = uptr - dsk_unit, i, nwords, sec;
int16 buf[DSK_NUMWD];
uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development
uint32 newpos; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */
int32 iocc_addr;
if (uptr->FUNC == DSK_FUNC_IDLE) /* service function called with no activity? not good, but ignore */
@ -415,16 +429,16 @@ t_stat dsk_svc (UNIT *uptr)
dsk_lastio[drv] = IO_READ;
uptr->pos = newpos;
}
fxread(buf, 2, DSK_NUMWD, uptr->fileref); // read whole sector so we're in position for next read
fxread(buf, 2, DSK_NUMWD, uptr->fileref); /* read whole sector so we're in position for next read */
uptr->pos = newpos + 2*DSK_NUMWD;
}
void_backtrace(iocc_addr, iocc_addr + nwords - 1); // mark prev instruction as altered
void_backtrace(iocc_addr, iocc_addr + nwords - 1); /* mark prev instruction as altered */
trace_io("* DSK%d read %d words from %d.%d (%x, %x) to M[%04x-%04x]", drv, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask,
(iocc_addr + nwords - 1) & mem_mask);
// // this will help debug the monitor by letting me watch phase loading
/* this will help debug the monitor by letting me watch phase loading */
if (raw_disk_debug)
printf("* DSK%d XIO @ %04x read %d words from %d.%d (%x, %x) to M[%04x-%04x]\n", drv, prev_IAR, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask,
(iocc_addr + nwords - 1) & mem_mask);
@ -448,7 +462,7 @@ t_stat dsk_svc (UNIT *uptr)
}
uptr->FUNC = DSK_FUNC_IDLE; // we're done with this operation
uptr->FUNC = DSK_FUNC_IDLE; /* we're done with this operation */
return SCPE_OK;
}
@ -459,8 +473,8 @@ t_stat dsk_reset (DEVICE *dptr)
UNIT *uptr;
#ifdef TRACE_DMS_IO
// add the WHERE command. It finds the phase that was loaded at given address and indicates
// the offset in the phase
/* add the WHERE command. It finds the phase that was loaded at given address and indicates */
/* the offset in the phase */
register_cmd("WHERE", &where_cmd, 0, "w{here} address find phase and offset of an address\n");
register_cmd("PHDEBUG", &phdebug_cmd, 0, "ph{debug} off|phlo phhi break on phase load\n");
register_cmd("FDUMP", &fdump_cmd, 0, NULL);
@ -487,14 +501,14 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr)
int drv = uptr - dsk_unit;
t_stat rval;
sim_cancel(uptr); // cancel current IO
sim_cancel(uptr); /* cancel current IO */
dsk_lastio[drv] = IO_NONE;
if (uptr->flags & UNIT_ATT) // dismount current disk
if (uptr->flags & UNIT_ATT) /* dismount current disk */
if ((rval = dsk_detach(uptr)) != SCPE_OK)
return rval;
uptr->CYL = 0; // reset the device
uptr->CYL = 0; /* reset the device */
uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME;
@ -502,18 +516,18 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr)
CLRBIT(ILSW[2], dsk_ilswbit[drv]);
calc_ints();
if (sim_switches & SWMASK('M')) // if memory mode (e.g. for CGI), buffer the file
SETBIT(uptr->flags, UNIT_BUFABLE);
if (sim_switches & SWMASK('M')) /* if memory mode (e.g. for CGI), buffer the file */
SETBIT(uptr->flags, UNIT_BUFABLE|UNIT_MUSTBUF);
if (sim_switches & SWMASK('R')) // read lock mode
if (sim_switches & SWMASK('R')) /* read lock mode */
SETBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_RONLY);
if (cgi && (sim_switches & SWMASK('M'))) { // if cgi and memory mode,
sim_switches |= SWMASK('R'); // have attach_unit open file in readonly mode
SETBIT(uptr->flags, UNIT_ROABLE|UNIT_MUSTBUF); // but don't set the UNIT_RONLY flag so DMS can write to the buffered image
if (cgi && (sim_switches & SWMASK('M')) && ! cgiwritable) { /* if cgi and memory mode, but writable option not specified */
sim_switches |= SWMASK('R'); /* have attach_unit open file in readonly mode */
SETBIT(uptr->flags, UNIT_ROABLE); /* but don't set the UNIT_RONLY flag so DMS can write to the buffered image */
}
if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK) { // mount new disk
if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK) { /* mount new disk */
SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY);
return rval;
}
@ -555,7 +569,7 @@ static t_stat dsk_detach (UNIT *uptr)
return SCPE_OK;
}
// boot routine - if they type BOOT DSK, load the standard boot card.
/* boot routine - if they type BOOT DSK, load the standard boot card. */
static t_stat dsk_boot (int unitno, DEVICE *dptr)
{
@ -585,7 +599,7 @@ struct tag_slet {
int16 nwords;
int16 sector;
} slet[MAXSLET] = {
# include "dmsr2v12slet.h" // without RPG, use this info until overwritten by actual data from disk
# include "dmsr2v12slet.h" /* without RPG, use this info until overwritten by actual data from disk */
};
#pragma pack()
@ -599,7 +613,7 @@ int nseg = 0;
static void enable_dms_tracing (int newsetting)
{
nseg = 0; // clear the segment map
nseg = 0; /* clear the segment map */
if ((newsetting && trace_dms) || ! (newsetting || trace_dms))
return;
@ -678,7 +692,7 @@ static t_stat where_cmd (int flag, char *ptr)
return SCPE_OK;
}
// savesector - save info on a sector just read. THIS IS NOT YET TESTED
/* savesector - save info on a sector just read. THIS IS NOT YET TESTED */
static void addseg (int i)
{
@ -713,14 +727,14 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
if (! trace_dms)
return;
addr++; // first word is sector address, so account for that
addr++; /* first word is sector address, so account for that */
len--;
for (i = 0; i < nseg; i++) {
if (addr >= (mseg[i].addr+mseg[i].len)) // entirely after this entry
if (addr >= (mseg[i].addr+mseg[i].len)) /* entirely after this entry */
continue;
if (mseg[i].addr < addr) { // old one starts before this. split it
if (mseg[i].addr < addr) { /* old one starts before this. split it */
addseg(i);
mseg[i].len = addr-mseg[i].addr;
i++;
@ -731,7 +745,7 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
break;
}
addseg(i); // add new segment. Old one ends up after this
addseg(i); /* add new segment. Old one ends up after this */
if (i >= MAXMSEG)
return;
@ -742,12 +756,12 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
mseg[i].len = len;
mseg[i].name = name;
i++; // delete any segments completely covered
i++; /* delete any segments completely covered */
while (i < nseg && (mseg[i].addr+mseg[i].len) <= (addr+len))
delseg(i);
if (i < nseg && mseg[i].addr < (addr+len)) { // old one extends past this. Retain the end
if (i < nseg && mseg[i].addr < (addr+len)) { /* old one extends past this. Retain the end */
mseg[i].len = (mseg[i].addr+mseg[i].len) - (addr+len);
mseg[i].addr = addr+len;
}
@ -755,19 +769,19 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
static void tracesector (int iswrite, int nwords, int addr, int sector)
{
int i, phid = 0, sletind = -1, offset = 0;
int i, phid = 0, offset = 0;
char *name = NULL;
if (nwords < 3 || ! trace_dms)
return;
switch (sector) { // explicitly known sector name
switch (sector) { /* explicitly known sector name */
case 0: name = "ID/COLD START"; break;
case 1: name = "DCOM"; break;
case 2: name = "RESIDENT IMAGE"; break;
case 3:
case 4:
case 5: name = "SLET"; // save just-read or written SLET info
case 5: name = "SLET"; /* save just-read or written SLET info */
memmove(&slet[(320/4)*(sector-3)], &M[addr+1], nwords*2);
break;
case 6: name = "RELOAD TABLE"; break;
@ -777,9 +791,9 @@ static void tracesector (int iswrite, int nwords, int addr, int sector)
printf("* %04x: %3d /%04x %c %3d.%d ",
prev_IAR, nwords, addr, iswrite ? 'W' : 'R', sector/8, sector%8);
if (name == NULL) { // look up sector in SLET
if (name == NULL) { /* look up sector in SLET */
for (i = 0; i < MAXSLET; i++) {
if (slet[i].phid == 0) // not found
if (slet[i].phid == 0) /* not found */
goto done;
else if (slet[i].sector > sector) {
if (--i >= 0) {
@ -792,17 +806,17 @@ static void tracesector (int iswrite, int nwords, int addr, int sector)
goto done;
}
if (slet[i].sector == sector) {
phid = slet[i].phid; // we found the starting sector
phid = slet[i].phid; /* we found the starting sector */
break;
}
}
if (i >= MAXSLET) // was not found
if (i >= MAXSLET) /* was not found */
goto done;
name = "?";
for (i = sizeof(phase)/sizeof(phase[0]); --i >= 0; ) {
if (phase[i].phid == phid) { // look up name
if (phase[i].phid == phid) { /* look up name */
name = phase[i].name;
break;
}
@ -816,7 +830,7 @@ done:
putchar('\n');
if (phid >= phdebug_lo && phid <= phdebug_hi && offset == 0)
break_simulation(STOP_PHASE_BREAK); // break on read of first sector of indicated phases
break_simulation(STOP_PHASE_BREAK); /* break on read of first sector of indicated phases */
if (name != NULL && *name != '?' && ! iswrite)
savesector(addr, offset, nwords, phid, name);
@ -824,12 +838,12 @@ done:
static t_stat fdump_cmd (int flags, char *cptr)
{
int addr = 0x7a24; // address of next statement;
int addr = 0x7a24; /* address of next statement */
int sofst = 0x7a26, symaddr;
int cword, nwords, stype, has_stnum, strel = 1, laststno = 0;
addr = M[addr & mem_mask] & mem_mask; // get address of first statement
sofst = M[sofst & mem_mask] & mem_mask; // get address of symbol table
addr = M[addr & mem_mask] & mem_mask; /* get address of first statement */
sofst = M[sofst & mem_mask] & mem_mask ; /* get address of symbol table */
for (;;) {
cword = M[addr];
@ -851,7 +865,7 @@ static t_stat fdump_cmd (int flags, char *cptr)
printf(" [%04x %04x %04x]", M[symaddr], M[symaddr+1], M[symaddr+2]);
}
if (stype == 0x5000) { // error record
if (stype == 0x5000) { /* error record */
printf(" (err %d)", M[addr+1]);
}
@ -872,4 +886,4 @@ static t_stat fdump_cmd (int flags, char *cptr)
return SCPE_OK;
}
#endif // TRACE_DMS_IO
#endif /* TRACE_DMS_IO */

View file

@ -1,60 +1,61 @@
// ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source
// Bob Flanders
// -------------------------------------------------------------------------------------------
//
// These routines are used by ibm1130_cr.c when the user has indicated
// that the input text is formatted with tabs. Input lines are edited
// into the appropriate column format. Three edit modes are recognized:
//
// Assembler mode:
// Input lines of the form
//
// [label]<whitespace>[opcode]<tab>[tag][L]<tab>[argument]
//
// are rearranged so that the input fields are placed in the appropriate columns
//
// The label must start on the first character of the line. If there is no label,
// the first character(s) before the opcode must be whitespace. Following the opcode, there
// MUST be a tab character, followed by the format and tag. Following the format and tag
// may be exactly one whitespace character, and then starts the argument.
//
// Input lines with * in column 1 and blank lines are turned into Assembler comments,
// with the * in the Opcode field.
//
// Assembler directive lines at the beginning of the deck must be preceded by
// ! to indicate that they are not comments. For example,
//
// !*LIST
// * This is a comment
//
// Fortran mode:
// Input lines of the form
//
// [label]<tab>statement
//
// or
//
// [label]<tab>Xcontinuation
//
// where X is a non alphabetic contination character are rearranged in the
// appropriate manner:
//
// 1 2
// 12345678901234567890...
// ------------------------
// label statement
// labelXcontinuation
//
// However, you must take care that you don't end up with statement text after column 72.
//
// Input lines with * or C in column 1 are left alone (comments and directives)
//
// (The ! escape is not used before Fortran directives as before Assembler directives)
//
// Tab mode:
// Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide,
// as is standard for vi, notepad, etc.
// -------------------------------------------------------------------------------------------
/*********************************************************************************************
* ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source
* Bob Flanders
* -------------------------------------------------------------------------------------------
*
* These routines are used by ibm1130_cr.c when the user has indicated
* that the input text is formatted with tabs. Input lines are edited
* into the appropriate column format. Three edit modes are recognized:
*
* Assembler mode:
* Input lines of the form
*
* [label]<whitespace>[opcode]<tab>[tag][L]<tab>[argument]
*
* are rearranged so that the input fields are placed in the appropriate columns
*
* The label must start on the first character of the line. If there is no label,
* the first character(s) before the opcode must be whitespace. Following the opcode, there
* MUST be a tab character, followed by the format and tag. Following the format and tag
* may be exactly one whitespace character, and then starts the argument.
*
* Input lines with * in column 1 and blank lines are turned into Assembler comments,
* with the * in the Opcode field.
*
* Assembler directive lines at the beginning of the deck must be preceded by
* ! to indicate that they are not comments. For example,
*
* !*LIST
* * This is a comment
*
* Fortran mode:
* Input lines of the form
*
* [label]<tab>statement
*
* or
*
* [label]<tab>Xcontinuation
*
* where X is a non alphabetic contination character are rearranged in the
* appropriate manner:
*
* 1 2
* 12345678901234567890...
* ------------------------
* label statement
* labelXcontinuation
*
* However, you must take care that you don't end up with statement text after column 72.
*
* Input lines with * or C in column 1 are left alone (comments and directives)
*
* (The ! escape is not used before Fortran directives as before Assembler directives)
*
* Tab mode:
* Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide,
* as is standard for vi, notepad, etc.
*********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
@ -63,10 +64,10 @@
#include <string.h>
#include "ibm1130_fmt.h"
#define MAXLINE 81 // maximum output line size
#define WORKSZ 256 // size for tab work area
#define TAGOFFSET 12 // offset for tag field
#define FMTOFFSET 11 // offset for format field
#define MAXLINE 81 /* maximum output line size */
#define WORKSZ 256 /* size for tab work area */
#define TAGOFFSET 12 /* offset for tag field */
#define FMTOFFSET 11 /* offset for format field */
#define MIN(a,b) ((a < b) ? a : b)
#define AMSG " with Assembler Reformat"
@ -77,225 +78,234 @@
#define FFORMAT "%-5.5s %-74.74s"
#define FCONTFMT "%-5.5s%-75.75s"
char gszLabel[6]; // work area for label
char gszArg[MAXLINE]; // .. argument
char gszOutput[MAXLINE]; // .. output
short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};// tab stops for assembler
char gszLabel[6]; /* work area for label */
char gszArg[MAXLINE]; /* .. argument */
char gszOutput[MAXLINE]; /* .. output */
short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};/* tab stops for assembler */
short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};// tab stops for just plain tabs
short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};/* tab stops for just plain tabs */
// ///////////////
// helper routines
/*
* helper routines
*/
///////////////////////////////////////////////////
// ExpandTabs: Expand tabs to spaces
/*************************************************
* ExpandTabs: Expand tabs to spaces
*/
char* ExpandTabs(char* p_szInbuf, // expand tabs .. input buffer
char* p_szOutbuf, // .. output buffer
short* p_aiTabs) // .. array of tab stops (1 based) -- 0 end of array
char* ExpandTabs(char* p_szInbuf, /* expand tabs .. input buffer */
char* p_szOutbuf, /* .. output buffer */
short* p_aiTabs) /* .. array of tab stops (1 based) -- 0 end of array */
{
short iI, // input position
iO, // output position
iT; // next tab stop
short iI, /* input position */
iO, /* output position */
iT; /* next tab stop */
char cX; // character to test
char cX; /* character to test */
iI = 0; // init input position
iO = 0; // init output position
iT = 0; // init tab stop
iI = 0; /* init input position */
iO = 0; /* init output position */
iT = 0; /* init tab stop */
while ((cX = *(p_szInbuf + iI)) != 0) // while there are characters
while ((cX = *(p_szInbuf + iI)) != 0) /* while there are characters */
{
if (cX == '\t') // q. tab character?
{ // a. yes ..
while ((p_aiTabs[iT] <= iO + 1) // search for next valid stop ..
&& (p_aiTabs[iT] != 0)) // .. or end of table
iT++; // .. go to next tab
if (cX == '\t') /* q. tab character? */
{ /* a. yes .. */
while ((p_aiTabs[iT] <= iO + 1) /* search for next valid stop .. */
&& (p_aiTabs[iT] != 0)) /* .. or end of table */
iT++; /* .. go to next tab */
if (p_aiTabs[iT] != 0) // q. end of tab array?
{ // a. no ..
while (iO < (p_aiTabs[iT] - 1)) // fill to tab with blanks
*(p_szOutbuf + iO++) = ' '; // .. put in a blank
if (p_aiTabs[iT] != 0) /* q. end of tab array? */
{ /* a. no .. */
while (iO < (p_aiTabs[iT] - 1)) /* fill to tab with blanks */
*(p_szOutbuf + iO++) = ' '; /* .. put in a blank */
}
else // Otherwise ...
*(p_szOutbuf + iO++) = ' '; // .. Translate to blank
else /* Otherwise ... */
*(p_szOutbuf + iO++) = ' '; /* .. Translate to blank */
}
else // Otherwise .. not tab
*(p_szOutbuf + iO++) = cX; // .. save the input char
else /* Otherwise .. not tab */
*(p_szOutbuf + iO++) = cX; /* .. save the input char */
iI++; // next input character
iI++; /* next input character */
}
*(p_szOutbuf + iO) = 0; // end the string..
return p_szOutbuf; // .. return output area addr
*(p_szOutbuf + iO) = 0; /* end the string.. */
return p_szOutbuf; /* .. return output area addr */
}
/////////////////////////////////////
// extract next token, modify pointer
/*************************************************
* extract next token, modify pointer
*/
char* GetToken(char* p_szOut, // output location
int p_iLen, // max output length
char**p_pszToken) // pointer to input token
char* GetToken(char* p_szOut, /* output location */
int p_iLen, /* max output length */
char**p_pszToken) /* pointer to input token */
{
int iI; // work integer
char* pszX; // work pointer
int iI; /* work integer */
char* pszX; /* work pointer */
pszX = *p_pszToken; // get pointer to token
pszX = *p_pszToken; /* get pointer to token */
for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) // while not whitespace & not end
iI++; // .. count token length
for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) /* while not whitespace & not end */
iI++; /* .. count token length */
memset(p_szOut, 0, p_iLen); // zero out output area
memset(p_szOut, 0, p_iLen); /* zero out output area */
if (iI > 0) // q. any chars?
strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); // a. yes.. copy max of p_iLen-1
if (iI > 0) /* q. any chars? */
strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); /* a. yes.. copy max of p_iLen-1 */
*p_pszToken += iI; // point beyond token
return p_szOut; // .. return token pointer
*p_pszToken += iI; /* point beyond token */
return p_szOut; /* .. return token pointer */
}
/////////////////////////////////////////////////////////
// EditToAsm - convert tab-formatted text line to 1130 Assembler format
/*************************************************
* EditToAsm - convert tab-formatted text line to 1130 Assembler format
*/
char *EditToAsm (char* p_pszEdit) // convert line to 1130 assembler
char *EditToAsm (char* p_pszEdit) /* convert line to 1130 assembler */
{
char pszLine[MAXLINE]; // source line
char pszWork[WORKSZ]; // work buffer
char acTFWrk[2]; // tag/format work area
size_t iI; // work integer
char pszLine[MAXLINE]; /* source line */
char pszWork[WORKSZ]; /* work buffer */
char acTFWrk[2]; /* tag/format work area */
size_t iI; /* work integer */
if (p_pszEdit == NULL) // q. null request?
return AMSG; // a. yes .. return display message
if (p_pszEdit == NULL) /* q. null request? */
return AMSG; /* a. yes .. return display message */
if (*p_pszEdit == '!') // leave lines starting with ! alone
if (*p_pszEdit == '!') /* leave lines starting with ! alone */
return EditToWhitespace(p_pszEdit+1);
if (*p_pszEdit == '*') // q. comment line?
{ // a. yes..
strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); // .. convert any tabs
sprintf(gszOutput, ACOMMENTFMT, pszWork); // .. put the comment out there in the opcode column
return gszOutput; // .. and return it
if (*p_pszEdit == '*') /* q. comment line? */
{ /* a. yes.. */
strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); /* .. convert any tabs */
sprintf(gszOutput, ACOMMENTFMT, pszWork); /* .. put the comment out there in the opcode column */
return gszOutput; /* .. and return it */
}
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */
ExpandTabs(pszLine, pszWork, gaiAsmTabs); // expand the tabs
strncpy(pszLine, pszWork, MAXLINE-1); // copy the line back
ExpandTabs(pszLine, pszWork, gaiAsmTabs); /* expand the tabs */
strncpy(pszLine, pszWork, MAXLINE-1); /* copy the line back */
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace
for (iI = strlen(pszLine); iI--;) /* trim trailing whitespace */
{
if (*(pszLine + iI) <= ' ') // q. space or less?
*(pszLine + iI) = 0; // a. yes .. remove it
else // otherwise
break; // .. done. Leave loop.
if (*(pszLine + iI) <= ' ') /* q. space or less? */
*(pszLine + iI) = 0; /* a. yes .. remove it */
else /* otherwise */
break; /* .. done. Leave loop. */
}
if (strlen(pszLine) == 0) // q. blank line?
{ // a. yes .. Assembler abhors these so
sprintf(gszOutput, ABLANKLINE); // format as comment statement
return gszOutput; // .. and return it
if (strlen(pszLine) == 0) /* q. blank line? */
{ /* a. yes .. Assembler abhors these so */
sprintf(gszOutput, ABLANKLINE); /* format as comment statement */
return gszOutput; /* .. and return it */
}
// TODO: Add code to process a strip switch
// comment?
/* TODO: Add code to process a strip switch
* comment?
*/
if (strlen(pszLine) > (TAGOFFSET + 1)) // q. line long enough?
{ // a. yes.. reorder tag/format
memcpy(acTFWrk, pszLine + FMTOFFSET, 2); // get tag/format
memset((pszLine + FMTOFFSET), ' ', 2); // .. blank 'em out
if (strlen(pszLine) > (TAGOFFSET + 1)) /* q. line long enough? */
{ /* a. yes.. reorder tag/format */
memcpy(acTFWrk, pszLine + FMTOFFSET, 2); /* get tag/format */
memset((pszLine + FMTOFFSET), ' ', 2); /* .. blank 'em out */
for (iI = 0; iI < 2; iI ++)
if (isalpha(acTFWrk[iI])) // q. alpha char?
*(pszLine + FMTOFFSET) = acTFWrk[iI]; // a. yes .. make it format
else if (isdigit(acTFWrk[iI])) // q. digit?
*(pszLine + TAGOFFSET) = acTFWrk[iI]; // a. yes .. make it the tag
if (isalpha(acTFWrk[iI])) /* q. alpha char? */
*(pszLine + FMTOFFSET) = acTFWrk[iI]; /* a. yes .. make it format */
else if (isdigit(acTFWrk[iI])) /* q. digit? */
*(pszLine + TAGOFFSET) = acTFWrk[iI]; /* a. yes .. make it the tag */
}
sprintf(gszOutput, AFORMAT, pszLine); // format the line
sprintf(gszOutput, AFORMAT, pszLine); /* format the line */
return gszOutput; // return formatted line
return gszOutput; /* return formatted line */
}
/////////////////////////////////////////////////////////
// EditToFortran - convert tab-formatted input text line to FORTRAN format
// (a la DEC Fortran)
/*************************************************
* EditToFortran - convert tab-formatted input text line to FORTRAN format
* (a la DEC Fortran)
*/
char *EditToFortran(char* p_pszEdit) // convert line to 1130 assembler
char *EditToFortran(char* p_pszEdit) /* convert line to 1130 assembler */
{
char pszLine[MAXLINE]; // source line
char* pszWork; // work pointer
size_t iI; // work integer
int bContinue; // true if continue
char pszLine[MAXLINE]; /* source line */
char* pszWork; /* work pointer */
size_t iI; /* work integer */
int bContinue; /* true if continue */
if (p_pszEdit == NULL) // q. null request?
return FMSG; // a. yes .. return display message
if (p_pszEdit == NULL) /* q. null request? */
return FMSG; /* a. yes .. return display message */
if (strchr(p_pszEdit, '\t') == NULL) // q. no tab in the line?
return p_pszEdit; // a. nope, return line as is, assume it's formatted correctly
if (strchr(p_pszEdit, '\t') == NULL) /* q. no tab in the line? */
return p_pszEdit; /* a. nope, return line as is, assume it's formatted correctly */
if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') // q. comment or directive or blank line?
{ // a. yes.. don't restructure
if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') /* q. comment or directive or blank line? */
{ /* a. yes.. don't restructure */
return EditToWhitespace(p_pszEdit);
}
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace
for (iI = strlen(pszLine); iI--;) /* trim trailing whitespace */
{
if (*(pszLine + iI) <= ' ') // q. space or less?
*(pszLine + iI) = 0; // a. yes .. remove it
else // otherwise
break; // .. done. Leave loop.
if (*(pszLine + iI) <= ' ') /* q. space or less? */
*(pszLine + iI) = 0; /* a. yes .. remove it */
else /* otherwise */
break; /* .. done. Leave loop. */
}
// TODO: Add code to process a strip switch
// comment?
/*
* TODO: Add code to process a strip switch
* comment?
*/
pszWork = (char*) pszLine; // set pointer to line
GetToken(gszLabel, 6, &pszWork); // get the line, if any.
pszWork = (char*) pszLine; /* set pointer to line */
GetToken(gszLabel, 6, &pszWork); /* get the line, if any. */
pszWork++; // skip tab/whitespace
pszWork++; /* skip tab/whitespace */
// continuation...
bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) // if first char non-zero digit
|| (!isspace(*pszWork) && !isalpha(*pszWork))); // .. or non-alpha non-blank
/* continuation... */
bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) /* if first char non-zero digit */
|| (!isspace(*pszWork) && !isalpha(*pszWork))); /* .. or non-alpha non-blank */
memset(gszArg, 0, MAXLINE); // .. and arguments
memset(gszArg, 0, MAXLINE); /* .. and arguments */
strncpy(gszArg, pszWork, 75); // copy rest to argument
strncpy(gszArg, pszWork, 75); /* copy rest to argument */
sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, // format the line
gszLabel, // .. statement #
gszArg); // .. code
sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, /* format the line */
gszLabel, /* .. statement # */
gszArg); /* .. code */
return gszOutput; // return formatted line
return gszOutput; /* return formatted line */
}
/////////////////////////////////////////////////////////
// EditToWhitespace - expand tabs at 8 space intervals.
/*************************************************
* EditToWhitespace - expand tabs at 8 space intervals.
*/
char* EditToWhitespace(char *p_pszEdit)
{
int iI; /* work integer */
char pszLine[MAXLINE]; // source line
char pszWork[WORKSZ]; // work buffer
char pszLine[MAXLINE]; /* source line */
char pszWork[WORKSZ]; /* work buffer */
if (p_pszEdit == NULL) // q. null request?
return AMSG; // a. yes .. return display message
if (p_pszEdit == NULL) /* q. null request? */
return AMSG; /* a. yes .. return display message */
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */
ExpandTabs(pszLine, pszWork, gaiPlainTabs); // expand the tabs
strncpy(gszOutput, pszWork, MAXLINE-1); // copy the line back
ExpandTabs(pszLine, pszWork, gaiPlainTabs); /* expand the tabs */
strncpy(gszOutput, pszWork, MAXLINE-1); /* copy the line back */
for (iI = strlen(gszOutput); iI--;) // look at each character
for (iI = strlen(gszOutput); iI--;) /* look at each character */
{
if (*(gszOutput + iI) <= ' ') // q. space or less?
*(gszOutput + iI) = 0; // a. yes .. remove it
else // otherwise
break; // .. done. Leave loop.
if (*(gszOutput + iI) <= ' ') /* q. space or less? */
*(gszOutput + iI) = 0; /* a. yes .. remove it */
else /* otherwise */
break; /* .. done. Leave loop. */
}

View file

@ -12,6 +12,6 @@
/* ibm1130_asm.h: definition of routines in ibm1130_asm.c
*/
char* EditToAsm(char*); // convert edit format to 1130 assembler format
char* EditToFortran(char*); // convert edit format to Fortran format
char* EditToWhitespace(char*); // clean white space, tabstops every 8 positions
char* EditToAsm(char*); /* convert edit format to 1130 assembler format */
char* EditToFortran(char*); /* convert edit format to Fortran format */
char* EditToWhitespace(char*); /* clean white space, tabstops every 8 positions */

View file

@ -3,11 +3,11 @@
/* ibm1130_gdu.c: IBM 1130 2250 Graphical Display Unit
(Under construction)
// stuff to fix:
// "store revert" might be backwards?
// alpha keyboard is not implemented
// pushbuttons are not implemented
// there is something about interrupts being deferred during a subroutine transition?
stuff to fix:
"store revert" might be backwards?
alpha keyboard is not implemented
pushbuttons are not implemented
there is something about interrupts being deferred during a subroutine transition?
Based on the SIMH package written by Robert M Supnik
@ -21,13 +21,13 @@
* Mail to simh@ibm1130.org
*/
#define BLIT_MODE // normally defined, undefine when debugging generate_image()
//#define DEBUG_LIGHTPEN // normally undefined, define to visualize light-pen sensing
#define BLIT_MODE /* define for better performance, undefine when debugging generate_image() */
/* #define DEBUG_LIGHTPEN */ /* define to debug light-pen sensing */
#define DEFAULT_GDU_RATE 20 // default frame rate
#define DEFAULT_PEN_THRESHOLD 3 // default looseness of light-pen hit
#define INDWIDTH 32 // width of an indicator (there are two columns of these)
#define INITSIZE 512 // initial window size
#define DEFAULT_GDU_RATE 20 /* default frame rate */
#define DEFAULT_PEN_THRESHOLD 3 /* default looseness of light-pen hit */
#define INDWIDTH 32 /* width of an indicator (there are two columns of these) */
#define INITSIZE 512 /* initial window size */
#define GDU_DSW_ORDER_CONTROLLED_INTERRUPT 0x8000
#define GDU_DSW_KEYBOARD_INTERUPT 0x4000
@ -109,7 +109,7 @@ static t_stat gdu_reset (DEVICE *dptr)
void xio_2250_display (int32 addr, int32 func, int32 modify)
{
// ignore commands to nonexistent device
/* ignore commands if device is nonexistent */
}
t_bool gdu_active (void)
@ -118,7 +118,7 @@ t_bool gdu_active (void)
}
/* -------------------------------------------------------------------------------------- */
#else // GUI_SUPPORT defined
#else /* GUI_SUPPORT defined */
/******* PLATFORM INDEPENDENT CODE ********************************************************/
@ -127,7 +127,6 @@ static int xmouse, ymouse, lpen_dist, lpen_dist2; // current mouse pointer, scal
static double sfactor; // current scaling factor
static t_bool last_abs = TRUE; // last positioning instruction was absolute
static t_bool mouse_present = FALSE; // mouse is/is not in the window
static void clear_interrupts (void);
static void set_indicators (int32 new_inds);
static void start_regeneration (void);
@ -239,23 +238,27 @@ static void start_regeneration (void)
{
SETBIT(gdu_dsw, GDU_DSW_BUSY);
if (gdu_unit.flags & UNIT_DISPLAYED) {
StartGDUUpdates();
}
else {
if ((gdu_unit.flags & UNIT_DISPLAYED) == 0) {
if (! CreateGDUWindow())
return;
SETBIT(gdu_unit.flags, UNIT_DISPLAYED);
}
StartGDUUpdates();
}
static void halt_regeneration (void)
{
// halt_regeneration gets called at end of every refresh interation, so it should NOT black out the
// screen -- this is why it was flickering so badly. The lower level code (called on a timer)
// should check to see if GDU_DSW_BUSY is clear, and if it it still zero after several msec,
// only then should it black out the screen and call StopGDUUpdates.
if (gdu_dsw & GDU_DSW_BUSY) {
StopGDUUpdates();
// StopGDUUpdates(); // let lower level code discover this during next refresh
CLRBIT(gdu_dsw, GDU_DSW_BUSY);
}
EraseGDUScreen();
// EraseGDUScreen(); // let cessation of regeneration erase it (eventually)
}
static void notify_window_closed (void)
@ -264,7 +267,9 @@ static void notify_window_closed (void)
StopGDUUpdates();
CLRBIT(gdu_dsw, GDU_DSW_BUSY);
}
CLRBIT(gdu_unit.flags, UNIT_DISPLAYED);
gdu_reset(&gdu_dev);
}
@ -671,7 +676,7 @@ static HPEN hRedPen = NULL;
#endif
static HBRUSH hGrayBrush, hDarkBrush;
static HPEN hBlackPen;
static int halted = 0; // number of time intervals that GDU has been halted w/o a regeneration
static LRESULT APIENTRY GDUWndProc (HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
static DWORD WINAPI GDUPump (LPVOID arg);
@ -719,11 +724,6 @@ static t_bool CreateGDUWindow (void)
{
static BOOL did_atexit = FALSE;
if (hwGDU != NULL) { // window already exists
StartGDUUpdates();
return TRUE;
}
hInstance = GetModuleHandle(NULL);
if (hGDUPump == INVALID_HANDLE_VALUE)
@ -878,7 +878,7 @@ static void gdu_WM_PAINT (HWND hWnd)
static void gdu_WM_SIZE (HWND hWnd, UINT state, int cx, int cy)
{
InvalidateRect(hWnd, NULL, FALSE);
InvalidateRect(hWnd, NULL, TRUE);
}
// tweak the sizing rectangle during a resize to guarantee a square window
@ -912,6 +912,16 @@ static void gdu_WM_TIMER (HWND hWnd, UINT id)
HDC hDC;
if (running) { // if CPU is running, update picture
if ((gdu_dsw & GDU_DSW_BUSY) == 0) { // regeneration is not to occur
if (++halted >= 4) { // stop the timer if four timer intervals go by with the display halted
EraseGDUScreen(); // screen goes black due to cessation of refreshing
StopGDUUpdates(); // might as well kill the timer
return;
}
}
else
halted = 0;
#ifdef BLIT_MODE
hDC = GetDC(hWnd); // blit the new image right over the old
PaintImage(hDC, FALSE);
@ -964,7 +974,7 @@ static void DrawPoint (int x, int y)
static void UpdateGDUIndicators(void)
{
if (hwGDU != NULL)
InvalidateRect(hwGDU, NULL, TRUE);
InvalidateRect(hwGDU, NULL, FALSE); // no need to erase the background -- the draw routine fully paints the indicator
}
static void CheckGDUKeyboard (void)
@ -981,6 +991,7 @@ static void StartGDUUpdates (void)
msec = (gdu_rate == 0) ? (1000 / DEFAULT_GDU_RATE) : 1000/gdu_rate;
idTimer = SetTimer(hwGDU, 1, msec, NULL);
}
halted = 0;
}
static void StopGDUUpdates (void)
@ -988,6 +999,7 @@ static void StopGDUUpdates (void)
if (idTimer != 0) {
KillTimer(hwGDU, 1);
idTimer = 0;
halted = 10000;
}
}
@ -1086,8 +1098,6 @@ static DWORD WINAPI GDUPump (LPVOID arg)
ShowWindow(hwGDU, SW_SHOWNOACTIVATE); /* display it */
UpdateWindow(hwGDU);
StartGDUUpdates();
while (GetMessage(&msg, hwGDU, 0, 0)) { /* message pump - this basically loops forevermore */
TranslateMessage(&msg);
DispatchMessage(&msg);

View file

@ -11,6 +11,9 @@
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org
*
* 30-Dec-05 BLK Fixed mask for IAR and SAR register display and added display
* of Arithmetic Factor, per Carl Claunch.
*
* 09-Apr-04 BLK Changed code to use stock windows cursor IDC_HAND if available
*
* 02-Dec-02 BLK Changed display, added printer and card reader icons
@ -33,9 +36,9 @@
#define UPDATE_BY_TIMER
#ifdef UPDATE_BY_TIMER
# define UPDATE_INTERVAL 20 // set to desired number of updates/second
# define UPDATE_INTERVAL 20 /* set to desired number of updates/second */
#else
# define UPDATE_INTERVAL 5000 // GUI: set to 100000/f where f = desired updates/second of 1130 time
# define UPDATE_INTERVAL 5000 /* GUI: set to 100000/f where f = desired updates/second of 1130 time */
#endif
#define UNIT_V_CR_EMPTY (UNIT_V_UF + 5) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_cr.c */
@ -46,8 +49,9 @@
#define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */
#define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
// I think I had it wrong; Program Load actually does start the processor after
// reading in the card?
/* I think I had it wrong; Program Load actually does start the processor after
* reading in the card?
*/
#define PROGRAM_LOAD_STARTS_CPU
@ -86,7 +90,7 @@ DEVICE console_dev = {
NULL, NULL, NULL
};
// reset for the "console" display device
/* reset for the "console" display device */
extern char *read_line (char *cptr, int size, FILE *stream);
extern FILE *sim_log;
@ -117,8 +121,8 @@ extern UNIT prt_unit;
t_stat console_reset (DEVICE *dptr)
{
if (! sim_gui) {
SETBIT(console_unit.flags, UNIT_DIS); // disable the GUI
CLRBIT(console_unit.flags, UNIT_DISPLAY); // turn the GUI off
SETBIT(console_unit.flags, UNIT_DIS); /* disable the GUI */
CLRBIT(console_unit.flags, UNIT_DISPLAY); /* turn the GUI off */
}
update_gui(FALSE);
@ -158,19 +162,19 @@ void scp_panic (char *msg)
#define IDC_RESET 14
#define IDC_PROGRAM_LOAD 15
#define IDC_TEAR 16 // standard button
#define IDC_1442 17 // device images
#define IDC_TEAR 16 /* standard button */
#define IDC_1442 17 /* device images */
#define IDC_1132 18
#define LAMPTIME 500 // 500 msec delay on updating
#define LAMPTIME 500 /* 500 msec delay on updating */
#define FLASH_TIMER_ID 1
#define UPDATE_TIMER_ID 2
#define RUNSWITCH_X 689 // center of the run mode switch dial
#define RUNSWITCH_X 689 /* center of the run mode switch dial */
#define RUNSWITCH_Y 107
#define TOGGLES_X 122 // left edge of series of toggle switches
#define TOGGLES_X 122 /* left edge of series of toggle switches */
#define TXTBOX_X 200 // text labels showing attached devices
#define TXTBOX_X 200 /* text labels showing attached devices */
#define TXTBOX_Y 300
#define TXTBOX_WIDTH 195
#define TXTBOX_HEIGHT 12
@ -238,19 +242,18 @@ static struct tag_btn {
TXTBOX_X+40, TXTBOX_Y+25, 35, 12, "Tear", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
635, 238, 110, 110, "EMPTY_1442", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
// 635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
};
#define NBUTTONS (sizeof(btn) / sizeof(btn[0]))
#define STATE_1442_EMPTY 0 // no cards (no file attached)
#define STATE_1442_FULL 1 // cards in hopper (file attached at BOF)
#define STATE_1442_MIDDLE 2 // cards in hopper and stacker (file attached, neither EOF nor BOF)
#define STATE_1442_EOF 3 // cards in stacker (file attached, at EOF)
#define STATE_1442_HIDDEN 4 // simulator is attached to physical card reader
#define STATE_1442_EMPTY 0 /* no cards (no file attached) */
#define STATE_1442_FULL 1 /* cards in hopper (file attached at BOF) */
#define STATE_1442_MIDDLE 2 /* cards in hopper and stacker (file attached, neither EOF nor BOF) */
#define STATE_1442_EOF 3 /* cards in stacker (file attached, at EOF) */
#define STATE_1442_HIDDEN 4 /* simulator is attached to physical card reader */
#define STATE_1132_EMPTY 0 // no paper hanging out of printer
#define STATE_1132_FULL 1 // paper hanging out of printer
#define STATE_1132_HIDDEN 2 // printer is attached to physical printer
#define STATE_1132_EMPTY 0 /* no paper hanging out of printer */
#define STATE_1132_FULL 1 /* paper hanging out of printer */
#define STATE_1132_HIDDEN 2 /* printer is attached to physical printer */
static struct tag_txtbox {
int x, y;
@ -309,9 +312,9 @@ static void destroy_console_window (void)
int i;
if (hConsoleWnd != NULL)
SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); // cross thread call is OK
SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); /* cross thread call is OK */
if (hPump != INVALID_HANDLE_VALUE) { // this is not the most graceful way to do it
if (hPump != INVALID_HANDLE_VALUE) { /* this is not the most graceful way to do it */
TerminateThread(hPump, 0);
hPump = INVALID_HANDLE_VALUE;
PumpID = 0;
@ -338,10 +341,11 @@ static void destroy_console_window (void)
NIXOBJECT(btn[i].hbrDark);
}
// if (class_defined) {
// UnregisterClass(hInstance, szConsoleClassName);
// class_defined = FALSE;
// }
/* if (class_defined) {
UnregisterClass(hInstance, szConsoleClassName);
class_defined = FALSE;
}
*/
}
/* ------------------------------------------------------------------------
@ -350,7 +354,7 @@ static void destroy_console_window (void)
static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext = 0;
static int shown_op = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0;
static int shown_ces = 0, shown_runmode = MODE_RUN;
static int shown_ces = 0, shown_arf = 0, shown_runmode = MODE_RUN;
static int CND;
/* ------------------------------------------------------------------------
@ -402,7 +406,7 @@ void update_gui (BOOL force)
static int32 displayed = 0;
RECT xin;
if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { // setting has changed
if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { /* setting has changed */
displayed = console_unit.flags & UNIT_DISPLAY;
if (displayed)
init_console_window();
@ -438,6 +442,8 @@ void update_gui (BOOL force)
{shown_iar = IAR; RedrawRegion(hConsoleWnd, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */
if (SAR != shown_sar)
{shown_sar = SAR; RedrawRegion(hConsoleWnd, 75, 42, 364, 65);}
if (ARF != shown_arf)
{shown_arf = ARF; RedrawRegion(hConsoleWnd, 75, 114, 364, 136);}
if (ACC != shown_acc)
{shown_acc = ACC; RedrawRegion(hConsoleWnd, 75, 141, 364, 164);}
if (EXT != shown_ext)
@ -465,7 +471,7 @@ void update_gui (BOOL force)
int_lamps = 0;
// this loop works with lamp buttons that are calculated on-the-fly only
/* this loop works with lamp buttons that are calculated on-the-fly only */
for (i = 0; i < NBUTTONS; i++) {
if (btn[i].pushable)
continue;
@ -475,26 +481,28 @@ void update_gui (BOOL force)
state = hFlashTimer || (running && ! wait_state);
break;
// this button is always off
// case IDC_PARITY_CHECK:
/* this button is always off
case IDC_PARITY_CHECK
*/
// these buttons are enabled/disabled directly
// case IDC_POWER_ON:
// case IDC_FILE_READY:
// case IDC_FORMS_CHECK:
// case IDC_KEYBOARD_SELECT:
// case IDC_DISK_UNLOCK:
/* these buttons are enabled/disabled directly
case IDC_POWER_ON:
case IDC_FILE_READY:
case IDC_FORMS_CHECK:
case IDC_KEYBOARD_SELECT:
case IDC_DISK_UNLOCK:
*/
default:
continue;
}
if (state != btn[i].state) { // state has changed
if (state != btn[i].state) { /* state has changed */
EnableWindow(btn[i].hBtn, state);
btn[i].state = state;
}
}
if (force) { // if force flag is set, update text region
if (force) { /* if force flag is set, update text region */
SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+2*TXTBOX_HEIGHT);
InvalidateRect(hConsoleWnd, &xin, TRUE);
}
@ -584,9 +592,9 @@ static int occurs (char *txt, char ch)
}
/* ------------------------------------------------------------------------
// turns out to get properly colored buttons you have to paint them yourself. Sheesh.
// On the plus side, this lets do a better job of aligning the button text than
// the button would by itself.
* turns out to get properly colored buttons you have to paint them yourself. Sheesh.
* On the plus side, this lets do a better job of aligning the button text than
* the button would by itself.
* ------------------------------------------------------------------------ */
void PaintButton (LPDRAWITEMSTRUCT dis)
@ -616,7 +624,7 @@ void PaintButton (LPDRAWITEMSTRUCT dis)
LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);
}
else if (down) {
// do the three-D thing
/* do the three-D thing */
hOldPen = SelectObject(dis->hDC, hDkGreyPen);
MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL);
LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);
@ -776,7 +784,7 @@ static DWORD WINAPI Pump (LPVOID arg)
hcArrow = LoadCursor(NULL, IDC_ARROW);
#ifdef IDC_HAND
hcHand = LoadCursor(NULL, IDC_HAND); // use stock object provided by Windows
hcHand = LoadCursor(NULL, IDC_HAND); /* use stock object provided by Windows */
if (hcHand == NULL)
hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND));
#else
@ -816,12 +824,13 @@ static DWORD WINAPI Pump (LPVOID arg)
EnableWindow(btn[i].hBtn, btn[i].state);
}
// This isn't needed anymore, now that we have the big printer icon -- it acts like a button now
// i = IDC_TEAR;
// btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,
// btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
//
// SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
/* This isn't needed anymore, now that we have the big printer icon -- it acts like a button now
* i = IDC_TEAR;
* btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,
* btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
*
* SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
*/
hbm1442_full = LoadBitmap(hInstance, "FULL_1442");
hbm1442_empty = LoadBitmap(hInstance, "EMPTY_1442");
@ -836,7 +845,6 @@ static DWORD WINAPI Pump (LPVOID arg)
btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
btn[i].state = STATE_1442_EMPTY;
// wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_full);
wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_empty);
i = IDC_1132;
@ -847,13 +855,6 @@ static DWORD WINAPI Pump (LPVOID arg)
wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1132_empty);
// for (i = 0; i < NTXTBOXES; i++) {
// txtbox[i].hBox = CreateWindow("EDIT", txtbox[i].txt,
// WS_CHILD|WS_VISIBLE|ES_LEFT|ES_READONLY,
// txtbox[i].x, txtbox[i].y, TXTBOX_WIDTH, TXTBOX_HEIGHT, hConsoleWnd, (HMENU) (i+100), hInstance, NULL);
// SendMessage(txtbox[i].hBox, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
// }
GetWindowRect(hConsoleWnd, &r); /* get window size as created */
wx = r.right - r.left + 1;
wy = r.bottom - r.top + 1;
@ -991,7 +992,7 @@ void DrawRunmode (HDC hDC, int mode)
* than a mouse-region test. Return value TRUE means the cursor is over a hotspot.
* ------------------------------------------------------------------------ */
static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual)
static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual, BOOL rightclick)
{
int b, x, r, ang, i;
@ -1054,9 +1055,10 @@ static void DrawConsole (HDC hDC, PAINTSTRUCT *ps)
SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */
DrawBits(hDC, 76, 15, shown_iar, 16, 0x3FFF, digits);
DrawBits(hDC, 76, 48, shown_sar, 16, 0x3FFF, digits);
DrawBits(hDC, 76, 15, shown_iar, 16, mem_mask, digits); /* register holds only 15 bits */
DrawBits(hDC, 76, 48, shown_sar, 16, mem_mask, digits); /* but let's display only used bits */
DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits);
DrawBits(hDC, 76, 114, shown_arf, 16, 0xFFFF, digits);
DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits);
DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits);
@ -1124,10 +1126,10 @@ static void DrawConsole (HDC hDC, PAINTSTRUCT *ps)
void flash_run (void)
{
EnableWindow(btn[IDC_RUN].hBtn, TRUE); // enable the run lamp
EnableWindow(btn[IDC_RUN].hBtn, TRUE); /* enable the run lamp */
if (hFlashTimer != 0)
KillTimer(hConsoleWnd, FLASH_TIMER_ID); // (re)schedule lamp update
KillTimer(hConsoleWnd, FLASH_TIMER_ID); /* (re)schedule lamp update */
hFlashTimer = SetTimer(hConsoleWnd, FLASH_TIMER_ID, LAMPTIME, NULL);
}
@ -1154,10 +1156,12 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
reset_all(0);
if (running && ! power) { /* turning off */
reason = STOP_POWER_OFF;
// this prevents message pump from running, which unfortunately locks up
// the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
// while (running)
// Sleep(10); /* wait for execution thread to exit */
/* wait for execution thread to exit */
/* this prevents message pump from running, which unfortunately locks up
* the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
* while (running)
* Sleep(10);
*/
}
btn[IDC_POWER_ON].state = power;
@ -1175,7 +1179,7 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
case MODE_INT_RUN:
case MODE_RUN:
case MODE_SI:
stuff_cmd("go");
stuff_cmd("cont");
break;
case MODE_DISP: /* display core and advance IAR */
@ -1196,16 +1200,17 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
case IDC_PROGRAM_STOP:
if (running) { /* potential race condition here */
GUI_BEGIN_CRITICAL_SECTION
SETBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP);
int_req |= INT_REQ_5;
SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);
int_req |= INT_REQ_5; /* note: calc_ints() is not needed in this case */
int_lamps |= INT_REQ_5;
GUI_END_CRITICAL_SECTION
}
break;
case IDC_LOAD_IAR:
if (! running) {
IAR = CES & 0x3FFF; /* set IAR from console entry switches */
IAR = CES & mem_mask; /* set IAR from console entry switches */
}
break;
@ -1214,12 +1219,13 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
case IDC_IMM_STOP:
if (running) {
reason = STOP_WAIT; /* terminate execution without setting wait_mode */
// this prevents message pump from running, which unfortunately locks up
// the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
// while (running)
// Sleep(10); /* wait for execution thread to exit */
reason = STOP_IMMEDIATE; /* terminate execution without setting wait_mode */
/* wait for execution thread to exit */
/* this prevents message pump from running, which unfortunately locks up
* the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
* while (running)
* Sleep(10);
*/
}
break;
@ -1290,10 +1296,6 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
SetRect(&rbmp, 0, 0, bmwid, bmht);
if (IntersectRect(&xsect, &clip, &rbmp))
BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY);
// rbmp.top = rbmp.bottom;
// rbmp.bottom += 200;
// if (IntersectRect(&xsect, &clip, &rbmp))
// FillRect(hDC, &xsect, hbBlack);
return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */
case WM_PAINT:
@ -1318,11 +1320,15 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
case WM_SETCURSOR:
GetCursorPos(&p);
ScreenToClient(hWnd, &p);
SetCursor(HandleClick(hWnd, p.x, p.y, FALSE) ? hcHand : hcArrow);
SetCursor(HandleClick(hWnd, p.x, p.y, FALSE, FALSE) ? hcHand : hcArrow);
return TRUE;
case WM_LBUTTONDOWN:
HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE);
HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, FALSE);
break;
case WM_RBUTTONDOWN:
HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, TRUE);
break;
case WM_CTLCOLORBTN:
@ -1339,7 +1345,7 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
break;
case WM_DROPFILES:
accept_dropped_file((HANDLE) wParam); // console window - dragged file is a script or card deck
accept_dropped_file((HANDLE) wParam); /* console window - dragged file is a script or card deck */
break;
default:
@ -1368,7 +1374,7 @@ void forms_check (int set)
EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
if (btn[IDC_FORMS_CHECK].clr != oldcolor)
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */
}
}
@ -1389,7 +1395,7 @@ void print_check (int set)
EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
if (btn[IDC_FORMS_CHECK].clr != oldcolor)
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */
}
}
@ -1425,34 +1431,34 @@ static void accept_dropped_file (HANDLE hDrop)
POINT pt;
HWND hWndDrop;
nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // get file count,
DragQueryFile(hDrop, 0, fname, sizeof(fname)); // get first filename
DragQueryPoint(hDrop, &pt); // get location of drop
nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); /* get file count, */
DragQueryFile(hDrop, 0, fname, sizeof(fname)); /* get first filename */
DragQueryPoint(hDrop, &pt); /* get location of drop */
DragFinish(hDrop);
if (nfiles <= 0) // hmm, this seems unlikely to occur, but better check
if (nfiles <= 0) /* hmm, this seems unlikely to occur, but better check */
return;
if (running) { // can only accept a drop while processor is stopped
if (running) { /* can only accept a drop while processor is stopped */
MessageBeep(0);
return;
}
if ((hWndDrop = ChildWindowFromPoint(hConsoleWnd, pt)) == btn[IDC_1442].hBtn)
cardreader = TRUE; // file was dropped onto 1442 card reader
cardreader = TRUE; /* file was dropped onto 1442 card reader */
else if (hWndDrop == NULL || hWndDrop == hConsoleWnd)
cardreader = FALSE; // file was dropped onto console window, not a button
cardreader = FALSE; /* file was dropped onto console window, not a button */
else {
MessageBeep(0); // file was dropped onto another button
MessageBeep(0); /* file was dropped onto another button */
return;
}
if (nfiles > 1) { // oops, we wouldn't know what order to read them in
if (nfiles > 1) { /* oops, we wouldn't know what order to read them in */
MessageBox(hConsoleWnd, "You may only drop one file at a time", "", MB_OK);
return;
}
// if shift key is down, prepend @ to name (make it a deck file)
/* if shift key is down, prepend @ to name (make it a deck file) */
deckfile = ((GetKeyState(VK_SHIFT) & 0x8000) && cardreader) ? "@" : "";
sprintf(cmd, "%s \"%s%s\"", cardreader ? "attach cr" : "do", deckfile, fname);
@ -1466,22 +1472,18 @@ static void tear_printer (void)
if ((prt_unit.flags & UNIT_ATT) == 0)
return;
strcpy(filename, prt_unit.filename); // save current attached filename
strcpy(filename, prt_unit.filename); /* save current attached filename */
if (! stuff_and_wait("detach prt", 1000, 0)) // detach it
if (! stuff_and_wait("detach prt", 1000, 0)) /* detach it */
return;
sprintf(cmd, "view \"%s\"", filename); // spawn notepad to view it
sprintf(cmd, "view \"%s\"", filename); /* spawn notepad to view it */
if (! stuff_and_wait(cmd, 3000, 500))
return;
// no, now we have them click the card reader icon twice to unload the deck. more flexible that way
// if (! stuff_and_wait("detach cr", 1000, 0)) // detach the card reader so they can edit the deck file
// return;
remove(filename); /* delete the file */
remove(filename); // delete the file
sprintf(cmd, "attach prt \"%s\"", filename); // reattach
sprintf(cmd, "attach prt \"%s\"", filename); /* reattach */
stuff_cmd(cmd);
}
@ -1582,24 +1584,25 @@ void stuff_cmd (char *cmd)
SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */
}
// my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,
// since it sleeps in the GUI thread while scp runs in the main thread. However,
// at the end of every command scp calls update_gui, which can result in messages
// being sent to the GUI thread. So, the GUI thread has to process messages while
// stuff_and_wait is waiting.
/* my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,
* since it sleeps in the GUI thread while scp runs in the main thread. However,
* at the end of every command scp calls update_gui, which can result in messages
* being sent to the GUI thread. So, the GUI thread has to process messages while
* stuff_and_wait is waiting.
*/
static void my_yield (void)
{
MSG msg;
// multitask
/* multitask */
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// stuff_and_wait -- stuff a command and wait for the emulator to process the command
// and come back to prompt for another
/* stuff_and_wait -- stuff a command and wait for the emulator to process the command
* and come back to prompt for another
*/
t_bool stuff_and_wait (char *cmd, int timeout, int delay)
{
@ -1650,5 +1653,5 @@ void remark_cmd (char *remark)
}
}
#endif // _WIN32 defined
#endif // GUI_SUPPORT defined
#endif /* _WIN32 defined */
#endif /* GUI_SUPPORT defined */

634
Ibm1130/ibm1130_plot.c Normal file
View file

@ -0,0 +1,634 @@
/* ibm1130_plot.c: IBM 1130 1627 plotter emulation
Based on the SIMH simulator package written by Robert M Supnik
Brian Knittel
Revision History
2004.10.22 - Written.
2006.1.2 - Rewritten as plotter routine by Carl V Claunch
* (C) Copyright 2004, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org
*/
#include "ibm1130_defs.h"
#ifndef ENABLE_PLOT_SUPPORT
DEVICE plot_dev = {
"PLOT", NULL, NULL, NULL,
0, 16, 16, 1, 16, 16,
NULL, NULL, NULL,
NULL, NULL, NULL};
void xio_1627_plotter (int32 addr, int32 func, int32 modify)
{
/* silently eat any plotter commands */
}
#else
#include "gd.h"
/***************************************************************************************
* 1627 model 1 plotter (based on Calcomp 535 which was sold as IBM 1627)
*
* - 11" wide carriage, addressible in .01" steps
* - continous sheet paper up to 120' in length
* - sheet moveable in .01" steps, either direction
* - switchable pen, in various colors and line widths
*
* Simulator implementation will create a JPEG image corresponding to a
* landscape mode sheet of paper, the width of the carriage at 11".
* A diagram of more than 8" of paper travel will span printed pages
* in landscape mode.
*
* When an 'att plot' command is issued a file is created based on the
* default or currently set values of paper length, starting
* position of the pen in both X and Y axes, pen color and pen width.
* Based on the number of logical pages of paper, the command will create
* the proper size canvas internally and create the output JPEG file.
*
* When a 'det plot' command is issued, the plotter image will be converted
* into the file that was specified during the attach process. The
* image is not viewable until this point, unless an examine plot is
* issued which will dump the current state of the paper into the file.
*
* The 'set plot' command can set pen width, paper length, pen color,
* current carriage X and Y coordinates. Paper length can be set
* to alter the default of 800 (8"); changes are ignored until
* the next 'attach' command. The current carriage x and y positions
* can be set at any time and will go into effect immediately, just
* as the pen color and pen width can be altered on the fly.
*
* NOTE: requires gd library and definition of ENABLE_PLOT_SUPPORT in makefile or Visual C configuration
* gd is not included in the main simh and ibm1130.org distributions at the present time.
***************************************************************************************/
#define PLOT1627_DSW_OP_COMPLETE 0x8000
#define PLOT1627_DSW_BUSY 0x0200
#define PLOT1627_DSW_NOT_READY 0x0100
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
#define IS_DEBUG ((plot_unit->flags & UNIT_DEBUG) == UNIT_DEBUG)
#define IS_PENDOWN ((plot_unit->flags & UNIT_PEN) == UNIT_PEN)
static t_stat plot_svc (UNIT *uptr); /* activity routine */
static t_stat plot_reset (DEVICE *dptr); /* reset of 1130 */
static t_stat plot_attach (UNIT *uptr, char *cptr); /* attach, loads plotter */
static t_stat plot_detach (UNIT *uptr); /* detach and save image */
static t_stat plot_examine (UNIT *uptr); /* update file with current canvas */
static t_stat plot_set_length (UNIT *uptr, int32 val, char * ptr, void *desc); /* set paper length */
static t_stat plot_set_pos (UNIT *uptr, int32 val, char * ptr, void *desc); /* reset current X/Y position */
static t_stat plot_show_vals(FILE *fp, UNIT *uptr, int32 val, void *descrip); /* print x, y and length */
static t_stat plot_show_nl(FILE *fp, UNIT *uptr, int32 val, void *descrip); /* overcome wacky simh behavior */
static void update_pen(void); /* will ensure pen action is correct when changes made */
static t_stat plot_validate_change (UNIT *uptr, int32 val, char * ptr, void *desc); /* when set command issued */
static void process_cmd(void); /* does actual drawing for plotter */
extern int32 sim_switches; /* switches set on simh command */
static int16 plot_dsw = 0; /* device status word */
static int16 plot_cmd = 0; /* the command to process */
static int32 plot_wait = 1000; /* plotter movement wait */
static int32 plot_xpos = 0; /* current X position */
static int32 plot_xmax = 799; /* end of paper */
static int32 plot_ypos = 0; /* current Y position */
static int32 plot_ymax = 1099; /* right edge of carriage */
#define PEN_DOWN 0x80000000
#define PEN_UP 0x00000000
static int32 plot_pen = PEN_UP; /* current pen position */
static int black_pen; /* holds color black */
static int blue_pen; /* holds color blue */
static int red_pen; /* holds color red */
static int green_pen; /* holds color green */
static int yellow_pen; /* holds yellow color */
static int purple_pen; /* holds color purple */
static int ltgrey_pen; /* holds light grey */
static int grey_pen; /* holds grey */
static int white_background; /* holds white of paper roll */
static int plot_pwidth; /* set and display variable */
static int plot_pcolor; /* set and display variable */
static int need_update = 0; /* flag to force and update_pen() */
static gdImagePtr image; /* pointer to our canvas */
#define UNIT_V_COLOR (UNIT_V_UF + 0) /* color of selected pen - 3 bits */
#define UNIT_V_WIDTH (UNIT_V_UF + 3) /* width of pen - two bits */
#define UNIT_V_NOOP (UNIT_V_UF + 5) /* dummy for set/show commands */
#define UNIT_V_DEBUG (UNIT_V_UF + 6) /* for -d switch on attach command */
#define UNIT_V_PEN (UNIT_V_UF + 7) /* track pen state */
#define UNIT_WIDTH (3u << UNIT_V_WIDTH) /* two bits */
#define UNIT_COLOR (7u << UNIT_V_COLOR) /* three bits */
#define UNIT_NOOP (1u << UNIT_V_NOOP) /* dummy for set/show */
#define UNIT_DEBUG (1u << UNIT_V_DEBUG) /* shows debug mode on */
#define UNIT_PEN (1u << UNIT_V_PEN) /* the pen state bit */
#define PEN_BLACK (0u << UNIT_V_COLOR)
#define PEN_RED (1u << UNIT_V_COLOR)
#define PEN_BLUE (2u << UNIT_V_COLOR)
#define PEN_GREEN (3u << UNIT_V_COLOR)
#define PEN_YELLOW (4u << UNIT_V_COLOR)
#define PEN_PURPLE (5u << UNIT_V_COLOR)
#define PEN_LTGREY (6u << UNIT_V_COLOR)
#define PEN_GREY (7u << UNIT_V_COLOR)
#define SET_COLOR(op) {plot_unit[0].flags &= ~UNIT_COLOR; plot_unit[0].flags |= (op);}
#define GET_COLOR (plot_unit[0].flags & UNIT_COLOR)
#define BLACK 0,0,0
#define BLUE 0,0,255
#define RED 255,0,0
#define GREEN 0,255,0
#define YELLOW 200,200,0
#define PURPLE 150,0,150
#define LTGREY 200,200,200
#define GREY 120,120,120
#define WHITE 255,255,255
#define PEN_SINGLE (0u << UNIT_V_WIDTH)
#define PEN_DOUBLE (1u << UNIT_V_WIDTH)
#define PEN_TRIPLE (2u << UNIT_V_WIDTH)
#define PEN_QUAD (3u << UNIT_V_WIDTH)
#define GET_WIDTH() (plot_unit[0].flags & UNIT_WIDTH)
#define SET_WIDTH(cd) {plot_unit[0].flags &= ~UNIT_WIDTH; un.flags |= (cd);}
UNIT plot_unit[] = {
{ UDATA (&plot_svc, UNIT_ATTABLE, 0) },
};
REG plot_reg[] = {
{ HRDATA (DSW, plot_dsw, 16) }, /* device status word */
{ DRDATA (WTIME, plot_wait, 24), PV_LEFT }, /* plotter movement wait */
{ DRDATA (Xpos, plot_xpos, 32), PV_LEFT }, /* Current X Position*/
{ DRDATA (Ypos, plot_ypos, 32), PV_LEFT }, /* Current Y Position*/
{ FLDATA (PenDown, plot_pen, 0)}, /* Current pen position - 1 = down */
{ DRDATA (PaperSize, plot_xmax, 32), PV_LEFT }, /* Length of paper in inches */
{ NULL } };
MTAB plot_mod[] = {
{ UNIT_COLOR, PEN_BLACK, "black", "BLACK", &plot_validate_change},
{ UNIT_COLOR, PEN_RED, "red", "RED", &plot_validate_change},
{ UNIT_COLOR, PEN_BLUE, "blue", "BLUE", &plot_validate_change},
{ UNIT_COLOR, PEN_GREEN, "green", "GREEN", &plot_validate_change},
{ UNIT_COLOR, PEN_YELLOW, "yellow", "YELLOW", &plot_validate_change},
{ UNIT_COLOR, PEN_PURPLE, "purple", "PURPLE", &plot_validate_change},
{ UNIT_COLOR, PEN_LTGREY, "ltgrey", "LTGREY", &plot_validate_change},
{ UNIT_COLOR, PEN_GREY, "grey", "GREY", &plot_validate_change},
{ UNIT_WIDTH, PEN_SINGLE, "1.0", "1.0", &plot_validate_change},
{ UNIT_WIDTH, PEN_DOUBLE, "2.0", "2.0", &plot_validate_change},
{ UNIT_WIDTH, PEN_TRIPLE, "3.0", "3.0", &plot_validate_change},
{ UNIT_WIDTH, PEN_QUAD, "4.0", "4.0", &plot_validate_change},
{ UNIT_PEN, UNIT_PEN, "pendown", "PENDOWN", &plot_validate_change},
{ UNIT_PEN, 0, "penup", "PENUP", &plot_validate_change},
/* below is dummy entry to trigger the show routine and print extended values */
{ UNIT_NOOP, 0, "", NULL, NULL, &plot_show_vals},
/* extended entries must allow parm for both unit and dev, but
* then they will print the value twice for a 'show plot' command
* therefore they are set to not display unless explicity requested
* and the special dummy NOOP entry will cause the print of these values */
{ MTAB_XTD | MTAB_VAL | MTAB_VUN | MTAB_VDV | MTAB_NMO, 2,
"length", "LENGTH", &plot_set_length, &plot_show_nl, &plot_reg[5]},
{ MTAB_XTD | MTAB_VAL | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0,
"Xpos", "XPOS", &plot_set_pos, &plot_show_nl, &plot_reg[2]},
{ MTAB_XTD | MTAB_VAL | MTAB_VDV | MTAB_VUN | MTAB_NMO, 1,
"Ypos", "YPOS", &plot_set_pos, &plot_show_nl, &plot_reg[3]},
{ 0 } };
DEVICE plot_dev = {
"PLOT", plot_unit, plot_reg, plot_mod,
1, 16, 16, 1, 16, 16,
NULL, NULL, plot_reset,
NULL, plot_attach, plot_detach};
/* xio_1627_plotter - XIO command interpreter for the 1627 plotter model 1 */
void xio_1627_plotter (iocc_addr, iocc_func, iocc_mod)
{
char msg[80];
if (! IS_ONLINE(plot_unit) ) {
SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* set not ready */
if (IS_DEBUG) printf("Plotter has no paper, ignored\n");
return; /* and ignore */
}
switch (iocc_func) {
case XIO_READ: /* read XIO */
xio_error("Read XIO not supported by 1627 plotter");
break;
case XIO_WRITE: /* write: do one plotter operation */
if ((plot_dsw & PLOT1627_DSW_NOT_READY)) {
if (IS_DEBUG) printf("Wrote to non-ready Plotter\n");
break;
}
plot_cmd = (uint16) ( M[iocc_addr & mem_mask] >> 10 ); /* pick up command */
process_cmd(); /* interpret command */
sim_activate(plot_unit, plot_wait); /* schedule interrupt */
SETBIT(plot_dsw, PLOT1627_DSW_BUSY); /* mark it busy */
break;
case XIO_SENSE_DEV: /* sense device status */
ACC = plot_dsw; /* get current status */
if (iocc_mod & 0x01) { /* reset interrupts */
CLRBIT(plot_dsw, PLOT1627_DSW_OP_COMPLETE);
CLRBIT(ILSW[3], ILSW_3_1627_PLOTTER);
}
break;
case XIO_CONTROL: /* control XIO */
xio_error("Control XIO not supported by 1627 plotter");
break;
default:
sprintf(msg, "Invalid 1627 Plotter XIO function %x", iocc_func);
xio_error(msg);
}
return;
}
// plot_svc - 1627 plotter operation complete
static t_stat plot_svc (UNIT *uptr)
{
CLRBIT(plot_dsw, PLOT1627_DSW_BUSY); /* clear reader busy flag */
SETBIT(plot_dsw, PLOT1627_DSW_OP_COMPLETE); /* indicate read complete */
SETBIT(ILSW[3], ILSW_3_1627_PLOTTER); /* initiate interrupt */
calc_ints();
return SCPE_OK;
}
/* plot_reset - reset emulated plotter */
static t_stat plot_reset (DEVICE *dptr)
{
char * buf;
int32 size;
sim_cancel(plot_unit);
CLRBIT(plot_dsw, PLOT1627_DSW_BUSY | PLOT1627_DSW_OP_COMPLETE);
if (IS_DEBUG) printf("reset routine for Plotter\n");
CLRBIT(ILSW[3], ILSW_3_1627_PLOTTER);
calc_ints();
return SCPE_OK;
}
/* plot_attach - attach file to simulated plotter */
static t_stat plot_attach (UNIT *uptr, char *cptr)
{
t_stat result;
CLRBIT(uptr->flags, UNIT_DEBUG);
if (sim_switches & SWMASK('D')) SETBIT(uptr->flags, UNIT_DEBUG);
/* get the output file by using regular attach routine */
result = attach_unit(uptr, cptr);
if (result != SCPE_OK) {
if (IS_DEBUG) printf("problem attaching file\n");
return result;
}
SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* assume failure */
/* set up our canvas at the desired size */
image = gdImageCreate(plot_ymax+1,plot_xmax+1); /* create our canvas */
if (image == NULL) {
if (IS_DEBUG) printf("problem creating image canvas\n");
return SCPE_MEM;
}
/* set up the basic colors after image created */
white_background = gdImageColorAllocate(image,WHITE); /* white is background */
black_pen = gdImageColorAllocate(image,BLACK); /* load up black color */
blue_pen = gdImageColorAllocate(image,BLUE); /* load up blue color */
red_pen = gdImageColorAllocate(image,RED); /* load up red color */
green_pen = gdImageColorAllocate(image,GREEN); /* load up green color */
yellow_pen = gdImageColorAllocate(image,YELLOW); /* load up yellow color */
purple_pen = gdImageColorAllocate(image,PURPLE); /* load up purple color */
ltgrey_pen = gdImageColorAllocate(image,LTGREY); /* load up light grey color */
grey_pen = gdImageColorAllocate(image,GREY); /* load up grey color */
if ( (white_background == -1) || (black_pen == -1) ||
(red_pen == -1) || (blue_pen == -1) || (green_pen == -1) ||
(purple_pen == -1) || (ltgrey_pen == -1) || (grey_pen == -1) ) {
if (IS_DEBUG) printf("problem allocating pen colors\n");
return SCPE_MEM;
}
CLRBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* we're in business */
update_pen(); /* routine to ensure pen is okay */
return SCPE_OK;
}
/* pen updating routine, called at attach and whenever we reset the values */
void update_pen (void)
{
int color;
int width;
if (!IS_ONLINE(plot_unit)) return; /* only do this if attached */
/* pick up latest color as active pen */
color = GET_COLOR;
switch (color) {
case PEN_BLACK:
plot_pcolor = black_pen;
break;
case PEN_RED:
plot_pcolor = red_pen;
break;
case PEN_BLUE:
plot_pcolor = blue_pen;
break;
case PEN_GREEN:
plot_pcolor = green_pen;
break;
case PEN_YELLOW:
plot_pcolor = yellow_pen;
break;
case PEN_PURPLE:
plot_pcolor = purple_pen;
break;
case PEN_LTGREY:
plot_pcolor = ltgrey_pen;
break;
case PEN_GREY:
plot_pcolor = grey_pen;
break;
default:
if (IS_DEBUG) printf("invalid pen color state\n");
plot_pcolor = black_pen;
break;
}
/* set up anti-aliasing for the line */
gdImageSetAntiAliased(image, plot_pcolor);
/* pick up latest width for pen */
width = GET_WIDTH();
switch (width) {
case PEN_SINGLE:
plot_pwidth = 1;
gdImageSetThickness(image, 1);
break;
case PEN_TRIPLE:
plot_pwidth = 3;
gdImageSetThickness(image, 3);
break;
case PEN_DOUBLE:
plot_pwidth = 2;
gdImageSetThickness(image, 2);
break;
case PEN_QUAD:
plot_pwidth = 4;
gdImageSetThickness(image, 4);
break;
default:
if (IS_DEBUG) printf("invalid pen width\n");
plot_pwidth = 1;
gdImageSetThickness(image, 1);
break;
}
/* now ensure the pen state is accurate */
plot_pen = IS_PENDOWN ? PEN_DOWN : PEN_UP;
return;
}
/* plot_detach - detach file from simulated plotter */
static t_stat plot_detach (UNIT *uptr)
{
char * buf;
int32 size;
FILE * fp;
int32 result;
SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY);
/* copy images to files, close files, set device to detached, free gd memory */
buf = gdImageGifPtr(image,&size);
if (! buf) {
if (IS_DEBUG) printf("failure creating GIF in-memory\n");
return SCPE_MEM;
}
fp = uptr->fileref; /* get file attached to unit */
if (! fseek(fp,0,SEEK_SET)) { /* first we reset to begin of file */
if (IS_DEBUG) printf("wrote out GIF to file\n");
result = fwrite(buf,1,size,fp); /* write out our image to the file */
}
gdFree(buf); /* free up the memory of GIF format */
gdImageDestroy(image); /* free up the canvas memory */
if (result != size) { /* some problem writing it */
if (IS_DEBUG) printf("error in write of image file\n");
return SCPE_IOERR;
}
return detach_unit(uptr); /* have simh close the file */
}
/* process_cmd - implement the drawing actions of the plotter */
static void process_cmd (void)
{
int32 oldx, oldy;
/* first see if we set any changes to pen or position, do an update */
if (need_update) {
update_pen();
need_update = 0;
}
/* will move pen one step or flip pen up or down */
oldx = plot_xpos;
oldy = plot_ypos;
switch (plot_cmd) {
case 1: /* raise pen command */
plot_pen = PEN_UP;
plot_unit->flags = plot_unit->flags & (~UNIT_PEN);
return;
break;
case 2: /* +Y command */
plot_ypos = plot_ypos + 1;
break;
case 4: /* -Y command */
plot_ypos = plot_ypos - 1;
break;
case 8: /* -X command */
plot_xpos = plot_xpos - 1;
break;
case 10: /* -X +Y command */
plot_xpos = plot_xpos - 1;
plot_ypos = plot_ypos + 1;
break;
case 12: /* -X -Y command */
plot_xpos = plot_xpos - 1;
plot_ypos = plot_ypos - 1;
break;
case 16: /* +X command */
plot_xpos = plot_xpos + 1;
break;
case 18: /* +X +Y command */
plot_xpos = plot_xpos + 1;
plot_ypos = plot_ypos + 1;
break;
case 20: /* +X -Y pen command */
plot_xpos = plot_xpos + 1;
plot_ypos = plot_ypos - 1;
break;
case 32: /* lower pen command */
plot_pen = PEN_DOWN;
plot_unit->flags = plot_unit->flags | UNIT_PEN;
return;
break;
default:
if (IS_DEBUG) printf("invalid plotter command\n");
return;
break;
}
/* check to see if carriage has moved off any edge */
if ((plot_xpos > (plot_xmax+1)) || (plot_ypos > (plot_ymax+1)) ||
(plot_xpos < 0) || (plot_ypos < 0)) {
/* if so, ignore as 1627 has no way of signalling error */
if (IS_DEBUG) printf(
"attempted to move carriage off paper edge %d %d for command %d\n",
plot_xpos,plot_ypos,plot_cmd);
return;
}
/* only draw a line if the pen was down during the movement command */
if (plot_pen) {
gdImageLine(image, plot_ymax-plot_ypos, plot_xmax-plot_xpos, plot_ymax-oldy, plot_xmax-oldx, gdAntiAliased);
/* semantics are 0,0 point is lower right */
}
return;
}
/* plot_set_length - validate and store the length of the paper */
static t_stat plot_set_length (UNIT *uptr, int32 set, char *ptr, void *desc)
{
char *cptr;
int32 val;
#define LONGEST_ROLL 1440000 /* longest is 120', 14400", 1,440,000 .01"s */
val = strtotv (ptr, &cptr, (uint32) 10); /* sim routine to get value */
if ((val < 1) | (val >= LONGEST_ROLL)) { /* check valid range */
if (IS_DEBUG) printf("setting paper more than 120' or less than 1 inch\n");
return SCPE_ARG;
}
/* origin zero drawing, reduce by 1 but show command will fudge by adding it back */
*((int32 *)((REG *) desc)->loc) = val - 1;
return SCPE_OK;
}
/* plot_set_pos - validate and store the new position of the carriage */
static t_stat plot_set_pos (UNIT *uptr, int32 set, char *ptr, void *desc)
{
char *cptr;
int32 val;
int32 max;
max = (set == 1) ? plot_ymax : plot_xmax;
val = strtotv (ptr, &cptr, (uint32) 10);
if ((val < 0) | (val > max)) {
if (IS_DEBUG) printf("error moving carriage off paper edge\n");
return SCPE_ARG;
}
*((int32 *)((REG *) desc)->loc) = val;
return SCPE_OK;
}
/* routine to display the paper length and carriage position
* cannot use regular simh routine because it prints values twice,
* once for device and once for unit
*/
static t_stat plot_show_vals (FILE *fp, UNIT *uptr, int32 val, void *descrip)
{
fprintf(fp, "length=%d, Xpos=%d, Ypos=%d",plot_xmax+1, plot_xpos,plot_ypos);
return SCPE_OK;
}
/* routine to add a terminating NL character when 'show plot length'
* or equivalent for xpos or ypos is issued, as simh will not append for us */
static t_stat plot_show_nl(FILE *fp, UNIT *uptr, int32 val, void *descrip)
{
int32 disp;
char *label;
disp = (val == 2) ? plot_xmax + 1 : ((val == 1) ? plot_ypos : plot_xpos);
label = (val == 2) ? "length=" : ((val == 1) ? "Ypos=" : "Xpos=");
fprintf(fp, "%s%d\n", label, disp);
return SCPE_OK;
}
/* plot_validate_change - force the update_pen routine to be called after user changes pen setting */
static t_stat plot_validate_change (UNIT *uptr, int32 set, char *ptr, void *desc)
{
need_update = 1;
return SCPE_OK;
}
#endif /* ENABLE_PLOT_SUPPORT */

View file

@ -5,6 +5,17 @@
Brian Knittel
Revision History
2006.12.06 - Moved CGI stuff out of this routine into cgi1130 main() module.
2006.07.06 - Made 1403 printer 132 columns wide, was 120 previously
2006.01.03 - Fixed bug in prt_attach, found and fixed by Carl Claunch. Detach followed
by reattach of 1403-mode printer left device permanently not-ready.
2004.11.08 - HACK for demo mode: in physical (-p) mode, multiple consecutive formfeeds are suppressed.
This lets us do a formfeed at the end of a job to kick the last page out
without getting another blank page at the beginning of the next job.
2003.12.02 - Added -p option for physical line printer output (flushes
output buffer after each line). When using a physical printer on
Windows, be sure to set printer to "send output directly to printer"
@ -36,6 +47,7 @@
*/
#include "ibm1130_defs.h"
#include <stdlib.h> /* needed for atexit, for cgi mode */
/***************************************************************************************
* 1132 PRINTER
@ -87,6 +99,8 @@ static int32 prt_fwait = 100; /* fast wait, for 1403 operations */
static int32 prt_twait = 50; /* transfer wait, for 1403 operations */
#define SKIPTARGET (uptr->u4) /* target for skip operation */
static t_bool formfed = FALSE; /* last line printed was a formfeed */
#define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */
#define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */
#define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */
@ -145,12 +159,13 @@ DEVICE prt_dev = {
NULL, NULL, &prt_reset,
NULL, prt_attach, prt_detach};
#define PRT_COLUMNS 120
#define PRT_ROWLEN 120
#define MAX_COLUMNS 120
#define MAX_OVPRINT 20
#define PRT1132_COLUMNS 120
#define PRT1403_COLUMNS 120 /* the 1130's version of the 1403 printed in 120 columns only (see Functional Characteristics) */
static char prtbuf[PRT_ROWLEN*MAX_OVPRINT];
static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp;
static char prtbuf[MAX_COLUMNS*MAX_OVPRINT];
static int nprint[MAX_COLUMNS], ncol[MAX_OVPRINT], maxnp;
static int prt_nchar, prt_row; /* current printwheel position, current page row */
static int prt_nnl; /* number of queued newlines */
@ -178,18 +193,18 @@ static struct tag_ccpunches { /* list of rows and punches on tape */
int row, channels;
}
ccpunches[] = {
2, CC_CHANNEL_1, // channel 1 = top of form
62, CC_CHANNEL_12 // channel 12 = bottom of form
2, CC_CHANNEL_1, /* channel 1 = top of form */
62, CC_CHANNEL_12 /* channel 12 = bottom of form */
},
cccgi[] = {
2, CC_CHANNEL_1 // channel 1 = top of form; no bottom of form
2, CC_CHANNEL_1 /* channel 1 = top of form; no bottom of form */
};
#include "ibm1130_prtwheel.h"
extern int32 sim_switches;
// cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read
/* cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read */
static int cc_format_1132 (int bits)
{
@ -200,7 +215,7 @@ static int cc_format_1132 (int bits)
#define cc_format_1403(bits) (bits)
// reset_prt_line - clear the print line following paper advancement
/* reset_prt_line - clear the print line following paper advancement */
static void reset_prt_line (void)
{
@ -209,116 +224,116 @@ static void reset_prt_line (void)
maxnp = 0;
}
// save_1132_prt_line - fire hammers for character 'ch'
/* save_1132_prt_line - fire hammers for character 'ch' */
static t_bool save_1132_prt_line (int ch)
{
int i, r, addr = 32;
int32 mask = 0, wd = 0;
for (i = 0; i < PRT_COLUMNS; i++) {
if (mask == 0) { // fetch next word from memory
for (i = 0; i < PRT1132_COLUMNS; i++) {
if (mask == 0) { /* fetch next word from memory */
mask = 0x8000;
wd = M[addr++];
}
if (wd & mask) { // hammer is to fire in this column
if (wd & mask) { /* hammer is to fire in this column */
if ((r = nprint[i]) < MAX_OVPRINT) {
if (ncol[r] <= i) { // we haven't moved this far yet
if (ncol[r] == 0) // first char in this row?
memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row
ncol[r] = i+1; // remember new row length
if (ncol[r] <= i) { /* we haven't moved this far yet */
if (ncol[r] == 0) /* first char in this row? */
memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1132_COLUMNS); /* blank out the new row */
ncol[r] = i+1; /* remember new row length */
}
prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character
prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */
nprint[i]++; // remember max overprintings for this column
nprint[i]++; /* remember max overprintings for this column */
maxnp = MAX(maxnp, nprint[i]);
}
}
mask >>= 1; // prepare to examine next bit
mask >>= 1; /* prepare to examine next bit */
}
return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set
return wd & 1; /* return TRUE if the last word has lsb set, which means all bits had been set */
}
// write_line - write collected line to output file. No need to trim spaces as the hammers
// are never fired for them, so ncol[r] is the last printed position on each line.
/* write_line - write collected line to output file. No need to trim spaces as the hammers
* are never fired for them, so ncol[r] is the last printed position on each line.
*/
static void newpage (FILE *fd)
static void newpage (FILE *fd, t_bool physical_printer)
{
if (cgi)
fputs("<HR>\n", fd);
else
putc('\f', fd); // formfeed
else if (! formfed) {
putc('\f', fd);
if (physical_printer) {
fflush(fd); /* send the ff out to the printer immediately */
formfed = TRUE; /* hack: inhibit consecutive ff's */
}
}
}
static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush)
static void flush_prt_line (FILE *fd, int spacemode, t_bool physical_printer)
{
int r;
if (! (spacemode || maxnp)) // nothing to do
if (! (spacemode || maxnp)) /* nothing to do */
return;
prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line
prt_row = (prt_row+1) % PRT_PAGELENGTH; /* NEXT line */
if (spacemode && ! maxnp) { // spacing only
if (spacemode && ! maxnp) { /* spacing only */
if (prt_row == 0 && prt_nnl) {
#ifdef _WIN32
if (! cgi)
putc('\r', fd); // DOS/Windows: end with cr/lf
putc('\r', fd); /* DOS/Windows: end with cr/lf */
#endif
putc('\n', fd); // otherwise end with lf
if (spacemode & UNIT_SKIPPING) // add formfeed if we crossed page boundary while skipping
newpage(fd);
putc('\n', fd); /* otherwise end with lf */
if (spacemode & UNIT_SKIPPING) /* add formfeed if we crossed page boundary while skipping */
newpage(fd, physical_printer);
prt_nnl = 0;
}
else
else {
prt_nnl++;
formfed = FALSE;
}
prt_unit->pos++; // note something written
prt_unit->pos++; /* note something written */
return;
}
if (prt_nnl) { // there are queued newlines
// if we spaced to top of form, don't emit formfeed. We'd only ever emit the formfeed if we skipped via control tape channels
// if (prt_row == 0 && prt_nnl) { // we spaced to top of form
//#ifdef _WIN32
// if (! cgi)
// putc('\r', fd); // DOS/Windows: end with cr/lf
//#endif
// putc('\n', fd); // otherwise end with lf
// newpage(fd);
// prt_nnl = 0;
// }
// else {
while (prt_nnl > 0) { // spit out queued newlines
if (prt_nnl) { /* there are queued newlines */
while (prt_nnl > 0) { /* spit out queued newlines */
#ifdef _WIN32
if (! cgi)
putc('\r', fd); // DOS/Windows: end with cr/lf
putc('\r', fd); /* DOS/Windows: end with cr/lf */
#endif
putc('\n', fd); // otherwise end with lf
putc('\n', fd); /* otherwise end with lf */
prt_nnl--;
}
// }
}
for (r = 0; r < maxnp; r++) {
if (r > 0)
putc('\r', fd); // carriage return between overprinted lines
fxwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd);
putc('\r', fd); /* carriage return between overprinted lines */
fxwrite(&prtbuf[r*MAX_COLUMNS], 1, ncol[r], fd);
}
reset_prt_line();
prt_unit->pos++; // note something written
prt_nnl++; // queue a newline
prt_unit->pos++; /* note something written */
prt_nnl++; /* queue a newline */
if (phys_flush) // if physical printer, send buffered output to device
if (physical_printer) /* if physical printer, send buffered output to device */
fflush(fd);
formfed = FALSE; /* note that something is now on the page */
}
// 1132 printer commands
/* 1132 printer commands */
#define PRT_CMD_START_PRINTER 0x0080
#define PRT_CMD_STOP_PRINTER 0x0040
@ -347,7 +362,7 @@ void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)
switch (func) {
case XIO_READ:
M[iocc_addr & mem_mask] = (uint16) (codewheel1132[prt_nchar].ebcdic << 8);
M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8;
if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132;
@ -364,31 +379,31 @@ void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)
case XIO_CONTROL:
if (modify & PRT_CMD_START_PRINTER) {
SETBIT(uptr->flags, UNIT_PRINTING);
// mytrace(1, "printing");
/* mytrace(1, "printing"); */
}
if (modify & PRT_CMD_STOP_PRINTER) {
CLRBIT(uptr->flags, UNIT_PRINTING);
// mytrace(0, "printing");
/* mytrace(0, "printing"); */
}
if (modify & PRT_CMD_START_CARRIAGE) {
SETBIT(uptr->flags, UNIT_SKIPPING);
// mytrace(1, "skipping");
/* mytrace(1, "skipping"); */
}
if (modify & PRT_CMD_STOP_CARRIAGE) {
CLRBIT(uptr->flags, UNIT_SKIPPING);
// mytrace(0, "skipping");
/* mytrace(0, "skipping"); */
}
if (modify & PRT_CMD_SPACE) {
SETBIT(uptr->flags, UNIT_SPACING);
// mytrace(1, "space");
/* mytrace(1, "space"); */
}
sim_cancel(uptr);
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { // busy bits = doing something
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { /* busy bits = doing something */
SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
sim_activate(uptr, prt_cwait);
}
@ -419,14 +434,14 @@ static t_stat prt_svc (UNIT *uptr)
return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr);
}
// prt1132_svc - emulated timeout for 1132 operation
/* prt1132_svc - emulated timeout for 1132 operation */
static t_stat prt1132_svc (UNIT *uptr)
{
if (PRT_DSW & PRT1132_DSW_NOT_READY) { // cancel operation if printer went offline
if (PRT_DSW & PRT1132_DSW_NOT_READY) { /* cancel operation if printer went offline */
SETBIT(uptr->flags, UNIT_FORMCHECK);
SET_ACTION(uptr, 0);
forms_check(TRUE); // and turn on forms check lamp
forms_check(TRUE); /* and turn on forms check lamp */
return SCPE_OK;
}
@ -436,7 +451,7 @@ static t_stat prt1132_svc (UNIT *uptr)
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY);
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE);
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */
calc_ints();
}
@ -445,7 +460,7 @@ static t_stat prt1132_svc (UNIT *uptr)
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK);
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]));
} while ((cctape[prt_row] & CC_1132_BITS) == 0); // slew directly to a cc tape punch
} while ((cctape[prt_row] & CC_1132_BITS) == 0); /* slew directly to a cc tape punch */
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE);
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
@ -453,21 +468,21 @@ static t_stat prt1132_svc (UNIT *uptr)
}
if (uptr->flags & UNIT_PRINTING) {
if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line
SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time
if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { /* save previous printed line */
SETBIT(uptr->flags, UNIT_DATACHECK); /* buffer wasn't set in time */
SET_ACTION(uptr, 0);
print_check(TRUE); // and turn on forms check lamp
print_check(TRUE); /* and turn on forms check lamp */
return SCPE_OK;
}
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; // advance print drum
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; /* advance print drum */
SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer
SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130)
SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); /* issue interrupt to tell printer to set buffer */
SETBIT(ILSW[1], ILSW_1_1132_PRINTER); /* we'll save the printed stuff just before next emitter response (later than on real 1130) */
calc_ints();
}
if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something
if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { /* still doing something */
SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
sim_activate(uptr, prt_cwait);
}
@ -483,18 +498,18 @@ void save_1403_prt_line (int32 addr)
unsigned char ebcdic;
int32 wd;
for (i = 0; i < PRT_COLUMNS; i++) {
if (even) { // fetch next word from memory
for (i = 0; i < PRT1403_COLUMNS; i++) {
if (even) { /* fetch next word from memory */
wd = M[addr++];
ebcdic = (unsigned char) ((wd >> 8) & 0x7F);
even = FALSE;
}
else {
ebcdic = (unsigned char) (wd & 0x7F); // use low byte of previously fetched word
ebcdic = (unsigned char) (wd & 0x7F); /* use low byte of previously fetched word */
even = TRUE;
}
ch = ' '; // translate ebcdic to ascii. Don't bother checking for parity errors
ch = ' '; /* translate ebcdic to ascii. Don't bother checking for parity errors */
for (j = 0; j < WHEELCHARS_1403; j++) {
if (codewheel1403[j].ebcdic == ebcdic) {
ch = codewheel1403[j].ascii;
@ -504,14 +519,14 @@ void save_1403_prt_line (int32 addr)
if (ch > ' ') {
if ((r = nprint[i]) < MAX_OVPRINT) {
if (ncol[r] <= i) { // we haven't moved this far yet
if (ncol[r] == 0) // first char in this row?
memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row
ncol[r] = i+1; // remember new row length
if (ncol[r] <= i) { /* we haven't moved this far yet */
if (ncol[r] == 0) /* first char in this row? */
memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1403_COLUMNS); /* blank out the new row */
ncol[r] = i+1; /* remember new row length */
}
prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character
prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */
nprint[i]++; // remember max overprintings for this column
nprint[i]++; /* remember max overprintings for this column */
maxnp = MAX(maxnp, nprint[i]);
}
}
@ -568,15 +583,15 @@ void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify)
static t_stat prt1403_svc(UNIT *uptr)
{
if (PRT_DSW & PRT1403_DSW_NOT_READY) { // cancel operation if printer went offline
if (PRT_DSW & PRT1403_DSW_NOT_READY) { /* cancel operation if printer went offline */
SET_ACTION(uptr, 0);
forms_check(TRUE); // and turn on forms check lamp
forms_check(TRUE); /* and turn on forms check lamp */
}
else if (uptr->flags & UNIT_TRANSFERRING) { // end of transfer
else if (uptr->flags & UNIT_TRANSFERRING) { /* end of transfer */
CLRBIT(uptr->flags, UNIT_TRANSFERRING);
SETBIT(uptr->flags, UNIT_PRINTING); // schedule "print complete"
SETBIT(uptr->flags, UNIT_PRINTING); /* schedule "print complete" */
SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); // issue transfer complete interrupt
SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); /* issue transfer complete interrupt */
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
}
else if (uptr->flags & UNIT_PRINTING) {
@ -584,14 +599,14 @@ static t_stat prt1403_svc(UNIT *uptr)
CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);
SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE);
SETBIT(ILSW[4], ILSW_4_1403_PRINTER); // issue print complete interrupt
SETBIT(ILSW[4], ILSW_4_1403_PRINTER); /* issue print complete interrupt */
}
else if (uptr->flags & UNIT_SKIPPING) {
do { // find line with exact match of tape punches
do { /* find line with exact match of tape punches */
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
} while (cctape[prt_row] != SKIPTARGET); // slew directly to requested cc tape punch
} while (cctape[prt_row] != SKIPTARGET); /* slew directly to requested cc tape punch */
CLRBIT(uptr->flags, UNIT_SKIPPING); // done with this
CLRBIT(uptr->flags, UNIT_SKIPPING); /* done with this */
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
@ -600,7 +615,7 @@ static t_stat prt1403_svc(UNIT *uptr)
else if (uptr->flags & UNIT_SPACING) {
flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
@ -610,7 +625,7 @@ static t_stat prt1403_svc(UNIT *uptr)
if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING))
sim_activate(uptr, prt_fwait);
CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); // set the two CC bits in the DSW
CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); /* set the two CC bits in the DSW */
if (cctape[prt_row] & CC_CHANNEL_9)
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
if (cctape[prt_row] & CC_CHANNEL_12)
@ -646,16 +661,17 @@ static t_stat prt_reset (DEVICE *dptr)
UNIT *uptr = &prt_unit[0];
int i;
// add a DELETE filename command so we can be sure to have clean listings
/* add a DELETE filename command so we can be sure to have clean listings */
register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n");
sim_cancel(uptr);
memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image
memset(cctape, 0, sizeof(cctape)); /* copy punch list into carriage control tape image */
if (cgi)
if (cgi) {
for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++)
cctape[cccgi[i].row-1] |= cccgi[i].channels;
}
else
for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++)
cctape[ccpunches[i].row-1] |= ccpunches[i].channels;
@ -697,6 +713,7 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
t_stat rval;
/* assume failure */
SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY);
formfed = FALSE;
if (uptr->flags & UNIT_ATT) {
if ((rval = prt_detach(uptr)) != SCPE_OK) {
@ -745,7 +762,7 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
reset_prt_line();
if (IS_1132(uptr)) {
PRT_DSW = (uint16) ((PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]));
PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]);
if (IS_ONLINE(uptr))
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
@ -758,10 +775,11 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
if (IS_ONLINE(uptr))
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
CLRBIT(PRT_DSW, PRT1403_DSW_NOT_READY); /* fixed by Carl Claunch */
}
forms_check(FALSE);
return SCPE_OK;
}
@ -769,6 +787,7 @@ static t_stat prt_detach (UNIT *uptr)
{
t_stat rval;
if (uptr->flags & UNIT_ATT)
flush_prt_line(uptr->fileref, TRUE, TRUE);
if (uptr->fileref == stdout) {
@ -797,3 +816,4 @@ static t_stat prt_detach (UNIT *uptr)
forms_check(FALSE);
return SCPE_OK;
}

View file

@ -81,7 +81,7 @@ DEVICE ptp_dev = {
/* xio_1134_papertape - XIO command interpreter for the 1134 paper tape reader and 1055 paper tape punch */
void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod)
void xio_1134_papertape (int32 iocc_addr, int32 iocc_func, int32 iocc_mod)
{
char msg[80];
@ -118,7 +118,7 @@ void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod)
}
}
// ptr_svc - emulated timeout - 1134 read operation complete
/* ptr_svc - emulated timeout - 1134 read operation complete */
static t_stat ptr_svc (UNIT *uptr)
{
@ -141,7 +141,7 @@ static t_stat ptr_svc (UNIT *uptr)
return SCPE_OK;
}
// ptp_svc - emulated timeout -- 1055 punch operation complete
/* ptp_svc - emulated timeout -- 1055 punch operation complete */
static t_stat ptp_svc (UNIT *uptr)
{
@ -245,37 +245,37 @@ static t_stat ptr_boot (int unitno, DEVICE *dptr)
}
if (leader) {
if ((ch & 0x7F) == 0x7F) // ignore leading rubouts or "delete" characters
if ((ch & 0x7F) == 0x7F) /* ignore leading rubouts or "delete" characters */
continue;
leader = FALSE; // after first nonrubout, any punch in channel 5 terminates load
leader = FALSE; /* after first nonrubout, any punch in channel 5 terminates load */
}
// this is untested -- not sure of actual byte ordering
/* this is untested -- not sure of actual byte ordering */
val = (val << 4) | (ch & 0x0F); // get next nybble
val = (val << 4) | (ch & 0x0F); /* get next nybble */
if (++nch == 4) { // if we now have four nybbles, store the word
if (++nch == 4) { /* if we now have four nybbles, store the word */
M[addr & mem_mask] = (uint16) val;
addr++; // prepare for next word
addr++; /* prepare for next word */
nch = 0;
val = 0;
}
if (ch & 0x10) { // channel 5 punch terminates load
if (ch & 0x10) { /* channel 5 punch terminates load */
start = TRUE;
break;
}
}
if (! start) // if we didn't get a valid load, report EOF error
if (! start) /* if we didn't get a valid load, report EOF error */
return SCPE_EOF;
if ((rval = reset_all(0)) != SCPE_OK) // force a reset
if ((rval = reset_all(0)) != SCPE_OK) /* force a reset */
return rval;
IAR = 0; // start running at address 0
IAR = 0; /* start running at address 0 */
return SCPE_OK;
}

1164
Ibm1130/ibm1130_sca.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -91,16 +91,13 @@
static void badio (char *dev)
{
// the real 1130 just ignores attempts to use uninstalled devices. They get tested
// at times, so it's best to just be quiet about this
// printf("%s I/O is not yet supported", dev);
/* the real 1130 just ignores attempts to use uninstalled devices. They get tested
* at times, so it's best to just be quiet about this
* printf("%s I/O is not yet supported", dev);
*/
}
// void xio_1134_papertape (int32 addr, int32 func, int32 modify) {badio("papertape");}
void xio_1627_plotter (int32 addr, int32 func, int32 modify) {badio("plotter");}
void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical mark");}
void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");}
void xio_1131_synch (int32 addr, int32 func, int32 modify) {badio("SCA");}
void xio_system7 (int32 addr, int32 func, int32 modify) {badio("System 7");}
/* ---------------------------------------------------------------------------- */
@ -120,7 +117,7 @@ extern int cgi;
static int32 tti_dsw = 0; /* device status words */
static int32 tto_dsw = 0;
static int32 con_dsw = 0;
int32 con_dsw = 0;
static unsigned char conout_map[256]; /* 1130 console code to ASCII translation. 0 = undefined, 0xFF = IGNR_ = no output */
static unsigned char conin_map[256]; /* input mapping */
@ -211,9 +208,10 @@ DEVICE tti_dev = {
tto_reg TTO register list
*/
// 14-Nov-03 -- the wait time was SERIAL_OUT_WAIT, but recent versions of SIMH reduced
// this to 100, and wouldn't you know it, APL\1130 has about 120 instructions between the XIO WRITE
// to the console and the associated WAIT.
/* 14-Nov-03 -- the wait time was SERIAL_OUT_WAIT, but recent versions of SIMH reduced
* this to 100, and wouldn't you know it, APL\1130 has about 120 instructions between the XIO WRITE
* to the console and the associated WAIT.
*/
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), 200 };
@ -279,7 +277,7 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify)
ch = (ReadW(iocc_addr) >> 8) & 0xFF; /* get character to write */
tto_unit.buf = emit_conout_character(ch); /* output character and save write status */
// fprintf(stderr, "[CONOUT] %02x\n", ch);
/* fprintf(stderr, "[CONOUT] %02x\n", ch); */
SETBIT(tto_dsw, TT_DSW_PRINTER_BUSY);
sim_activate(&tto_unit, tto_unit.wait); /* schedule interrupt */
@ -300,10 +298,10 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify)
xio_error(msg);
}
// fprintf(stderr, "After XIO %04x %04x\n", tti_dsw, tto_dsw);
/* fprintf(stderr, "After XIO %04x %04x\n", tti_dsw, tto_dsw); */
}
// emit_conout_character - write character with 1130 console code 'ch'
/* emit_conout_character - write character with 1130 console code 'ch' */
t_stat emit_conout_character (int ch)
{
@ -342,12 +340,12 @@ t_stat emit_conout_character (int ch)
return map_conout_character(ch);
}
static void Beep (void) // notify user keyboard was locked or key was bad
static void Beep (void) /* notify user keyboard was locked or key was bad */
{
sim_putchar(7);
}
// tti_svc - keyboard polling (never stops)
/* tti_svc - keyboard polling (never stops) */
static t_stat tti_svc (UNIT *uptr)
{
@ -386,7 +384,7 @@ static t_stat tti_svc (UNIT *uptr)
if (temp == PROGRAM_STOP_KEY) { /* simulate the program stop button */
SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);
calc_ints();
#ifdef DEBUG_CONSOLE
@ -417,16 +415,13 @@ static t_stat tti_svc (UNIT *uptr)
printf("[%04x]", tti_unit.buf & 0xFFFF);
#endif
// CLRBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY); /* clear busy flag (unselect keyboard) */
// keyboard_selected(FALSE);
SETBIT(tti_unit.flags, KEYBOARD_LOCKED); /* prevent further keystrokes */
SETBIT(tti_dsw, TT_DSW_KEYBOARD_RESPONSE); /* queue interrupt */
SETBIT(ILSW[4], ILSW_4_CONSOLE);
calc_ints();
// fprintf(stderr, "TTI interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw);
/* fprintf(stderr, "TTI interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); */
return SCPE_OK;
}
@ -450,14 +445,14 @@ static t_stat tti_reset (DEVICE *dptr)
return SCPE_OK;
}
// basic_attach - fix quotes in filename, then call standard unit attach routine
/* basic_attach - fix quotes in filename, then call standard unit attach routine */
t_stat basic_attach (UNIT *uptr, char *cptr)
{
return attach_unit(uptr, quotefix(cptr)); /* fix quotes in filenames & attach */
}
// quotefix - strip off quotes around filename, if present
/* quotefix - strip off quotes around filename, if present */
char * quotefix (char * cptr)
{
@ -492,7 +487,7 @@ static t_stat tto_svc (UNIT *uptr)
SETBIT(ILSW[4], ILSW_4_CONSOLE);
calc_ints();
// fprintf(stderr, "TTO interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw);
/* fprintf(stderr, "TTO interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); */
return (t_stat) tto_unit.buf; /* return status saved during output conversion */
}
@ -648,7 +643,7 @@ static struct { /* default output mapping for APLPLUS font */
#define NCONOUT_TO_APL (sizeof(conout_to_APL)/sizeof(conout_to_APL[0]))
static OS_MAP default_os_map[] = // overstrike mapping for APLPLUS font
static OS_MAP default_os_map[] = /* overstrike mapping for APLPLUS font */
{
'\x8a', 2, "\x5e\x7e",
'\x8b', 2, "\x9f\x7e",
@ -717,12 +712,12 @@ static void strsort (int n, unsigned char *s)
unsigned char temp;
int i, big;
while (--n > 0) { // repeatedly
big = 0; // find largest value of s[0]...s[n]
while (--n > 0) { /* repeatedly */
big = 0; /* find largest value of s[0]...s[n] */
for (i = 1; i <= n; i++)
if (s[i] > s[big]) big = i;
temp = s[n]; // put largest value at end of array
temp = s[n]; /* put largest value at end of array */
s[n] = s[big];
s[big] = temp;
}
@ -730,10 +725,10 @@ static void strsort (int n, unsigned char *s)
/* file format:
[font XXX] // font named XXX
OUT // failure character
OUT IN // single character mapping
OUT IN IN ... // overstrike mapping
[font XXX] font named XXX
OUT failure character
OUT IN single character mapping
OUT IN IN ... overstrike mapping
*/
@ -742,35 +737,35 @@ static void set_conout_mapping (int32 flags)
curcol = 0;
maxcol = 0;
// set the default mappings. We may later override them with settings from an ini file
/* set the default mappings. We may later override them with settings from an ini file */
set_default_mapping(flags);
}
// finish_conout_mapping - sort the finalized overstrike mapping
/* finish_conout_mapping - sort the finalized overstrike mapping */
static void finish_conout_mapping (int32 flags)
{
int i, n, big;
OS_MAP temp;
for (i = 0; i < n_os_mappings; i++) // sort the inlist strings individually
for (i = 0; i < n_os_mappings; i++) /* sort the inlist strings individually */
strsort(os_map[i].nin, os_map[i].inlist);
for (n = n_os_mappings; --n > 0; ) { // then sort the os_map array itself with insertion sort
big = 0; // find largest value of s[0]...s[n]
for (n = n_os_mappings; --n > 0; ) { /* then sort the os_map array itself with insertion sort */
big = 0; /* find largest value of s[0]...s[n] */
for (i = 1; i <= n; i++)
if (os_map_comp(os_map+i, os_map+big) > 0) big = i;
if (big != n) {
temp = os_map[n]; // put largest value at end of array
temp = os_map[n]; /* put largest value at end of array */
os_map[n] = os_map[big];
os_map[big] = temp;
}
}
}
// validate_conout_mapping - called when set command gets a new value
/* validate_conout_mapping - called when set command gets a new value */
static t_stat validate_conout_mapping (UNIT *uptr, int32 match, char *cvptr, void *desc)
{
@ -793,7 +788,7 @@ static void reset_mapping (void)
conin_map[i] = (unsigned char) i; /* default conin_map is identity map */
}
// set_default_mapping - create standard font and overstrike map
/* set_default_mapping - create standard font and overstrike map */
static void set_default_mapping (int32 flags)
{
@ -824,10 +819,10 @@ static void set_default_mapping (int32 flags)
break;
}
finish_conout_mapping(flags); // sort conout mapping if necessary
finish_conout_mapping(flags); /* sort conout mapping if necessary */
}
// sim_putstr - write a string to the console
/* sim_putstr - write a string to the console */
t_stat sim_putstr (char *s)
{
@ -843,7 +838,7 @@ t_stat sim_putstr (char *s)
return SCPE_OK;
}
// map_conout_character - translate and write a single character
/* map_conout_character - translate and write a single character */
static t_stat map_conout_character (int ch)
{
@ -857,54 +852,54 @@ static t_stat map_conout_character (int ch)
return (tto_unit.flags & ENABLE_ANSI) ? sim_putstr((char *) red_ribbon) : SCPE_OK;
if ((ch = conout_map[ch & 0xFF]) == 0)
ch = '?'; // unknown character? print ?
ch = '?'; /* unknown character? print ? */
if (ch == '\n') { // newline: reset overstrike buffer
if (ch == '\n') { /* newline: reset overstrike buffer */
curcol = 0;
maxcol = -1;
}
else if (ch == '\r') { // carriage return: rewind to column 0
else if (ch == '\r') { /* carriage return: rewind to column 0 */
curcol = 0;
maxcol = -1; // assume it advances paper too
maxcol = -1; /* assume it advances paper too */
}
else if (ch == '\b') { // backspace: back up one character
else if (ch == '\b') { /* backspace: back up one character */
if (curcol > 0)
curcol--;
}
else if (n_os_mappings && ch != (unsigned char) IGNR_) {
if (curcol >= MAX_OUTPUT_COLUMNS)
map_conout_character('\x81'); // precede with automatic carriage return/line feed, I guess
map_conout_character('\x81'); /* precede with automatic carriage return/line feed, I guess */
if (curcol > maxcol) { // first time in this column, no overstrike possible yet
if (curcol > maxcol) { /* first time in this column, no overstrike possible yet */
os_buf[curcol].nin = 0;
maxcol = curcol;
}
if (ch != ' ' && ch != 0) { // (if it's not a blank or unknown)
if (ch != ' ' && ch != 0) { /* (if it's not a blank or unknown) */
os_buf[curcol].inlist[os_buf[curcol].nin] = (unsigned char) ch;
strsort(++os_buf[curcol].nin, os_buf[curcol].inlist);
}
if (os_buf[curcol].nin == 0) // if nothing but blanks seen,
ch = ' '; // output is a blank
else if (os_buf[curcol].nin == 1) { // if only one printing character seen, display it
if (os_buf[curcol].nin == 0) /* if nothing but blanks seen, */
ch = ' '; /* output is a blank */
else if (os_buf[curcol].nin == 1) { /* if only one printing character seen, display it */
ch = os_buf[curcol].inlist[0];
}
else { // otherwise look up mapping
else { /* otherwise look up mapping */
ch = '?';
for (i = 0; i < n_os_mappings; i++) {
cmp = os_map_comp(&os_buf[curcol], &os_map[i]);
if (cmp == 0) { // a hit
if (cmp == 0) { /* a hit */
ch = os_map[i].ch;
break;
}
else if (cmp < 0) // not found
else if (cmp < 0) /* not found */
break;
}
}
if (curcol < MAX_OUTPUT_COLUMNS) // this should now never happen, as we automatically return
if (curcol < MAX_OUTPUT_COLUMNS) /* this should now never happen, as we automatically return */
curcol++;
}

View file

@ -3,6 +3,7 @@
Based on PDP-11 simulator written by Robert M Supnik
Revision History
0.27 2005Mar08 - Added sca device
0.26 2002Apr24 - Added !BREAK in card deck file to stop simulator
0.25 2002Apr18 - Fixed some card reader problems. It starts the reader
properly if you attach a deck while it's waiting to a read.
@ -27,9 +28,9 @@
#include <ctype.h>
#include <stdarg.h>
extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev, prt_dev, log_dev;
extern DEVICE gdu_dev, console_dev;
extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev, t2741_dev;
extern DEVICE tti_dev, tto_dev, prt_dev, log_dev, sca_dev;
extern DEVICE gdu_dev, console_dev, plot_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
@ -61,8 +62,11 @@ DEVICE *sim_devices[] = {
&prt_dev, /* 1132 printer */
&ptr_dev, /* 1134 paper tape reader */
&ptp_dev, /* 1055 paper tape punch */
&sca_dev, /* Synchronous communications adapter option */
&console_dev, /* console display (windows GUI) */
&gdu_dev, /* 2250 display */
&t2741_dev, /* nonstandard serial interface used by APL\1130 */
&plot_dev, /* plotter device, in ibm1130_plot.c */
NULL
};
@ -76,7 +80,11 @@ const char *sim_stop_messages[] = {
"!BREAK in card deck file",
"Phase load break",
"Program has run amok",
"Run time limit exceeded"
"Run time limit exceeded",
"Immediate Stop key requested",
"Simulator break key pressed",
"Simulator step count expired",
"Simulator IO error",
};
/* Loader. IPL is normally performed by card reader (boot command). This function
@ -106,13 +114,13 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam)
int iaddr = -1, runaddr = -1, val, nwords;
while (fgets(line, sizeof(line), fileref) != NULL) {
for (c = line; *c && *c <= ' '; c++) // find first nonblank
for (c = line; *c && *c <= ' '; c++) /* find first nonblank */
;
if (*c == '\0' || *c == '#' || *c == '/' || *c == ';')
continue; // empty line or comment
continue; /* empty line or comment */
if (*c == '@') { // set load address
if (*c == '@') { /* set load address */
if (sscanf(c+1, "%x", &iaddr) != 1)
return SCPE_FMT;
}
@ -124,7 +132,7 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam)
if (sscanf(c+1, "%x", &val) != 1)
return SCPE_FMT;
CES = val & 0xFFFF; // preload console entry switches
CES = val & 0xFFFF; /*preload console entry switches */
}
else if (*c == 'z' || *c == 'Z') {
if (sscanf(c+1, "%x", &nwords) != 1)
@ -145,11 +153,11 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam)
if (iaddr == -1)
return SCPE_FMT;
WriteW(iaddr, val); // store data
WriteW(iaddr, val); /*store data */
iaddr++;
}
else
return SCPE_FMT; // unexpected data
return SCPE_FMT; /*unexpected data */
}
if (runaddr != -1)
@ -166,14 +174,14 @@ t_stat my_save (FILE *fileref, char *cptr, char *fnam)
fprintf(fileref, "@0000\r\n");
for (iaddr = 0; iaddr < nwords; iaddr++) {
val = ReadW(iaddr);
if (val == 0) // queue up zeroes
if (val == 0) /*queue up zeroes */
nzeroes++;
else {
if (nzeroes >= 4) { // spit out a Z directive
if (nzeroes >= 4) { /*spit out a Z directive */
fprintf(fileref, "Z%04x\r\n", nzeroes);
nzeroes = 0;
}
else { // write queued zeroes literally
else { /*write queued zeroes literally */
while (nzeroes > 0) {
fprintf(fileref, " 0000\r\n");
nzeroes--;
@ -182,7 +190,7 @@ t_stat my_save (FILE *fileref, char *cptr, char *fnam)
fprintf(fileref, " %04x\r\n", val);
}
}
if (nzeroes >= 4) { // emit any queued zeroes
if (nzeroes >= 4) { /*emit any queued zeroes */
fprintf(fileref, "Z%04x\r\n", nzeroes);
nzeroes = 0;
}
@ -241,7 +249,7 @@ static char *opcode[] = {
"AND ", "OR ", "EOR ", "?1F ",
};
static char relative[] = { // true if short mode displacements are IAR relative
static char relative[] = { /*true if short mode displacements are IAR relative */
FALSE, TRUE, FALSE, FALSE,
FALSE, TRUE, FALSE, FALSE,
TRUE, FALSE, FALSE, FALSE,
@ -287,10 +295,11 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
cflag = (uptr == NULL) || (uptr == &cpu_unit);
// if (sw & SWMASK ('A')) { /* ASCII? not useful */
// fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
// return SCPE_OK;
// }
/* if (sw & SWMASK ('A')) { // ASCII? not useful
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
return SCPE_OK;
}
*/
if (sw & SWMASK ('C')) /* character? not useful -- make it EBCDIC */
sw |= SWMASK('E');
@ -349,7 +358,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
DSPLC &= 0x003F;
eaddr = DSPLC;
}
else if ((OP == 0x08 && F)|| OP == 0x09) { // BSI L and BSC any
else if ((OP == 0x08 && F)|| OP == 0x09) { /* BSI L and BSC any */
if (OP == 0x09 && (IR & 0x40))
mnem = "BOSC";
@ -368,7 +377,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
fprintf(of, "%04x %s %c%c %s ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst);
return SCPE_OK;
}
else if (OP == 0x0e && TAG == 0) { // MDX with no tag => MDM or jump
else if (OP == 0x0e && TAG == 0) { /* MDX with no tag => MDM or jump */
if (F) {
fprintf(of, "%04x %s %c%c %04x,%x (%d) ", IR & 0xFFFF, "MDM ", (INDIR ? 'I' : 'L'), tagc[TAG], eaddr & 0xFFFF, DSPLC & 0xFFFF, DSPLC);
return -1;
@ -446,47 +455,47 @@ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
#ifndef _WIN32
int strnicmp (char *a, char *b, int n)
int strnicmp (const char *a, const char *b, int n)
{
int ca, cb;
for (;;) {
if (--n < 0) // still equal after n characters? quit now
if (--n < 0) /* still equal after n characters? quit now */
return 0;
if ((ca = *a) == 0) // get character, stop on null terminator
if ((ca = *a) == 0) /* get character, stop on null terminator */
return *b ? -1 : 0;
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */
ca -= 32;
cb = *b;
if (cb >= 'a' && cb <= 'z')
cb -= 32;
if ((ca -= cb) != 0) // if different, return comparison
if ((ca -= cb) != 0) /* if different, return comparison */
return ca;
a++, b++;
}
}
int strcmpi (char *a, char *b)
int strcmpi (const char *a, const char *b)
{
int ca, cb;
for (;;) {
if ((ca = *a) == 0) // get character, stop on null terminator
if ((ca = *a) == 0) /* get character, stop on null terminator */
return *b ? -1 : 0;
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */
ca -= 32;
cb = *b;
if (cb >= 'a' && cb <= 'z')
cb -= 32;
if ((ca -= cb) != 0) // if different, return comparison
if ((ca -= cb) != 0) /* if different, return comparison */
return ca;
a++, b++;

388
Ibm1130/ibm1130_t2741.c Normal file
View file

@ -0,0 +1,388 @@
/***************************************************************************************
* Nonstandard serial attachment for remote 2741 terminal (IO selectric) used by APL\1130
* This implementation may be incomplete and/or incorrect
***************************************************************************************/
#include "ibm1130_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#define DEBUG_T2741
static TMLN t2741_ldsc = { 0 }; /* line descr for telnet attachment */
static TMXR t2741_tmxr = { 1, 0, 0, &t2741_ldsc }; /* line mux for telnet attachment */
#define T2741_DSW_TRANSMIT_NOT_READY 0x4000
#define T2741_DSW_READ_RESPONSE 0x1000
#define T2741_DSW_READ_OVERRUN 0x0800
#define T2741_DSW_ATTENTION 0x0010
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
#define UNIT_V_PHYSICAL_TERM (UNIT_V_UF + 0) /* indicates not telnet but attachment to real terminal */
#define UNIT_V_UPCASE (UNIT_V_UF + 1) /* indicates upshift performed */
#define UNIT_V_SENDING (UNIT_V_UF + 2) /* indicates not telnet but attachment to real terminal */
#define UNIT_V_RECEIVING (UNIT_V_UF + 3) /* indicates not telnet but attachment to real terminal */
#define UNIT_PHYSICAL_TERM (1u << UNIT_V_PHYSICAL_TERM)
#define UNIT_UPCASE (1u << UNIT_V_UPCASE)
#define UNIT_SENDING (1u << UNIT_V_SENDING)
#define UNIT_RECEIVING (1u << UNIT_V_RECEIVING)
#define CODE_SHIFTUP 0x1C00
#define CODE_SHIFTDOWN 0x7C00
#define CODE_CIRCLEC 0x1F00
#define CODE_CIRCLED 0x1600
#define CODE_RETURN 0x5B00
#define CODE_LINEFEED 0x3B00
#define CODE_ATTENTION 0x0001 /* pseudocode, never really returned as a received character */
#define CODE_UNKNOWN 0x0000
static t_stat t2741_svc (UNIT *uptr);
static t_stat t2741_reset (DEVICE *dptr);
static t_stat t2741_attach (UNIT *uptr, char *cptr);
static t_stat t2741_detach (UNIT *uptr);
static uint16 ascii_to_t2741 (int ascii);
static char * t2741_to_ascii (uint16 code);
static void set_transmit_notready (void);
static uint16 t2741_dsw = T2741_DSW_TRANSMIT_NOT_READY; /* device status word */
static uint32 t2741_swait = 200; /* character send wait */
static uint32 t2741_rwait = 2000; /* character receive wait */
static uint16 t2741_char = 0; /* last character received */
static int overrun = FALSE;
static uint32 t2741_socket = 1130;
UNIT t2741_unit[1] = {
{ UDATA (&t2741_svc, UNIT_ATTABLE, 0) },
};
REG t2741_reg[] = {
{ HRDATA (DSW, t2741_dsw, 16) }, /* device status word */
{ DRDATA (RTIME, t2741_rwait, 24), PV_LEFT }, /* character receive wait */
{ DRDATA (STIME, t2741_swait, 24), PV_LEFT }, /* character send wait */
{ DRDATA (SOCKET, t2741_socket,16), PV_LEFT }, /* socket number */
{ HRDATA (LASTCHAR, t2741_char, 16), PV_LEFT }, /* last character read */
{ NULL } };
DEVICE t2741_dev = {
"T2741", t2741_unit, t2741_reg, NULL,
1, 16, 16, 1, 16, 16,
NULL, NULL, t2741_reset,
NULL, t2741_attach, t2741_detach};
/* xio_t2741_terminal - XIO command interpreter for the terminal adapter */
void xio_t2741_terminal (int32 iocc_addr, int32 iocc_func, int32 iocc_mod)
{
char msg[80];
uint16 code;
switch (iocc_func) {
case XIO_READ: /* read: return last character read */
code = t2741_char & 0xFF00;
M[iocc_addr & mem_mask] = code;
overrun = FALSE;
#ifdef DEBUG_T2741
/* trace_both("T2741 %04x READ %02x %s", prev_IAR, code >> 8, t2741_to_ascii(code)); */
#endif
break;
case XIO_WRITE: /* write: initiate character send */
code = M[iocc_addr & mem_mask] & 0xFF00;
#ifdef DEBUG_T2741
trace_both("T2741 %04x SEND %02x %s", prev_IAR, code >> 8, t2741_to_ascii(code));
#endif
SETBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY);
SETBIT(t2741_unit->flags, UNIT_SENDING);
if (code == CODE_SHIFTUP)
SETBIT(t2741_unit->flags, UNIT_UPCASE);
else if (code == CODE_SHIFTDOWN)
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
sim_activate(t2741_unit, t2741_swait); /* schedule interrupt */
break;
case XIO_SENSE_DEV: /* sense device status */
ACC = t2741_dsw;
#ifdef DEBUG_T2741
/* trace_both("T2741 %04x SENS %04x%s", prev_IAR, t2741_dsw, (iocc_mod & 0x01) ? " reset" : ""); */
#endif
if (iocc_mod & 0x01) { /* reset interrupts */
CLRBIT(t2741_dsw, T2741_DSW_READ_RESPONSE);
CLRBIT(ILSW[4], ILSW_4_T2741_TERMINAL);
}
break;
case XIO_CONTROL: /* control: do something to interface */
#ifdef DEBUG_T2741
trace_both("T2741 %04x CTRL %04x", prev_IAR, iocc_mod &0xFF);
#endif
SETBIT(t2741_unit->flags, UNIT_RECEIVING); /* set mode to receive mode */
if (IS_ONLINE(t2741_unit) && (t2741_char != 0 || ! feof(t2741_unit->fileref))) {
sim_activate(t2741_unit, t2741_rwait);
t2741_char = (CODE_CIRCLED >> 8); /* first character received after turnaround is circled */
}
break;
default:
sprintf(msg, "Invalid T2741 XIO function %x", iocc_func);
xio_error(msg);
}
}
static void set_transmit_notready (void)
{
if (IS_ONLINE(t2741_unit) && ! (t2741_unit->flags & UNIT_SENDING))
CLRBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY);
else
SETBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY);
}
static t_stat t2741_svc (UNIT *uptr)
{
int ch = EOF;
uint16 code;
if (uptr->flags & UNIT_SENDING) { /* xmit: no interrupt, as far as I know. just clr busy bit */
CLRBIT(uptr->flags, UNIT_SENDING);
set_transmit_notready();
}
if (uptr->flags & UNIT_RECEIVING) { /* rcv: fire interrupt */
t2741_char <<= 8;
if (t2741_char == 0) { /* there is no 2nd character from previous ascii input */
if ((ch = getc(t2741_unit->fileref)) == EOF)
t2741_char = 0;
else {
if (ch == '\r') { /* if we get CR, jump to LF */
if ((ch = getc(t2741_unit->fileref)) != '\n') {
ungetc(ch, t2741_unit->fileref);
ch = '\r';
}
}
if (ch == '\027') {
t2741_char = CODE_LINEFEED; /* attention key sends line feed character */
#ifdef DEBUG_T2741
trace_both("T2741 ---- ATTENTION");
#endif
SETBIT(t2741_dsw, T2741_DSW_ATTENTION); /* no character returned ? */
}
else {
t2741_char = ascii_to_t2741(ch); /* translate to 2741 code(s) */
}
}
}
code = t2741_char & 0xFF00;
if (t2741_char != 0) {
if (overrun) /* previous character was not picked up! */
SETBIT(t2741_dsw, T2741_DSW_READ_OVERRUN);
SETBIT(t2741_dsw, T2741_DSW_READ_RESPONSE);
SETBIT(ILSW[4], ILSW_4_T2741_TERMINAL); /* issue interrupt */
calc_ints();
#ifdef DEBUG_T2741
trace_both("T2741 ---- RCVD %02x '%s' RDRESP%s%s", code >> 8, t2741_to_ascii(code),
(t2741_dsw & T2741_DSW_READ_OVERRUN) ? "|OVERRUN" : "",
(t2741_dsw & T2741_DSW_ATTENTION) ? "|ATTENTION" : "");
#endif
overrun = TRUE; /* arm overrun flag */
}
if (t2741_char == CODE_CIRCLEC) /* end of line (CIRCLEC after RETURN) auto downshifts */
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
if (t2741_char == 0 || code == CODE_CIRCLEC)
CLRBIT(uptr->flags, UNIT_RECEIVING); /* on enter or EOF, stop typing */
else
sim_activate(t2741_unit, t2741_rwait); /* schedule next character to arrive */
}
return SCPE_OK;
}
static t_stat t2741_attach (UNIT *uptr, char *cptr)
{
int rval;
if ((rval = attach_unit(uptr, cptr)) == SCPE_OK) { /* use standard attach */
t2741_char = 0;
overrun = FALSE;
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
if ((t2741_unit->flags & UNIT_RECEIVING) && ! feof(t2741_unit->fileref))
sim_activate(t2741_unit, t2741_rwait); /* schedule interrupt */
}
set_transmit_notready();
return rval;
}
static t_stat t2741_detach (UNIT *uptr)
{
t_stat rval;
if (t2741_unit->flags & UNIT_RECEIVING) /* if receive was pending, cancel interrupt */
sim_cancel(t2741_unit);
t2741_char = 0;
overrun = FALSE;
rval = detach_unit(uptr); /* use standard detach */
set_transmit_notready();
return rval;
}
static t_stat t2741_reset (DEVICE *dptr)
{
sim_cancel(t2741_unit);
CLRBIT(t2741_unit->flags, UNIT_SENDING|UNIT_RECEIVING|UNIT_UPCASE);
t2741_char = 0;
t2741_dsw = 0;
overrun = FALSE;
set_transmit_notready();
CLRBIT(ILSW[4], ILSW_4_T2741_TERMINAL);
calc_ints();
return SCPE_OK;
}
static struct tag_t2741_map {
int code;
int lcase, ucase;
t_bool shifts;
} t2741_map[] = {
{0x4F00, 'A', 'a', TRUE},
{0x3700, 'B', 'b', TRUE},
{0x2F00, 'C', 'c', TRUE},
{0x2A00, 'D', 'd', TRUE},
{0x2900, 'E', 'e', TRUE},
{0x6700, 'F', '_', TRUE},
{0x6200, 'G', 'g', TRUE},
{0x3200, 'H', 'h', TRUE},
{0x4C00, 'I', 'i', TRUE},
{0x6100, 'J', 'j', TRUE},
{0x2C00, 'K', '\'', TRUE},
{0x3100, 'L', 'l', TRUE},
{0x4300, 'M', '|', TRUE},
{0x2500, 'N', 'n', TRUE},
{0x5100, 'O', 'o', TRUE},
{0x6800, 'P', '*', TRUE},
{0x6D00, 'Q', '?', TRUE},
{0x4A00, 'R', 'r', TRUE},
{0x5200, 'S', 's', TRUE},
{0x2000, 'T', '~', TRUE},
{0x2600, 'U', 'u', TRUE},
{0x4600, 'V', 'v', TRUE},
{0x5700, 'W', 'w', TRUE},
{0x2300, 'X', 'x', TRUE},
{0x7300, 'Y', 'y', TRUE},
{0x1500, 'Z', 'z', TRUE},
{0x1300, '0', '&', TRUE},
{0x0200, '1', '?', TRUE},
{0x0400, '2', '?', TRUE},
{0x0700, '3', '<', TRUE},
{0x1000, '4', '?', TRUE},
{0x0800, '5', '=', TRUE},
{0x0D00, '6', '?', TRUE},
{0x0B00, '7', '>', TRUE},
{0x0E00, '8', '?', TRUE},
{0x1600, '9', '|', TRUE},
{0x7000, '/', '\\', TRUE},
{0x7600, '+', '-', TRUE},
{0x6400, '?', '?', TRUE},
{0x4000, '<', '>', TRUE},
{0x6B00, '[', '(', TRUE},
{0x4900, ']', ')', TRUE},
{0x6E00, ',', ';', TRUE},
{0x4500, '.', ':', TRUE},
{0x0100, ' ', 0, FALSE},
{0x5B00, '\r', 0, FALSE},
{0x3B00, '\n', 0, FALSE},
{0x5D00, '\b', 0, FALSE},
{0x5E00, '\t', 0, FALSE},
{0x0001, '\027', 0, FALSE},
};
static uint16 ascii_to_t2741 (int ascii)
{
int i;
uint16 rval = 0;
ascii &= 0xFF;
if (ascii == '\n') /* turn newlines into returns + CIRCLED? */
return CODE_RETURN | (CODE_CIRCLEC >> 8);
for (i = sizeof(t2741_map)/sizeof(t2741_map[0]); --i >= 0; ) {
if (t2741_map[i].shifts) {
if (t2741_map[i].lcase == ascii) {
rval = t2741_map[i].code;
if (t2741_unit->flags & UNIT_UPCASE) {
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
rval = CODE_SHIFTDOWN | (rval >> 8);
}
return rval;
}
if (t2741_map[i].ucase == ascii) {
rval = t2741_map[i].code;
if (! (t2741_unit->flags & UNIT_UPCASE)) {
SETBIT(t2741_unit->flags, UNIT_UPCASE);
rval = CODE_SHIFTUP | (rval >> 8);
}
return rval;
}
}
else if (t2741_map[i].lcase == ascii)
return t2741_map[i].code;
}
return CODE_UNKNOWN;
}
static char * t2741_to_ascii (uint16 code)
{
int i;
static char string[2] = {'?', '\0'};
switch (code) {
case CODE_SHIFTUP: return "SHIFTUP";
case CODE_SHIFTDOWN: return "SHIFTDN";
case CODE_CIRCLEC: return "CIRCLEC";
case CODE_CIRCLED: return "CIRCLED";
}
for (i = sizeof(t2741_map)/sizeof(t2741_map[0]); --i >= 0; ) {
if (t2741_map[i].code == code) {
if (t2741_map[i].shifts) {
string[0] = (t2741_unit->flags & UNIT_UPCASE) ? t2741_map[i].ucase : t2741_map[i].lcase;
return string;
}
switch (t2741_map[i].lcase) {
case ' ': return " ";
case '\r': return "RETURN";
case '\n': return "LINEFEED";
case '\b': return "BS";
case '\t': return "IDLE";
}
break;
}
}
return "?";
}

View file

@ -25,6 +25,8 @@
cpu Interdata 16b CPU
27-Oct-06 RMS Added idle support
Removed separate PASLA clock
06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger)
22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
25-Aug-05 RMS Fixed DH integer overflow cases
@ -219,7 +221,8 @@ uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL };
extern int32 sim_interval;
extern int32 sim_int_char;
extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern UNIT pic_unit, lfc_unit, pas_unit; /* timers */
extern t_bool sim_idle_enab;
extern UNIT pic_unit, lfc_unit; /* timers */
uint32 ReadB (uint32 loc);
uint32 ReadH (uint32 loc);
@ -445,7 +448,7 @@ static uint32 s1_rel_const[16] = { /* addr 8000-FFFF */
DIB cpu_dib = { d_DS, -1, v_DS, NULL, &display, NULL };
UNIT cpu_unit = {
UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_716, MAXMEMSIZE16)
UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_716, MAXMEMSIZE16)
};
REG cpu_reg[] = {
@ -513,6 +516,13 @@ REG cpu_reg[] = {
};
MTAB cpu_mod[] = {
{ UNIT_TYPE, 0, "I3", "I3", &cpu_set_model },
{ UNIT_TYPE, UNIT_ID4, "I4", "I4", &cpu_set_model },
{ UNIT_TYPE, UNIT_716, "7/16", "716", &cpu_set_model },
{ UNIT_TYPE, UNIT_816, "8/16", "816", &cpu_set_model },
{ UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model },
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
@ -521,11 +531,6 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
{ UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },
{ UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size },
{ UNIT_TYPE, 0, "I3", "I3", &cpu_set_model },
{ UNIT_TYPE, UNIT_ID4, "I4", "I4", &cpu_set_model },
{ UNIT_TYPE, UNIT_716, "7/16", "716", &cpu_set_model },
{ UNIT_TYPE, UNIT_816, "8/16", "816", &cpu_set_model },
{ UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
&cpu_set_consint, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
@ -584,7 +589,6 @@ int_eval (); /* eval interrupts */
cc = newPSW (PSW & psw_mask); /* split PSW, eval wait */
sim_rtcn_init (lfc_unit.wait, TMR_LFC); /* init clock */
sim_rtcn_init (pic_unit.wait, TMR_PIC); /* init timer */
sim_rtcn_init (pas_unit.wait, TMR_PAS); /* init pas */
reason = 0;
/* Process events */
@ -641,10 +645,9 @@ while (reason == 0) { /* loop until halted */
}
if (PSW & PSW_WAIT) { /* wait state? */
t = sim_qcount (); /* events in queue */
if ((t == 0) || ((t == 1) && stop_wait)) /* empty, or kbd only? */
reason = STOP_WAIT; /* then stop */
else sim_interval = 0; /* force check */
if (sim_idle_enab) /* idling enabled? */
sim_idle (TMR_LFC, TRUE);
else sim_interval = sim_interval - 1; /* no, count cycle */
continue;
}

View file

@ -1,6 +1,6 @@
/* id16_sys.c: Interdata 16b simulator interface
Copyright (c) 2000-2005, Robert M. Supnik
Copyright (c) 2000-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
18-Oct-06 RMS Re-ordered device list
26-Mar-04 RMS Fixed warning with -std=c99
27-Feb-03 RMS Added relative addressing support
*/
@ -69,13 +70,13 @@ int32 sim_emax = 2;
DEVICE *sim_devices[] = {
&cpu_dev,
&sch_dev,
&pic_dev,
&lfc_dev,
&pt_dev,
&tt_dev,
&ttp_dev,
&pas_dev,
&pasl_dev,
&pic_dev,
&lfc_dev,
&lpt_dev,
&dp_dev,
&idc_dev,

View file

@ -25,6 +25,8 @@
cpu Interdata 32b CPU
27-Oct-06 RMS Added idle support
Removed separate PASLA clock
09-Mar-06 RMS Added 8 register bank support for 8/32
06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger)
22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
@ -249,7 +251,8 @@ uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL };
extern int32 sim_interval;
extern int32 sim_int_char;
extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern UNIT pic_unit, lfc_unit, pas_unit; /* timers */
extern t_bool sim_idle_enab;
extern UNIT pic_unit, lfc_unit; /* timers */
extern FILE *sim_deb;
uint32 ReadB (uint32 loc, uint32 rel);
@ -566,11 +569,6 @@ REG cpu_reg[] = {
};
MTAB cpu_mod[] = {
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
{ UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },
{ UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size },
{ UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size },
{ UNIT_MSIZE, 1048756, NULL, "1M", &cpu_set_size },
{ UNIT_8RS|UNIT_TYPE, 0, NULL, "732", NULL },
{ UNIT_DPFP, UNIT_DPFP, NULL, "DPFP", NULL },
{ UNIT_TYPE, 0, "7/32, single precision fp", "732", NULL },
@ -579,6 +577,13 @@ MTAB cpu_mod[] = {
{ UNIT_8RS, 0, NULL, "2RS", NULL },
{ UNIT_8RS|UNIT_TYPE, UNIT_8RS|UNIT_DPFP|UNIT_832, "832, 8 register sets", NULL, NULL },
{ UNIT_8RS|UNIT_TYPE, UNIT_DPFP|UNIT_832, "832, 2 register sets", NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
{ UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },
{ UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size },
{ UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size },
{ UNIT_MSIZE, 1048756, NULL, "1M", &cpu_set_size },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
&cpu_set_consint, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
@ -624,7 +629,6 @@ int_eval (); /* eval interrupts */
cc = newPSW (PSW & PSW_MASK); /* split PSW, eval wait */
sim_rtcn_init (lfc_unit.wait, TMR_LFC); /* init clock */
sim_rtcn_init (pic_unit.wait, TMR_PIC); /* init timer */
sim_rtcn_init (pas_unit.wait, TMR_PAS); /* init pas */
reason = 0;
/* Abort handling
@ -703,10 +707,9 @@ while (reason == 0) { /* loop until halted */
}
if (PSW & PSW_WAIT) { /* wait state? */
t = sim_qcount (); /* events in queue */
if ((t == 0) || ((t == 1) && stop_wait)) /* empty, or kbd only? */
reason = STOP_WAIT; /* then stop */
else sim_interval = 0; /* force check */
if (sim_idle_enab) /* idling enabled? */
sim_idle (TMR_LFC, TRUE);
else sim_interval = sim_interval - 1; /* no, count cycle */
continue;
}

View file

@ -1,6 +1,6 @@
/* id32_sys.c: Interdata 32b simulator interface
Copyright (c) 2000-2005, Robert M. Supnik
Copyright (c) 2000-2007, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,8 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
25-Jan-07 RMS Fixed conflict between -h (hex) and -h (halfword)
18-Oct-06 RMS Re-ordered device list
02-Jul-04 RMS Fixed missing type in declaration
15-Jul-03 RMS Fixed signed/unsigned bug in get_imm
27-Feb-03 RMS Added relative addressing support
@ -72,13 +74,13 @@ int32 sim_emax = 6;
DEVICE *sim_devices[] = {
&cpu_dev,
&sch_dev,
&pic_dev,
&lfc_dev,
&pt_dev,
&tt_dev,
&ttp_dev,
&pas_dev,
&pasl_dev,
&pic_dev,
&lfc_dev,
&lpt_dev,
&dp_dev,
&idc_dev,
@ -365,7 +367,7 @@ if (sw & SWMASK ('C')) { /* string? */
fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2);
return -1;
}
if (sw & SWMASK ('H')) { /* halfword? */
if (sw & SWMASK ('W')) { /* halfword? */
fprint_val (of, val[0], rdx, 16, PV_RZRO);
return -1;
}
@ -584,7 +586,7 @@ if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */
val[0] = ((t_value) cptr[0] << 8) | (t_value) cptr[1];
return -1;
}
if (sw & SWMASK ('H')) { /* halfword? */
if (sw & SWMASK ('W')) { /* halfword? */
val[0] = (int32) get_uint (cptr, rdx, DMASK16, &r); /* get number */
if (r != SCPE_OK) return r;
return -1;

View file

@ -451,7 +451,6 @@ typedef struct {
#define TMR_LFC 0 /* LFC = timer 0 */
#define TMR_PIC 1 /* PIC = timer 1 */
#define TMR_PAS 2 /* PAS = timer 2 */
#define LPT_WIDTH 132
#define VFU_LNT 132
#define MIN(x,y) (((x) < (y))? (x): (y))

View file

@ -128,8 +128,8 @@
#define HCYL_V_HD 10 /* head/cyl word */
#define HCYL_V_CYL 0
#define GET_SA(cy,sf,sc,t) (((((cy)*drv_tab[t].surf)+(sf))* \
IDC_NUMSC)+(sc))
#define GET_SA(cy,sf,sc,t) \
(((((cy)*drv_tab[t].surf)+(sf))*IDC_NUMSC)+(sc))
/* The MSM (IDC) controller supports (two) six different disk drive types:

View file

@ -167,7 +167,8 @@ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
t = uptr->buf; /* get character */
if (lpt_spnd || ((t >= LF) && (t < CR))) { /* spc pend or spc op? */
lpt_spnd = 0;
if (lpt_bufout (uptr) != SCPE_OK) return SCPE_IOERR; /* print */
if (lpt_bufout (uptr) != SCPE_OK) /* print */
return SCPE_IOERR;
if ((t == 1) || (t == LF)) lpt_spc (uptr, 1); /* single space */
else if (t == VT) r = lpt_vfu (uptr, VT_VFU - 1); /* VT->VFU */
else if (t == 0xC) r = lpt_vfu (uptr, FF_VFU - 1); /* FF->VFU */

View file

@ -1,6 +1,6 @@
/* id_pas.c: Interdata programmable async line adapter simulator
Copyright (c) 2001-2005, Robert M Supnik
Copyright (c) 2001-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
pas Programmable asynchronous line adapter(s)
18-Oct-06 RMS Synced PASLA to clock
22-Nov-05 RMS Revised for new terminal processing routines
29-Jun-05 RMS Added SET PASLn DISCONNECT
21-Jun-05 RMS Fixed bug in SHOW CONN/STATS
@ -49,7 +50,6 @@
#define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */
#define UNIT_MDM (1 << UNIT_V_MDM)
#define PAS_INIT_POLL 8000
#define PASL_WAIT 500
/* Status byte */
@ -88,6 +88,7 @@
#define CMD_TYP 0x01 /* command type */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
extern int32 lfc_poll;
uint8 pas_sta[PAS_LINES]; /* status */
uint16 pas_cmd[PAS_LINES]; /* command */
@ -96,7 +97,6 @@ uint8 pas_xbuf[PAS_LINES]; /* xmt buf */
uint8 pas_rarm[PAS_LINES]; /* rcvr int armed */
uint8 pas_xarm[PAS_LINES]; /* xmt int armed */
uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */
uint32 pas_tps = 50; /* polls/second */
uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */
TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */
@ -126,7 +126,7 @@ void pas_reset_ln (int32 i);
DIB pas_dib = { d_PAS, -1, v_PAS, pas_tplte, &pas, &pas_ini };
UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE, 0), PAS_INIT_POLL };
UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE, 0), 0 };
REG pas_nlreg = { DRDATA (NLINES, PAS_ENAB, 6), PV_LEFT };
@ -312,11 +312,10 @@ return 0;
t_stat pasi_svc (UNIT *uptr)
{
int32 ln, c, out, t;
int32 ln, c, out;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
t = sim_rtcn_calb (pas_tps, TMR_PAS); /* calibrate */
sim_activate (uptr, t); /* continue poll */
sim_activate (uptr, lfc_poll); /* continue poll */
ln = tmxr_poll_conn (&pas_desc); /* look for connect */
if (ln >= 0) { /* got one? */
if ((pasl_unit[ln].flags & UNIT_MDM) && /* modem control */
@ -448,7 +447,7 @@ return c & 0xFF;
t_stat pas_reset (DEVICE *dptr)
{
int32 i, t;
int32 i;
if (dptr->flags & DEV_DIS) { /* disabled? */
pas_dev.flags = pas_dev.flags | DEV_DIS; /* disable lines */
@ -458,12 +457,8 @@ else {
pas_dev.flags = pas_dev.flags & ~DEV_DIS; /* enable lines */
pasl_dev.flags = pasl_dev.flags & ~DEV_DIS;
}
if (pas_unit.flags & UNIT_ATT) { /* master att? */
if (!sim_is_active (&pas_unit)) {
t = sim_rtcn_init (pas_unit.wait, TMR_PAS);
sim_activate (&pas_unit, t); /* activate */
}
}
if (pas_unit.flags & UNIT_ATT) /* master att? */
sim_activate_abs (&pas_unit, lfc_poll); /* cosched with clock */
else sim_cancel (&pas_unit); /* else stop */
for (i = 0; i < PAS_LINES; i++) pas_reset_ln (i);
return SCPE_OK;
@ -477,8 +472,7 @@ t_stat r;
r = tmxr_attach (&pas_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
sim_rtcn_init (pas_unit.wait, TMR_PAS);
sim_activate (uptr, 100); /* quick poll */
sim_activate_abs (uptr, 100); /* quick poll */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* id_tt.c: Interdata teletype
Copyright (c) 2000-2005, Robert M. Supnik
Copyright (c) 2000-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
tt console
18-Oct-06 RMS Sync keyboard to LFC clock
30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode
22-Nov-05 RMS Revised for new terminal processing routines
29-Dec-03 RMS Added support for console backpressure
25-Apr-03 RMS Revised for extended file support
@ -49,6 +51,7 @@
#define CMD_V_RD 2 /* read/write */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
extern int32 lfc_poll;
uint32 tt_sta = STA_BSY; /* status */
uint32 tt_fdpx = 1; /* tt mode */
@ -74,7 +77,7 @@ t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc);
DIB tt_dib = { d_TT, -1, v_TT, NULL, &tt, NULL };
UNIT tt_unit[] = {
{ UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT },
{ UDATA (&tti_svc, TT_MODE_KSR, 0), 0 },
{ UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT }
};
@ -82,7 +85,7 @@ REG tt_reg[] = {
{ HRDATA (STA, tt_sta, 8) },
{ HRDATA (KBUF, tt_unit[TTI].buf, 8) },
{ DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (KTIME, tt_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (KTIME, tt_unit[TTI].wait, 24), PV_LEFT },
{ HRDATA (TBUF, tt_unit[TTO].buf, 8) },
{ DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
@ -175,7 +178,7 @@ t_stat tti_svc (UNIT *uptr)
{
int32 out, temp;
sim_activate (uptr, uptr->wait); /* continue poll */
sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_poll)); /* continue poll */
tt_sta = tt_sta & ~STA_BRK; /* clear break */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
if (tt_rd) { /* read mode? */
@ -192,7 +195,7 @@ if (temp & SCPE_BREAK) { /* break? */
else uptr->buf = sim_tt_inpcvt (temp, TT_GET_MODE (uptr->flags) | TTUF_KSR);
uptr->pos = uptr->pos + 1; /* incr count */
if (!tt_fdpx) { /* half duplex? */
out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags));
out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags) | TTUF_KSR);
if (out >= 0) { /* valid echo? */
sim_putchar (out); /* write char */
tt_unit[TTO].pos = tt_unit[TTO].pos + 1;
@ -206,7 +209,7 @@ t_stat tto_svc (UNIT *uptr)
int32 ch;
t_stat r;
ch = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags));
ch = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR);
if (ch >= 0) {
if ((r = sim_putchar_s (ch)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
@ -226,7 +229,7 @@ return SCPE_OK;
t_stat tt_reset (DEVICE *dptr)
{
if (dptr->flags & DEV_DIS) sim_cancel (&tt_unit[TTI]); /* dis? cancel poll */
else sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* activate input */
else sim_activate_abs (&tt_unit[TTI], KBD_WAIT (tt_unit[TTI].wait, lfc_poll));
sim_cancel (&tt_unit[TTO]); /* cancel output */
tt_rd = tt_fdpx = 1; /* read, full duplex */
tt_chp = 0; /* no char */

View file

@ -1,6 +1,6 @@
/* id_ttp.c: Interdata PASLA console interface
Copyright (c) 2000-2005, Robert M. Supnik
Copyright (c) 2000-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
ttp console (on PAS)
18-Oct-06 RMS Sync keyboard to LFC clock
22-Nov-05 RMS Revised for new terminal processing routines
29-Dec-03 RMS Added support for console backpressure
25-Apr-03 RMS Revised for extended file support
@ -52,6 +53,8 @@
#define CMD_TYP 0x01 /* command type */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
extern int32 pas_par (int32 cmd, int32 c);
extern int32 lfc_poll;
uint32 ttp_sta = 0; /* status */
uint32 ttp_cmd = 0; /* command */
@ -68,14 +71,12 @@ t_stat ttp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ttp_set_break (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ttp_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc);
extern int32 pas_par (int32 cmd, int32 c);
/* TTP data structures */
DIB ttp_dib = { d_TTP, -1, v_TTP, ttp_tplte, &ttp, NULL };
UNIT ttp_unit[] = {
{ UDATA (&ttpi_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&ttpi_svc, 0, 0), 0 },
{ UDATA (&ttpo_svc, 0, 0), SERIAL_OUT_WAIT }
};
@ -83,7 +84,7 @@ REG ttp_reg[] = {
{ HRDATA (CMD, ttp_cmd, 16) },
{ HRDATA (KBUF, ttp_unit[TTI].buf, 8) },
{ DRDATA (KPOS, ttp_unit[TTI].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (KTIME, ttp_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (KTIME, ttp_unit[TTI].wait, 24), REG_NZ + PV_LEFT + REG_HRO },
{ FLDATA (KIREQ, int_req[l_TTP], i_TTP) },
{ FLDATA (KIENB, int_enb[l_TTP], i_TTP) },
{ FLDATA (KARM, ttp_karm, 0) },
@ -175,7 +176,7 @@ t_stat ttpi_svc (UNIT *uptr)
{
int32 c, out;
sim_activate (uptr, uptr->wait); /* continue poll */
sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_poll)); /* continue poll */
ttp_sta = ttp_sta & ~STA_FR; /* clear break */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
ttp_sta = ttp_sta & ~STA_PF; /* clear parity err */
@ -227,7 +228,7 @@ return SCPE_OK;
t_stat ttp_reset (DEVICE *dptr)
{
if (dptr->flags & DEV_DIS) sim_cancel (&ttp_unit[TTI]);
else sim_activate (&ttp_unit[TTI], ttp_unit[TTI].wait);
else sim_activate_abs (&ttp_unit[TTI], KBD_WAIT (ttp_unit[TTI].wait, lfc_poll));
sim_cancel (&ttp_unit[TTO]);
CLR_INT (v_TTP); /* clear int */
CLR_ENB (v_TTP);

View file

@ -1,6 +1,6 @@
/* id_uvc.c: Interdata universal clock
Copyright (c) 2001-2005, Robert M. Supnik
Copyright (c) 2001-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@
pic precision incremental clock
lfc line frequency clock
18-Oct-06 RMS Changed LFC to be free running, export tmr_poll
23-Jul-05 RMS Fixed {} error in OC
01-Mar-03 RMS Added SET/SHOW LFC FREQ support
Changed precision clock algorithm for V7 UNIX
@ -75,6 +76,7 @@ void pic_sched (t_bool strt);
uint32 pic_rd_cic (void);
int32 lfc_tps = 120; /* ticks per */
int32 lfc_poll = 8000;
uint32 lfc_arm = 0; /* int arm */
DEVICE lfc_dev;
@ -314,8 +316,6 @@ return SCPE_OK;
uint32 lfc (uint32 dev, uint32 op, uint32 dat)
{
int32 t;
switch (op) { /* case IO op */
case IO_ADR: /* select */
@ -323,10 +323,6 @@ switch (op) { /* case IO op */
case IO_OC: /* command */
lfc_arm = int_chg (v_LFC, dat, lfc_arm); /* upd int ctrl */
if (lfc_arm && !sim_is_active (&lfc_unit)) { /* starting? */
t = sim_rtcn_init (lfc_unit.wait, TMR_LFC);
sim_activate (&lfc_unit, t); /* init clock */
}
break;
}
return 0;
@ -336,13 +332,10 @@ return 0;
t_stat lfc_svc (UNIT *uptr)
{
int32 t;
lfc_poll = sim_rtcn_calb (lfc_tps, TMR_LFC); /* calibrate */
sim_activate (uptr, lfc_poll); /* reactivate */
if (lfc_arm) { /* armed? */
SET_INT (v_LFC); /* req intr */
if (pic_unit.flags & UNIT_DIAG) t = uptr->wait; /* diag? fixed delay */
else t = sim_rtcn_calb (lfc_tps, TMR_LFC); /* else calibrate */
sim_activate (uptr, t); /* reactivate */
}
return SCPE_OK;
}
@ -351,7 +344,8 @@ return SCPE_OK;
t_stat lfc_reset (DEVICE *dptr)
{
sim_cancel (&lfc_unit); /* cancel unit */
lfc_poll = sim_rtcn_init (lfc_unit.wait, TMR_LFC);
sim_activate_abs (&lfc_unit, lfc_poll); /* init clock */
CLR_INT (v_LFC); /* clear int */
CLR_ENB (v_LFC); /* disable int */
lfc_arm = 0; /* disarm int */

View file

@ -59,7 +59,8 @@
#define DSK_NUMSC 8 /* sectors/track */
#define DSK_NUMTR 128 /* tracks/disk */
#define DSK_DKSIZE (DSK_NUMTR*DSK_NUMSC*DSK_NUMWD) /* words/disk */
#define DSK_AMASK ((DSK_NUMDK*DSK_NUMTR*DSK_NUMSC) - 1) /* address mask */
#define DSK_AMASK ((DSK_NUMDK*DSK_NUMTR*DSK_NUMSC) - 1)
/* address mask */
#define DSK_NUMDK 8 /* disks/controller */
#define GET_DISK(x) (((x) / (DSK_NUMSC * DSK_NUMTR)) & (DSK_NUMDK - 1))

125
PDP1/pdp1_clk.c Normal file
View file

@ -0,0 +1,125 @@
/* pdp1_clk.c: PDP-1D clock simulator
Copyright (c) 2006, Robert M. Supnik
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 Robert M Supnik shall not be
bused in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
clk PDP-1D clock
Note that the clock is run at 1/8 of real speed (125Hz instead of 1Khz), to
provide for eventual implementation of idling.
*/
#include "pdp1_defs.h"
#define CLK_HWRE_TPS 1000 /* hardware freq */
#define CLK_TPS 125 /* sim freq */
#define CLK_CNTS (CLK_HWRE_TPS / CLK_TPS) /* counts per tick */
#define CLK_C1MIN (1000 * 60) /* counts per min */
#define CLK_C32MS 32 /* counts per 32ms */
int32 clk32ms_sbs = 0; /* 32ms SBS level */
int32 clk1min_sbs = 0; /* 1min SBS level */
int32 clk_cntr = 0;
int32 tmxr_poll = 5000;
extern int32 stop_inst;
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
/* CLK data structures
clk_dev CLK device descriptor
clk_unit CLK unit
clk_reg CLK register list
*/
UNIT clk_unit = {
UDATA (&clk_svc, 0, 0), 5000
};
REG clk_reg[] = {
{ ORDATA (CNTR, clk_cntr, 16) },
{ DRDATA (SBS32LVL, clk32ms_sbs, 4), REG_HRO },
{ DRDATA (SBS1MLVL, clk1min_sbs, 4), REG_HRO },
{ NULL }
};
MTAB clk_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBS32MSLVL", "SBS32MSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &clk32ms_sbs },
{ MTAB_XTD|MTAB_VDV, 0, "SBS1MINLVL", "SBS1MINLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &clk1min_sbs },
{ 0 }
};
DEVICE clk_dev = {
"CLK", &clk_unit, clk_reg, clk_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &clk_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE | DEV_DIS
};
/* Clock IOT routine */
int32 clk (int32 inst, int32 dev, int32 dat)
{
int32 used, incr;
if (clk_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */
used = tmxr_poll - (sim_is_active (&clk_unit) - 1);
incr = (used * CLK_CNTS) / tmxr_poll;
return clk_cntr + incr;
}
/* Unit service, generate appropriate interrupts */
t_stat clk_svc (UNIT *uptr)
{
if (clk_dev.flags & DEV_DIS) return SCPE_OK; /* disabled? */
tmxr_poll = sim_rtcn_calb (CLK_TPS, TMR_CLK); /* calibrate clock */
sim_activate (&clk_unit, tmxr_poll); /* reactivate unit */
clk_cntr = clk_cntr + CLK_CNTS; /* incr counter */
if ((clk_cntr % CLK_C32MS) == 0) /* 32ms interval? */
dev_req_int (clk32ms_sbs); /* req intr */
if (clk_cntr >= CLK_C1MIN) { /* 1min interval? */
dev_req_int (clk1min_sbs); /* req intr */
clk_cntr = 0; /* reset counter */
}
return SCPE_OK;
}
/* Reset routine */
t_stat clk_reset (DEVICE *dptr)
{
if (clk_dev.flags & DEV_DIS) sim_cancel (&clk_unit); /* disabled? */
else {
tmxr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK);
sim_activate_abs (&clk_unit, tmxr_poll); /* activate unit */
}
clk_cntr = 0; /* clear counter */
return SCPE_OK;
}

File diff suppressed because it is too large Load diff

431
PDP1/pdp1_dcs.c Normal file
View file

@ -0,0 +1,431 @@
/* pdp1_dcs.c: PDP-1D terminal multiplexor simulator
Copyright (c) 2006, Robert M Supnik
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 Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
dcs Type 630 data communications subsystem
This module implements up to 32 individual serial interfaces.
*/
#include "pdp1_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#define DCS_LINES 32 /* lines */
#define DCS_LINE_MASK (DCS_LINES - 1)
#define DCSL_WAIT 1000 /* output wait */
#define DCS_NUMLIN dcs_desc.lines
int32 dcs_sbs = 0; /* SBS level */
uint32 dcs_send = 0; /* line for send */
uint32 dcs_scan = 0; /* line for scanner */
uint8 dcs_flg[DCS_LINES]; /* line flags */
uint8 dcs_buf[DCS_LINES]; /* line bufffers */
extern int32 iosta, stop_inst;
extern int32 tmxr_poll;
TMLN dcs_ldsc[DCS_LINES] = { 0 }; /* line descriptors */
TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc }; /* mux descriptor */
t_stat dcsi_svc (UNIT *uptr);
t_stat dcso_svc (UNIT *uptr);
t_stat dcs_reset (DEVICE *dptr);
t_stat dcs_attach (UNIT *uptr, char *cptr);
t_stat dcs_detach (UNIT *uptr);
t_stat dcs_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dcs_show (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
void dcs_reset_ln (int32 ln);
void dcs_scan_next (t_bool unlk);
/* DCS data structures
dcs_dev DCS device descriptor
dcs_unit DCS unit descriptor
dcs_reg DCS register list
dcs_mod DCS modifiers list
*/
REG dcs_nlreg = { DRDATA (NLINES, DCS_NUMLIN, 6), PV_LEFT };
UNIT dcs_unit = { UDATA (&dcsi_svc, UNIT_ATTABLE, 0) };
REG dcs_reg[] = {
{ BRDATA (BUF, dcs_buf, 8, 8, DCS_LINES) },
{ BRDATA (FLAGS, dcs_flg, 8, 1, DCS_LINES) },
{ FLDATA (SCNF, iosta, IOS_V_DCS) },
{ ORDATA (SCAN, dcs_scan, 5) },
{ ORDATA (SEND, dcs_send, 5) },
{ DRDATA (SBSLVL, dcs_sbs, 4), REG_HRO },
{ NULL }
};
MTAB dcs_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &dcs_sbs },
{ MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",
&dcs_vlines, NULL, &dcs_nlreg },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &dcs_desc },
{ UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dcs_summ },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &dcs_show, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &dcs_show, NULL },
{ 0 }
};
DEVICE dcs_dev = {
"DCS", &dcs_unit, dcs_reg, dcs_mod,
1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &dcs_reset,
NULL, &dcs_attach, &dcs_detach,
NULL, DEV_NET | DEV_DISABLE | DEV_DIS
};
/* DCSL data structures
dcsl_dev DCSL device descriptor
dcsl_unit DCSL unit descriptor
dcsl_reg DCSL register list
dcsl_mod DCSL modifiers list
*/
UNIT dcsl_unit[] = {
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT },
{ UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }
};
MTAB dcsl_mod[] = {
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &dcs_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &dcs_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &dcs_desc },
{ 0 }
};
REG dcsl_reg[] = {
{ URDATA (TIME, dcsl_unit[0].wait, 10, 24, 0,
DCS_LINES, REG_NZ + PV_LEFT) },
{ NULL }
};
DEVICE dcsl_dev = {
"DCSL", dcsl_unit, dcsl_reg, dcsl_mod,
DCS_LINES, 10, 31, 1, 8, 8,
NULL, NULL, &dcs_reset,
NULL, NULL, NULL,
NULL, DEV_DIS
};
/* DCS IOT routine */
int32 dcs (int32 inst, int32 dev, int32 dat)
{
int32 pls = (inst >> 6) & 077;
if (dcs_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */
if (pls & 020) dat = 0; /* pulse 20? clr IO */
switch (pls & 057) { /* case IR<6,8:11> */
case 000: /* RCH */
dat |= dcs_buf[dcs_scan]; /* return line buf */
dcs_flg[dcs_scan] = 0; /* clr line flag */
break;
case 001: /* RRC */
dat |= dcs_scan; /* return line num */
break;
case 010: /* RCC */
dat |= dcs_buf[dcs_scan]; /* return line buf */
dcs_flg[dcs_scan] = 0; /* clr line flag */
/* fall through */
case 011: /* RSC */
dcs_scan_next (TRUE); /* unlock scanner */
break;
case 040: /* TCB */
dcs_buf[dcs_send] = dat & 0377; /* load buffer */
dcs_flg[dcs_send] = 0; /* clr line flag */
sim_activate (&dcsl_unit[dcs_send], dcsl_unit[dcs_send].wait);
break;
case 041: /* SSB */
dcs_send = dat & DCS_LINE_MASK; /* load line num */
break;
case 050: /* TCC */
dcs_buf[dcs_scan] = dat & 0377; /* load buffer */
dcs_flg[dcs_scan] = 0; /* clr line flag */
sim_activate (&dcsl_unit[dcs_scan], dcsl_unit[dcs_scan].wait);
dcs_scan_next (TRUE); /* unlock scanner */
break;
default:
return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */
} /* end case */
return dat;
}
/* Unit service - receive side
Poll all active lines for input
Poll for new connections
*/
t_stat dcsi_svc (UNIT *uptr)
{
int32 ln, c, out;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
if (dcs_dev.flags & DEV_DIS) return SCPE_OK;
sim_activate (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&dcs_desc); /* look for connect */
if (ln >= 0) { /* got one? */
dcs_ldsc[ln].rcve = 1; /* set rcv enable */
}
tmxr_poll_rx (&dcs_desc); /* poll for input */
for (ln = 0; ln < DCS_NUMLIN; ln++) { /* loop thru lines */
if (dcs_ldsc[ln].conn) { /* connected? */
if (c = tmxr_getc_ln (&dcs_ldsc[ln])) { /* get char */
if (c & SCPE_BREAK) c = 0; /* break? */
else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR);
dcs_buf[ln] = c; /* save char */
dcs_flg[ln] = 1; /* set line flag */
dcs_scan_next (FALSE); /* kick scanner */
out = sim_tt_outcvt (c & 0177, TT_GET_MODE (dcsl_unit[ln].flags));
if (out >= 0) {
tmxr_putc_ln (&dcs_ldsc[ln], out); /* echo char */
tmxr_poll_tx (&dcs_desc); /* poll xmt */
}
}
}
else dcs_ldsc[ln].rcve = 0; /* disconnected */
} /* end for */
return SCPE_OK;
}
/* Unit service - transmit side */
t_stat dcso_svc (UNIT *uptr)
{
int32 c;
uint32 ln = uptr - dcsl_unit; /* line # */
if (dcs_dev.flags & DEV_DIS) return SCPE_OK;
if (dcs_ldsc[ln].conn) { /* connected? */
if (dcs_ldsc[ln].xmte) { /* xmt enabled? */
c = sim_tt_outcvt (dcs_buf[ln] & 0177, TT_GET_MODE (uptr->flags));
if (c >= 0) tmxr_putc_ln (&dcs_ldsc[ln], c); /* output char */
tmxr_poll_tx (&dcs_desc); /* poll xmt */
}
else { /* buf full */
tmxr_poll_tx (&dcs_desc); /* poll xmt */
sim_activate (uptr, uptr->wait); /* reschedule */
return SCPE_OK;
}
}
dcs_flg[ln] = 1; /* set line flag */
dcs_scan_next (FALSE); /* kick scanner */
return SCPE_OK;
}
/* Kick scanner */
void dcs_scan_next (t_bool unlk)
{
int32 i;
if (unlk) iosta &= ~IOS_DCS; /* unlock? */
else if (iosta & IOS_DCS) return; /* no, locked? */
for (i = 0; i < DCS_LINES; i++) { /* scan flags */
dcs_scan = (dcs_scan + 1) & DCS_LINE_MASK; /* next flag */
if (dcs_flg[dcs_scan] != 0) { /* flag set? */
iosta |= IOS_DCS; /* lock scanner */
dev_req_int (dcs_sbs); /* request intr */
return;
}
}
return;
}
/* Reset routine */
t_stat dcs_reset (DEVICE *dptr)
{
int32 i;
if (dcs_dev.flags & DEV_DIS) /* master disabled? */
dcsl_dev.flags = dcsl_dev.flags | DEV_DIS; /* disable lines */
else dcsl_dev.flags = dcsl_dev.flags & ~DEV_DIS;
if (dcs_unit.flags & UNIT_ATT) /* master att? */
sim_activate_abs (&dcs_unit, tmxr_poll); /* activate */
else sim_cancel (&dcs_unit); /* else stop */
for (i = 0; i < DCS_LINES; i++) dcs_reset_ln (i); /* reset lines */
dcs_send = 0;
dcs_scan = 0;
iosta &= ~IOS_DCS; /* clr intr req */
return SCPE_OK;
}
/* Attach master unit */
t_stat dcs_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = tmxr_attach (&dcs_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
sim_activate_abs (uptr, tmxr_poll); /* start poll */
return SCPE_OK;
}
/* Detach master unit */
t_stat dcs_detach (UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach (&dcs_desc, uptr); /* detach */
for (i = 0; i < DCS_LINES; i++) dcs_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (uptr); /* stop poll */
return r;
}
/* Show summary processor */
t_stat dcs_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < DCS_LINES; i++) t = t + (dcs_ldsc[i].conn != 0);
if (t == 1) fprintf (st, "1 connection");
else fprintf (st, "%d connections", t);
return SCPE_OK;
}
/* SHOW CONN/STAT processor */
t_stat dcs_show (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < DCS_LINES; i++) t = t + (dcs_ldsc[i].conn != 0);
if (t) {
for (i = 0; i < DCS_LINES; i++) {
if (dcs_ldsc[i].conn) {
if (val) tmxr_fconns (st, &dcs_ldsc[i], i);
else tmxr_fstats (st, &dcs_ldsc[i], i);
}
}
}
else fprintf (st, "all disconnected\n");
return SCPE_OK;
}
/* Change number of lines */
t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
newln = get_uint (cptr, 10, DCS_LINES, &r);
if ((r != SCPE_OK) || (newln == DCS_NUMLIN)) return r;
if (newln == 0) return SCPE_ARG;
if (newln < DCS_LINES) {
for (i = newln, t = 0; i < DCS_NUMLIN; i++) t = t | dcs_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < DCS_NUMLIN; i++) {
if (dcs_ldsc[i].conn) {
tmxr_linemsg (&dcs_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&dcs_ldsc[i]); /* reset line */
}
dcsl_unit[i].flags = dcsl_unit[i].flags | UNIT_DIS;
dcs_reset_ln (i);
}
}
else {
for (i = DCS_NUMLIN; i < newln; i++) {
dcsl_unit[i].flags = dcsl_unit[i].flags & ~UNIT_DIS;
dcs_reset_ln (i);
}
}
DCS_NUMLIN = newln;
return SCPE_OK;
}
/* Reset an individual line */
void dcs_reset_ln (int32 ln)
{
sim_cancel (&dcsl_unit[ln]);
dcs_buf[ln] = 0;
dcs_flg[ln] = 0;
return;
}

View file

@ -1,6 +1,6 @@
/* pdp1_defs.h: 18b PDP simulator definitions
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
21-Dec-06 RMS Added 16-channel sequence break support
22-Jul-05 RMS Fixed definition of CPLS_DPY
08-Feb-04 PLB Added support for display
08-Dec-03 RMS Added support for parallel drum
@ -61,6 +62,7 @@
#define STOP_IND 5 /* nested indirects */
#define STOP_WAIT 6 /* IO wait hang */
#define STOP_DTOFF 7 /* DECtape off reel */
#define ERR_RMV 10 /* restrict mode viol */
/* Memory */
@ -72,6 +74,7 @@
/* Architectural constants */
#define SIGN 0400000 /* sign */
#define DMASK 0777777 /* data mask */
#define DAMASK 0007777 /* direct addr */
#define EPCMASK (AMASK & ~DAMASK) /* extended addr */
@ -83,6 +86,37 @@
#define OP_JMP 0600000 /* JMP */
#define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */
/* Program flags/sense switches */
#define PF_V_L 7
#define PF_V_RNG 6
#define PF_L (1u << PF_V_L)
#define PF_RNG (1u << PF_V_RNG)
#define PF_SS_1 0040
#define PF_SS_2 0020
#define PF_SS_3 0010
#define PF_SS_4 0004
#define PF_SS_5 0002
#define PF_SS_6 0001
#define PF_VR_ALL 0377
#define PF_SS_ALL 0077
/* Restict mode */
#define RTB_IOT 0400000
#define RTB_ILL 0200000
#define RTB_HLT 0100000
#define RTB_DBK 0040000
#define RTB_CHR 0020000
#define RTB_MB_MASK 0017777
#define RM45_V_BNK 14
#define RM45_M_BNK 003
#define RM48_V_BNK 12
#define RM48_M_BNK 017
#define RN45_SIZE 4
/* IOT subroutine return codes */
#define IOT_V_SKP 18 /* skip */
@ -100,8 +134,9 @@
#define IOS_V_PTP 13 /* paper tape punch */
#define IOS_V_DRM 12 /* drum */
#define IOS_V_SQB 11 /* sequence break */
#define IOS_V_PNT 2 /* print done */
#define IOS_V_SPC 1 /* space done */
#define IOS_V_PNT 3 /* print done */
#define IOS_V_SPC 2 /* space done */
#define IOS_V_DCS 1 /* data comm sys */
#define IOS_V_DRP 0 /* parallel drum busy */
#define IOS_LPN (1 << IOS_V_LPN)
@ -113,6 +148,7 @@
#define IOS_SQB (1 << IOS_V_SQB)
#define IOS_PNT (1 << IOS_V_PNT)
#define IOS_SPC (1 << IOS_V_SPC)
#define IOS_DCS (1 << IOS_V_DCS)
#define IOS_DRP (1 << IOS_V_DRP)
/* Completion pulses */
@ -128,7 +164,7 @@
#define CPLS_LPT (1 << CPLS_V_LPT)
#define CPLS_DPY (1 << CPLS_V_DPY)
/* Sequence break flags */
/* One channel sequence break */
#define SB_V_IP 0 /* in progress */
#define SB_V_RQ 1 /* request */
@ -138,4 +174,21 @@
#define SB_RQ (1 << SB_V_RQ)
#define SB_ON (1 << SB_V_ON)
/* 16 channel sequence break */
#define SBS_LVLS 16 /* num levels */
#define SBS_LVL_MASK (SBS_LVLS - 1)
#define SBS_LVL_RMV 14 /* restrict level */
#define SBS_MASK(x) (1u << (SBS_LVLS - 1 - (x))) /* level to mask */
/* Timers */
#define TMR_CLK 0
/* Device routines */
t_stat dev_req_int (int32 lvl);
t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc);
#endif

View file

@ -1,6 +1,6 @@
/* pdp1_drm.c: PDP-1 drum simulator
Copyright (c) 1993-2005, Robert M Supnik
Copyright (c) 1993-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@
drp Type 23 parallel drum
drm Type 24 serial drum
21-Dec-06 RMS Added 16-chan SBS support
08-Dec-03 RMS Added parallel drum support
Fixed bug in DBL/DCN decoding
26-Oct-03 RMS Cleaned up buffer copy code
@ -71,7 +72,7 @@
((double) DRM_NUMWDT)))
extern int32 M[];
extern int32 iosta, sbs;
extern int32 iosta;
extern int32 stop_inst;
extern UNIT cpu_unit;
@ -82,6 +83,7 @@ uint32 drm_ma = 0; /* memory address */
uint32 drm_err = 0; /* error flag */
uint32 drm_wlk = 0; /* write lock */
int32 drm_time = 4; /* inter-word time */
int32 drm_sbs = 0; /* SBS level */
int32 drm_stopioe = 1; /* stop on error */
/* Parallel drum variables */
@ -123,12 +125,19 @@ REG drm_reg[] = {
{ FLDATA (ERR, drm_err, 0) },
{ ORDATA (WLK, drm_wlk, 32) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
{ DRDATA (SBSLVL, drm_sbs, 4), REG_HRO },
{ FLDATA (STOP_IOE, drm_stopioe, 0) },
{ NULL }
};
MTAB drm_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "APILVL", "APILVL",
&dev_set_sbs, &dev_show_sbs, (void *) &drm_sbs },
{ 0 }
};
DEVICE drm_dev = {
"DRM", &drm_unit, drm_reg, NULL,
"DRM", &drm_unit, drm_reg, drm_mod,
1, 8, 20, 1, 8, 18,
NULL, NULL, &drm_reset,
NULL, NULL, NULL,
@ -159,6 +168,7 @@ REG drp_reg[] = {
{ FLDATA (ERR, drp_err, 0) },
{ DRDATA (TIME, drp_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, drp_stopioe, 0) },
{ DRDATA (SBSLVL, drm_sbs, 4), REG_HRO },
{ NULL }
};
@ -266,7 +276,7 @@ uint32 *fbuf = uptr->filebuf;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */
iosta = iosta | IOS_DRM; /* set done */
sbs = sbs | SB_RQ; /* req intr */
dev_req_int (drm_sbs); /* req intr */
return IORETURN (drm_stopioe, SCPE_UNATT);
}
@ -287,7 +297,7 @@ for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
}
drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
iosta = iosta | IOS_DRM; /* set done */
sbs = sbs | SB_RQ; /* req intr */
dev_req_int (drm_sbs); /* req intr */
return SCPE_OK;
}
@ -314,7 +324,7 @@ uint32 *fbuf = uptr->filebuf;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drp_err = 1; /* set error */
iosta = iosta & ~IOS_DRP; /* clear busy */
if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */
if (uptr->FUNC) dev_req_int (drm_sbs); /* req intr */
return IORETURN (drp_stopioe, SCPE_UNATT);
}
@ -330,7 +340,7 @@ if (uptr->FUNC == DRP_RW) { /* read/write? */
} /* end for */
} /* end if */
iosta = iosta & ~IOS_DRP; /* clear busy */
if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */
if (uptr->FUNC) dev_req_int (drm_sbs); /* req intr */
return SCPE_OK;
}

View file

@ -25,6 +25,7 @@
dt Type 550/555 DECtape
21-Dec-06 RMS Added 16-channel SBS support
23-Jun-06 RMS Fixed conflict in ATTACH switches
Revised header format
16-Aug-05 RMS Fixed C++ declaration and cast problems
@ -179,7 +180,7 @@
#define DTA_RW 077
#define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)]
#define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \
sbs = sbs | SB_RQ;
dev_req_int (dt_sbs);
#define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT)
#define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC)
@ -247,7 +248,6 @@
#define ABS(x) (((x) < 0)? (-(x)): (x))
extern int32 M[];
extern int32 sbs;
extern int32 stop_inst;
extern UNIT cpu_unit;
extern int32 sim_switches;
@ -257,6 +257,7 @@ extern FILE *sim_deb;
int32 dtsa = 0; /* status A */
int32 dtsb = 0; /* status B */
int32 dtdb = 0; /* data buffer */
int32 dt_sbs = 0; /* SBS level */
int32 dt_ltime = 12; /* interline time */
int32 dt_dctime = 40000; /* decel time */
int32 dt_substate = 0;
@ -326,10 +327,13 @@ REG dt_reg[] = {
{ URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0,
DT_NUMDR, REG_HRO) },
{ FLDATA (STOP_OFFR, dt_stopoffr, 0) },
{ DRDATA (SBSLVL, dt_sbs, 4), REG_HRO },
{ NULL }
};
MTAB dt_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &dt_sbs },
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },

View file

@ -1,6 +1,6 @@
/* pdp1_lp.c: PDP-1 line printer simulator
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
lpt Type 62 line printer for the PDP-1
21-Dec-06 RMS Added 16-channel SBS support
07-Sep-03 RMS Changed ioc to ios
23-Jul-03 RMS Fixed bugs in instruction decoding, overprinting
Revised to detect I/O wait hang
@ -43,6 +44,7 @@ int32 lpt_spc = 0; /* print (0) vs spc */
int32 lpt_ovrpr = 0; /* overprint */
int32 lpt_stopioe = 0; /* stop on error */
int32 lpt_bptr = 0; /* buffer ptr */
int32 lpt_sbs = 0; /* SBS level */
char lpt_buf[LPT_BSIZE + 1] = { 0 };
static const unsigned char lpt_trans[64] = {
' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<',
@ -51,7 +53,7 @@ static const unsigned char lpt_trans[64] = {
'_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','['
};
extern int32 ios, cpls, sbs, iosta;
extern int32 ios, cpls, iosta;
extern int32 stop_inst;
t_stat lpt_svc (UNIT *uptr);
@ -80,11 +82,18 @@ REG lpt_reg[] = {
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ DRDATA (SBSLVL, lpt_sbs, 4), REG_HRO },
{ NULL }
};
MTAB lpt_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &lpt_sbs },
{ 0 }
};
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL,
@ -151,7 +160,7 @@ if (cpls & CPLS_LPT) { /* completion pulse? */
ios = 1; /* restart */
cpls = cpls & ~CPLS_LPT; /* clr pulse pending */
}
sbs = sbs | SB_RQ; /* req seq break */
dev_req_int (lpt_sbs); /* req interrupt */
if (lpt_spc) { /* space? */
iosta = iosta | IOS_SPC; /* set flag */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */

View file

@ -1,6 +1,6 @@
/* pdp1_stddev.c: PDP-1 standard devices
Copyright (c) 1993-2005, Robert M. Supnik
Copyright (c) 1993-2006, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -28,6 +28,7 @@
tti keyboard
tto teleprinter
21-Dec-06 RMS Added 16-channel sequence break support
29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (from Phil Budne)
07-Sep-03 RMS Changed ioc to ios
30-Aug-03 RMS Revised PTR to conform to Maintenance Manual;
@ -58,8 +59,6 @@
#define BOTH (1 << (UC_V + 1)) /* both cases */
#define CW (1 << (UC_V + 2)) /* char waiting */
#define TT_WIDTH 077
#define TTI 0
#define TTO 1
#define UNIT_V_ASCII (UNIT_V_UF + 0) /* ASCII/binary mode */
#define UNIT_ASCII (1 << UNIT_V_ASCII)
#define PTR_LEADER 20 /* ASCII leader chars */
@ -70,12 +69,16 @@ int32 ptr_stopioe = 0;
int32 ptr_uc = 0; /* upper/lower case */
int32 ptr_hold = 0; /* holding buffer */
int32 ptr_leader = PTR_LEADER; /* leader count */
int32 ptr_sbs = 0; /* SBS level */
int32 ptp_stopioe = 0;
int32 ptp_sbs = 0; /* SBS level */
int32 tti_hold = 0; /* tti hold buf */
int32 tti_sbs = 0; /* SBS level */
int32 tty_buf = 0; /* tty buffer */
int32 tty_uc = 0; /* tty uc/lc */
int32 tto_sbs = 0;
extern int32 sbs, ios, ioh, cpls, iosta;
extern int32 ios, ioh, cpls, iosta;
extern int32 PF, IO, PC, TA;
extern int32 M[];
@ -154,10 +157,13 @@ REG ptr_reg[] = {
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ DRDATA (LEADER, ptr_leader, 6), REG_HRO },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ DRDATA (SBSLVL, ptr_sbs, 4), REG_HRO },
{ NULL }
};
MTAB ptr_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &ptr_sbs },
{ UNIT_ASCII, UNIT_ASCII, "ASCII", "ASCII", NULL },
{ UNIT_ASCII, 0, "FIODEC", "FIODEC", NULL },
{ 0 }
@ -189,46 +195,87 @@ REG ptp_reg[] = {
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ DRDATA (SBSLVL, ptp_sbs, 4), REG_HRO },
{ NULL }
};
MTAB ptp_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &ptp_sbs },
{ 0 }
};
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
"PTP", &ptp_unit, ptp_reg, ptp_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL,
NULL, 0
};
/* TTY data structures
/* TTI data structures
tty_dev TTY device descriptor
tty_unit TTY unit
tty_reg TTY register list
tti_dev TTI device descriptor
tti_unit TTI unit
tti_reg TTI register list
*/
UNIT tty_unit[] = {
{ UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 }
};
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
REG tty_reg[] = {
REG tti_reg[] = {
{ ORDATA (BUF, tty_buf, 6) },
{ FLDATA (UC, tty_uc, UC_V) },
{ FLDATA (RPLS, cpls, CPLS_V_TTO) },
{ ORDATA (HOLD, tti_hold, 9), REG_HRO },
{ FLDATA (KDONE, iosta, IOS_V_TTI) },
{ DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (TDONE, iosta, IOS_V_TTO) },
{ DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TTIME, tty_unit[TTO].wait, 24), PV_LEFT },
{ FLDATA (DONE, iosta, IOS_V_TTI) },
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (SBSLVL, tti_sbs, 4), REG_HRO },
{ NULL }
};
DEVICE tty_dev = {
"TTY", tty_unit, tty_reg, NULL,
2, 10, 31, 1, 8, 8,
MTAB tti_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &tti_sbs },
{ 0 }
};
DEVICE tti_dev = {
"TTI", &tti_unit, tti_reg, tti_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tty_reset,
NULL, NULL, NULL,
NULL, 0
};
/* TTO data structures
tto_dev TTO device descriptor
tto_unit TTO unit
tto_reg TTO register list
*/
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 };
REG tto_reg[] = {
{ ORDATA (BUF, tty_buf, 6) },
{ FLDATA (UC, tty_uc, UC_V) },
{ FLDATA (RPLS, cpls, CPLS_V_TTO) },
{ FLDATA (DONE, iosta, IOS_V_TTO) },
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
{ DRDATA (SBSLVL, tto_sbs, 4), REG_HRO },
{ NULL }
};
MTAB tto_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL",
&dev_set_sbs, &dev_show_sbs, (void *) &tto_sbs },
{ 0 }
};
DEVICE tto_dev = {
"TTO", &tto_unit, tto_reg, tto_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tty_reset,
NULL, NULL, NULL,
NULL, 0
@ -309,7 +356,7 @@ if (ptr_state == 0) { /* done? */
}
else { /* no, interrupt */
iosta = iosta | IOS_PTR; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
dev_req_int (ptr_sbs); /* req interrupt */
}
}
else sim_activate (uptr, uptr->wait); /* get next char */
@ -443,7 +490,7 @@ if (cpls & CPLS_PTP) { /* completion pulse? */
cpls = cpls & ~CPLS_PTP;
}
iosta = iosta | IOS_PTP; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
dev_req_int (ptp_sbs); /* req interrupt */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (uptr->buf, uptr->fileref) == EOF) { /* I/O error? */
@ -485,7 +532,7 @@ if (GEN_CPLS (inst)) { /* comp pulse? */
cpls = cpls | CPLS_TTO;
}
else cpls = cpls & ~CPLS_TTO;
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); /* activate unit */
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
return dat;
}
@ -518,8 +565,8 @@ else {
}
}
iosta = iosta | IOS_TTI; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
PF = PF | 040; /* set prog flag 1 */
dev_req_int (tti_sbs); /* req interrupt */
PF = PF | PF_SS_1; /* set prog flag 1 */
uptr->pos = uptr->pos + 1;
return SCPE_OK;
}
@ -543,7 +590,7 @@ if (cpls & CPLS_TTO) { /* completion pulse? */
cpls = cpls & ~CPLS_TTO;
}
iosta = iosta | IOS_TTO; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
dev_req_int (tto_sbs); /* req interrupt */
uptr->pos = uptr->pos + 1;
if (c == '\r') { /* cr? add lf */
sim_putchar ('\n');
@ -561,7 +608,7 @@ tty_uc = 0; /* clear case */
tti_hold = 0; /* clear hold buf */
cpls = cpls & ~CPLS_TTO;
iosta = (iosta & ~IOS_TTI) | IOS_TTO; /* clear flag */
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate keyboard */
sim_cancel (&tty_unit[TTO]); /* stop printer */
sim_activate (&tti_unit, tti_unit.wait); /* activate keyboard */
sim_cancel (&tto_unit); /* stop printer */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp1_sys.c: PDP-1 simulator interface
Copyright (c) 1993-2004, Robert M. Supnik
Copyright (c) 1993-2007, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,8 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
03-Jan-07 RMS Fixed bugs in block loader, char input
21-Dec-06 RMS Added 16-channel sequence break support, PDP-1D support
06-Apr-04 RMS Fixed bug in binary loader (found by Mark Crispin)
08-Feb-04 PLB Merged display support
08-Dec-03 RMS Added parallel drum support, drum mnemonics
@ -46,13 +48,16 @@
#include <ctype.h>
extern DEVICE cpu_dev;
extern DEVICE clk_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE tty_dev;
extern DEVICE tti_dev;
extern DEVICE tto_dev;
extern DEVICE lpt_dev;
extern DEVICE dt_dev;
extern DEVICE drm_dev;
extern DEVICE drp_dev;
extern DEVICE dcs_dev, dcsl_dev;
extern DEVICE dpy_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
@ -80,13 +85,17 @@ int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&clk_dev,
&ptr_dev,
&ptp_dev,
&tty_dev,
&tti_dev,
&tto_dev,
&lpt_dev,
&dt_dev,
&drm_dev,
&drp_dev,
&dcs_dev,
&dcsl_dev,
/* &dpy_dev, */
NULL
};
@ -152,13 +161,13 @@ for (;;) {
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT;
if ((val & 0760000) != OP_DIO) return SCPE_FMT;
csum = csum + val;
if (csum > 0777777) csum = (csum + 1) & 0777777;
count = (val & DAMASK) - start + 1; /* block count */
if (csum > DMASK) csum = (csum + 1) & DMASK;
count = (val & DAMASK) - start; /* block count */
if (count <= 0) return SCPE_FMT;
while (count--) { /* loop on data */
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT;
csum = csum + val;
if (csum > 0777777) csum = (csum + 1) & 0777777;
if (csum > DMASK) csum = (csum + 1) & DMASK;
M[fld | start] = val;
start = (start + 1) & DAMASK;
}
@ -196,7 +205,7 @@ return SCPE_OK;
/* Symbol tables */
#define I_V_FL 18 /* inst class */
#define I_M_FL 07 /* class mask */
#define I_M_FL 017 /* class mask */
#define I_V_NPN 0 /* no operand */
#define I_V_IOT 1 /* IOT */
#define I_V_LAW 2 /* LAW */
@ -205,6 +214,7 @@ return SCPE_OK;
#define I_V_OPR 5 /* OPR */
#define I_V_SKP 6 /* skip */
#define I_V_SHF 7 /* shift */
#define I_V_SPC 8 /* special */
#define I_NPN (I_V_NPN << I_V_FL) /* no operand */
#define I_IOT (I_V_IOT << I_V_FL) /* IOT */
#define I_LAW (I_V_LAW << I_V_FL) /* LAW */
@ -213,10 +223,12 @@ return SCPE_OK;
#define I_OPR (I_V_OPR << I_V_FL) /* OPR */
#define I_SKP (I_V_SKP << I_V_FL) /* skip */
#define I_SHF (I_V_SHF << I_V_FL) /* shift */
#define I_SPC (I_V_SPC << I_V_FL)
static const int32 masks[] = {
0777777, 0763777, 0760000, 0760000,
0770000, 0760017, 0760077, 0777000
0777777, 0760077, 0760000, 0760000,
0770000, 0760017, 0760077, 0777000,
0760003
};
static const char *opcode[] = {
@ -224,22 +236,30 @@ static const char *opcode[] = {
"LAC", "LIO", "DAC", "DAP",
"DIP", "DIO", "DZM", "ADD",
"SUB", "IDX", "ISP", "SAD",
"SAS", "MUL", "DIV", "JMP", "JSP",
"SAS", "MUL", "DIV", "JMP",
"JSP", "LCH", "DCH", "TAD",
"CAL", "JDA", /* mem ref no ind */
"LAW",
"IOH", "RPA", "RPB", "RRB", /* I/O instructions */
"PPA", "PPB", "TYO", "TYI",
"DPY",
"DSC", "ASC", "ISC", "CAC",
"LSM", "ESM", "CBS",
"LEM", "EEM", "CKS",
"MSE", "MLC", "MRD", "MWR", "MRS",
"DIA", "DBA", "DWC", "DRA", "DCL",
"DRD", "DWR", "DBL", "DCN",
"DTD", "DSE", "DSP",
"LRG", "ERG", "LRM", "ERM",
"RNM", "RSM", "RCK", "CTB",
"RCH", "RCC", "TCC", "TCB",
"RRC", "SSB", "RSC",
"SKP", "SKP I", "CLO",
"SFT", "LAW", "OPR",
"SKP", "SKP I", "CLO", /* base as NPNs */
"SFT", "SPC", "OPR",
"RAL", "RIL", "RCL", /* shifts */
"SAL", "SIL", "SCL",
@ -268,12 +288,24 @@ static const char *opcode[] = {
"STF1", "STF2", "STF3",
"STF4", "STF5", "STF6", "STF7",
"SZA", "SPA", "SMA", /* encode only */
"SZO", "SPI", "I",
"FF1", "FF2", "FF3", /* specials */
"SZA", "SPA", "SMA", /* uprog skips */
"SZO", "SPI", "SNI",
"I", /* encode only */
"LIA", "LAI", "SWP", /* uprog opers */
"LAP", "CLA", "HLT",
"CMA", "LAT", "CLI",
NULL, NULL, /* decode only */
NULL
"CMI",
"CML", "CLL", "SZL", /* uprog specials */
"SCF", "SCI", "SCM",
"IDA", "IDC", "IFI",
"IIF",
NULL, NULL, NULL, /* decode only */
NULL,
};
static const int32 opc_val[] = {
@ -281,22 +313,30 @@ static const int32 opc_val[] = {
0200000+I_MRF, 0220000+I_MRF, 0240000+I_MRF, 0260000+I_MRF,
0300000+I_MRF, 0320000+I_MRF, 0340000+I_MRF, 0400000+I_MRF,
0420000+I_MRF, 0440000+I_MRF, 0460000+I_MRF, 0500000+I_MRF,
0520000+I_MRF, 0540000+I_MRF, 0560000+I_MRF, 0600000+I_MRF, 0620000+I_MRF,
0520000+I_MRF, 0540000+I_MRF, 0560000+I_MRF, 0600000+I_MRF,
0620000+I_MRF, 0120000+I_MRF, 0140000+I_MRF, 0360000+I_MRF,
0160000+I_MRI, 0170000+I_MRI,
0700000+I_LAW,
0730000+I_NPN, 0720001+I_IOT, 0720002+I_IOT, 0720030+I_IOT,
0720005+I_IOT, 0720006+I_IOT, 0720003+I_IOT, 0720004+I_IOT,
0720007+I_IOT,
0720050+I_IOT, 0720051+I_IOT, 0720052+I_IOT, 0720053+I_NPN,
0720054+I_NPN, 0720055+I_NPN, 0720056+I_NPN,
0720074+I_NPN, 0724074+I_NPN, 0720033+I_NPN,
0720301+I_NPN, 0720401+I_NPN, 0720501+I_NPN, 0720601+I_NPN, 0720701+I_NPN,
0720061+I_NPN, 0722061+I_NPN, 0720062+I_NPN, 0722062+I_NPN, 0720063+I_NPN,
0720161+I_NPN, 0721161+I_NPN, 0720162+I_NPN, 0721162+I_NPN,
0720163+I_NPN, 0720164+I_NPN, 0721164+I_NPN,
0720010+I_NPN, 0720011+I_NPN, 0720064+I_NPN, 0720065+I_NPN,
0720066+I_IOT, 0720067+I_NPN, 0720032+I_NPN, 0720035+I_NPN,
0720022+I_NPN, 0721022+I_NPN, 0725022+I_NPN, 0724022+I_NPN,
0720122+I_NPN, 0724122+I_NPN, 0721122+I_NPN,
0640000+I_NPN, 0650000+I_NPN, 0651600+I_NPN,
0660000+I_NPN, 0700000+I_LAW, 0760000+I_NPN,
0660000+I_NPN, 0740000+I_NPN, 0760000+I_NPN,
0661000+I_SHF, 0662000+I_SHF, 0663000+I_SHF,
0665000+I_SHF, 0666000+I_SHF, 0667000+I_SHF,
@ -325,12 +365,23 @@ static const int32 opc_val[] = {
0760011+I_OPR, 0760012+I_OPR, 0760013+I_OPR,
0760014+I_OPR, 0760015+I_OPR, 0760016+I_OPR, 0760017+I_OPR,
0640100+I_SKP, 0640200+I_SKP, 0640400+I_SKP, /* encode only */
0641000+I_SKP, 0642000+I_SKP, 0010000+I_SKP,
0740001+I_SPC, 0740002+I_SPC, 0740003+I_OPR,
0640100+I_SKP, 0640200+I_SKP, 0640400+I_SKP,
0641000+I_SKP, 0642000+I_SKP, 0644000+I_SKP,
0010000+I_SKP, /* encode only */
0760020+I_OPR, 0760040+I_OPR, 0760060+I_NPN,
0760100+I_OPR, 0760200+I_OPR, 0760400+I_OPR,
0761000+I_OPR, 0762000+I_OPR, 0764000+I_OPR,
0770000+I_OPR,
0640000+I_SKP, 0760000+I_OPR, /* decode only */
0740004+I_SPC, 0740010+I_SPC, 0740020+I_SPC,
0740040+I_SPC, 0740100+I_SPC, 0740200+I_SPC,
0740400+I_SPC, 0741000+I_SPC, 0742000+I_SPC,
0744000+I_SPC,
0640000+I_SKP, 0740000+I_SPC, 0760000+I_OPR, /* decode only */
-1
};
@ -406,7 +457,7 @@ disp = inst & 007777;
ma = (addr & EPCMASK) | disp;
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((opc_val[i] & 0777777) == (inst & masks[j])) { /* match? */
if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */
switch (j) { /* case on class */
@ -433,7 +484,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
break;
case I_V_OPR: /* operates */
sp = fprint_opr (of, inst & 007700, j, 0);
sp = fprint_opr (of, inst & 017760, j, 0);
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
break;
@ -443,6 +494,12 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
if (inst & IA) fprintf (of, sp? " I": "I");
break;
case I_V_SPC: /* specials */
sp = fprint_opr (of, inst & 007774, j, 0);
if (opcode[i]) sp = fprintf (of, (sp? " %s": "%s"), opcode[i]);
if (inst & IA) fprintf (of, sp? " I": "I");
break;
case I_V_SHF: /* shifts */
fprintf (of, "%s %-d", opcode[i], sc_map[inst & 0777]);
break;
@ -475,7 +532,7 @@ else if (*cptr == '-') {
*sign = -1;
cptr++;
}
return get_uint (cptr, 8, 0777777, status);
return get_uint (cptr, 8, DMASK, status);
}
/* Symbolic input
@ -508,16 +565,16 @@ if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
}
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (ASCTOSIX (cptr[0] & 077) << 12) |
(ASCTOSIX (cptr[1] & 077) << 6) |
ASCTOSIX (cptr[2] & 077);
val[0] = ((ASCTOSIX (cptr[0]) & 077) << 12) |
((ASCTOSIX (cptr[1]) & 077) << 6) |
(ASCTOSIX (cptr[2]) & 077);
return SCPE_OK;
}
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
val[0] = opc_val[i] & 0777777; /* get value */
val[0] = opc_val[i] & DMASK; /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
switch (j) { /* case on class */
@ -545,13 +602,14 @@ switch (j) { /* case on class */
val[0] = val[0] | sc_enc[d];
break;
case I_V_NPN: case I_V_IOT: case I_V_OPR: case I_V_SKP:
case I_V_NPN: case I_V_IOT:
case I_V_OPR: case I_V_SKP: case I_V_SPC:
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0); i++) ;
if (opcode[i] != NULL) {
k = opc_val[i] & 0777777;
k = opc_val[i] & DMASK;
if ((k != IA) && (((k ^ val[0]) & 0760000) != 0))
return SCPE_ARG;
val[0] = val[0] | k;

View file

@ -136,8 +136,6 @@
#define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
#define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define HIST_PC 0x40000000
#define HIST_MIN 64
@ -188,6 +186,7 @@ int32 stop_op0 = 0; /* stop on 0 */
int32 rlog = 0; /* extend fixup log */
int32 ind_max = 32; /* nested ind limit */
int32 xct_max = 32; /* nested XCT limit */
int32 t20_idlelock = 0; /* TOPS-20 idle lock */
a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
@ -321,6 +320,7 @@ extern t_bool wrpcst (a10 ea, int32 prv);
extern t_bool spm (a10 ea, int32 prv);
extern t_bool lpmr (a10 ea, int32 prv);
extern int32 pi_ub_vec (int32 lvl, int32 *uba);
extern t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc);
/* CPU data structures
@ -390,9 +390,14 @@ REG cpu_reg[] = {
};
MTAB cpu_mod[] = {
{ UNIT_ITS+UNIT_T20V41, 0, "Standard microcode", "STANDARD", NULL },
{ UNIT_ITS+UNIT_T20V41, UNIT_T20V41, "TOPS-20 V4.1", "TOPS20V41", NULL },
{ UNIT_ITS+UNIT_T20V41, UNIT_ITS, "ITS microcode", "ITS", NULL },
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, "TOPS-10", "TOPS-10", &tim_set_mod },
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, NULL , "TOPS10", &tim_set_mod },
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, "TOPS-20", "TOPS-20", &tim_set_mod },
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, NULL, "TOPS20", &tim_set_mod },
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_ITS, "ITS", "ITS", &tim_set_mod },
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_KLAD, "diagnostic mode", "KLAD", &tim_set_mod },
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
NULL, &show_iospace },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
@ -593,11 +598,11 @@ static t_stat jrst_tab[16] = {
#define T__N if ((AC(ac) & mb) != 0) INCPC
#define T__A INCPC
#define IOC if (TSTF (F_USR) && !TSTF (F_UIO)) goto MUUO;
#define IO7(x,y) IOC; fptr = ((ITS)? x[ac]: y[ac]); \
#define IO7(x,y) IOC; fptr = ((Q_ITS)? x[ac]: y[ac]); \
if (fptr == NULL) goto MUUO; \
if (fptr (ea, MM_OPND)) INCPC; break;
#define IOA IOC; if (!ITS) ea = calc_ioea (inst, pflgs)
#define IOAM IOC; ea = ((ITS)? ((a10) Read (ea, MM_OPND)): \
#define IOA IOC; if (!Q_ITS) ea = calc_ioea (inst, pflgs)
#define IOAM IOC; ea = ((Q_ITS)? ((a10) Read (ea, MM_OPND)): \
calc_ioea (inst, pflgs))
/* Flag tests */
@ -629,7 +634,8 @@ pager_pi = FALSE; /* not in pi sequence */
rlog = 0; /* not in extend */
pi_eval (); /* eval pi system */
sim_rtc_init (tim_unit.wait); /* init calibration */
if (!ITS) its_1pr = 0; /* ~ITS, clr 1-proc */
if (!Q_ITS) its_1pr = 0; /* ~ITS, clr 1-proc */
t20_idlelock = 0; /* clr T20 idle lock */
/* Abort handling
@ -656,7 +662,7 @@ else if (abortval == PAGE_FAIL) { /* page fail */
if (rlog) xtcln (rlog); /* clean up extend */
rlog = 0; /* clear log */
if (pager_tc) flags = pager_flags; /* trap? get flags */
if (T20) { /* TOPS-20 */
if (T20PAG) { /* TOPS-20 paging? */
WriteP (upta + UPT_T20_PFL, pager_word); /* write page fail wd */
WriteP (upta + UPT_T20_OFL, XWD (flags, 0));
WriteP (upta + UPT_T20_OPC, pager_PC);
@ -664,7 +670,7 @@ else if (abortval == PAGE_FAIL) { /* page fail */
}
else {
a10 ea; /* TOPS-10 or ITS */
if (ITS) { /* ITS? */
if (Q_ITS) { /* ITS? */
ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3);
if (its_1pr) flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; /* clear 1-proc */
@ -715,7 +721,7 @@ if (qintr) {
else inst = ReadP (epta + EPT_PIIT + (2 * qintr));
op = GET_OP (inst); /* get opcode */
ac = GET_AC (inst); /* get ac */
if (its_1pr && ITS) { /* 1-proc set? */
if (its_1pr && Q_ITS) { /* 1-proc set? */
flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; /* clear 1-proc */
}
@ -846,12 +852,12 @@ case 0037: Write (040, UUOWORD, MM_CUR); /* store op, ac, ea */
/* case 0100: MUUO /* UJEN */
/* case 0101: MUUO /* unassigned */
case 0102: if (ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */
case 0102: if (Q_ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */
inst = Read (ea, MM_OPND);
pflgs = pflgs | ac; goto XCT;
}
goto MUUO;
case 0103: if (ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */
case 0103: if (Q_ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */
inst = Read (ea, MM_OPND);
pflgs = pflgs | ac; goto XCT;
}
@ -977,7 +983,7 @@ case 0243: AC(P1) = jffo (AC(ac)); /* JFFO */
case 0244: ashc (ac, ea); break; /* ASHC */
case 0245: rotc (ac, ea); break; /* ROTC */
case 0246: lshc (ac, ea); break; /* LSHC */
case 0247: if (ITS) circ (ac, ea); break; /* (ITS) CIRC */
case 0247: if (Q_ITS) circ (ac, ea); break; /* (ITS) CIRC */
case 0250: RM; WRAC; AC(ac) = mb; break; /* EXCH */
case 0251: blt (ac, ea, pflgs); break; /* BLT */
case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */
@ -991,9 +997,10 @@ case 0255: if (flags & (ac << 14)) { /* JFCL */
case 0256: if (xct_cnt++ >= xct_max) /* XCT */
ABORT (STOP_XCT);
inst = Read (ea, MM_OPND);
if (ac && !TSTF (F_USR) && !ITS) pflgs = pflgs | ac;
if (ac && !TSTF (F_USR) && !Q_ITS)
pflgs = pflgs | ac;
goto XCT;
case 0257: if (ITS) goto MUUO; /* MAP */
case 0257: if (Q_ITS) goto MUUO; /* MAP */
AC(ac) = map (ea, MM_OPND); break;
case 0260: WRP (FLPC); AOBAC; /* PUSHJ */
SUBJ (ea); PUSHF; break;
@ -1054,7 +1061,12 @@ case 0340: AOJ; break; /* AOJ */
case 0341: AOJ; if (TL (AC(ac))) JUMP (ea); break; /* AOJL */
case 0342: AOJ; if (TE (AC(ac))) JUMP (ea); break; /* AOJE */
case 0343: AOJ; if (TLE (AC(ac))) JUMP (ea); break; /* AOJLE */
case 0344: AOJ; JUMP(ea); break; /* AOJA */
case 0344: AOJ; JUMP(ea); /* AOJA */
if (Q_ITS && Q_IDLE && /* ITS idle? */
TSTF (F_USR) && (pager_PC == 017) && /* user mode, loc 17? */
(ac == 0) && (ea == 017)) /* AOJA 0,17? */
sim_idle (0, FALSE);
break;
case 0345: AOJ; if (TGE (AC(ac))) JUMP (ea); break; /* AOJGE */
case 0346: AOJ; if (TN (AC(ac))) JUMP (ea); break; /* AOJN */
case 0347: AOJ; if (TG (AC(ac))) JUMP (ea); break; /* AOJG */
@ -1073,7 +1085,22 @@ case 0363: SOJ; if (TLE (AC(ac))) JUMP (ea); break; /* SOJLE */
case 0364: SOJ; JUMP(ea); break; /* SOJA */
case 0365: SOJ; if (TGE (AC(ac))) JUMP (ea); break; /* SOJGE */
case 0366: SOJ; if (TN (AC(ac))) JUMP (ea); break; /* SOJN */
case 0367: SOJ; if (TG (AC(ac))) JUMP (ea); break; /* SOJG */
case 0367: SOJ; if (TG (AC(ac))) JUMP (ea); /* SOJG */
if ((ea == pager_PC) && Q_IDLE) { /* to self, idle enab? */
extern int32 tmr_poll;
if ((ac == 6) && (ea == 1) && /* SOJG 6,1? */
TSTF (F_USR) && Q_T10) /* T10, user mode? */
sim_idle (0, FALSE);
else if (!t20_idlelock && /* interlock off? */
(ac == 2) && (ea == 3) && /* SOJG 2,3? */
!TSTF (F_USR) && Q_T20 && /* T20, mon mode? */
(sim_interval > (tmr_poll >> 1))) { /* >= half clock? */
t20_idlelock = 1; /* set interlock */
if (sim_os_ms_sleep (1)) /* sleep 1ms */
sim_interval = 0; /* if ok, sched event */
}
}
break;
case 0370: SOS; break; /* SOS */
case 0371: SOS; if (TL (mb)) INCPC; break; /* SOSL */
case 0372: SOS; if (TE (mb)) INCPC; break; /* SOSE */
@ -1331,7 +1358,7 @@ case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */
default:
MUUO:
its_2pr = 0; /* clear trap */
if (T20) { /* TOPS20? */
if (T20PAG) { /* TOPS20 paging? */
int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18));
WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */
flags & ~(F_T2 | F_T1), tf)); /* traps clear */
@ -1425,7 +1452,7 @@ case 0254: /* JRST */
break;
case 015: /* JRST 15 = XJRST */
if (!T20) goto MUUO; /* only in TOPS20 */
if (!T20PAG) goto MUUO; /* only in TOPS20 paging */
JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */
break;
} /* end case subop */
@ -1434,7 +1461,7 @@ case 0254: /* JRST */
if (its_2pr) { /* 1-proc trap? */
its_1pr = its_2pr = 0; /* clear trap */
if (ITS) { /* better be ITS */
if (Q_ITS) { /* better be ITS */
WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */
mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */
JUMP (mb); /* set PC */
@ -2017,7 +2044,7 @@ return;
t_bool aprid (a10 ea, int32 prv)
{
Write (ea, (ITS)? UC_AIDITS: UC_AIDDEC, prv);
Write (ea, (Q_ITS)? UC_AIDITS: UC_AIDDEC, prv);
return FALSE;
}
@ -2069,7 +2096,7 @@ if (jrst && TSTF (F_USR)) { /* if in user now */
fl = fl | F_USR; /* can't clear user */
if (!TSTF (F_UIO)) fl = fl & ~F_UIO; /* if !UIO, can't set */
}
if (ITS && (fl & F_1PR)) { /* ITS 1-proceed? */
if (Q_ITS && (fl & F_1PR)) { /* ITS 1-proceed? */
its_1pr = 1; /* set flag */
fl = fl & ~F_1PR; /* vanish bit */
}
@ -2177,7 +2204,7 @@ pi_enb = pi_act = pi_prq = 0; /* clear PI */
apr_enb = apr_flg = apr_lvl = 0; /* clear APR */
pcst = 0; /* clear PC samp */
rlog = 0; /* clear reg log */
hsb = (ITS)? UC_HSBITS: UC_HSBDEC; /* set HSB */
hsb = (Q_ITS)? UC_HSBITS: UC_HSBDEC; /* set HSB */
set_dyn_ptrs ();
set_ac_display (ac_cur);
pi_eval ();

View file

@ -1,6 +1,6 @@
/* pdp10_defs.h: PDP-10 simulator definitions
Copyright (c) 1993-2005, Robert M Supnik
Copyright (c) 1993-2007, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,8 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
01-Feb-07 RMS Added CD support
29-Oct-06 RMS Added clock coscheduling function
29-Dec-03 RMS Added Q18 definition for PDP11 compatibility
19-May-03 RMS Revised for new conditional compilation scheme
09-Jan-03 RMS Added DEUNA/DELUA support
@ -122,10 +124,16 @@ typedef t_int64 d10; /* PDP-10 data (36b) */
/* Operating system flags, kept in cpu_unit.flags */
#define UNIT_V_ITS (UNIT_V_UF) /* ITS */
#define UNIT_V_T20 (UNIT_V_UF + 1) /* TOPS-20 */
#define UNIT_V_KLAD (UNIT_V_UF + 2) /* diagnostics */
#define UNIT_ITS (1 << UNIT_V_ITS)
#define UNIT_V_T20V41 (UNIT_V_UF + 1) /* TOPS-20 V4.1 */
#define UNIT_T20V41 (1 << UNIT_V_T20V41)
#define ITS (cpu_unit.flags & UNIT_ITS)
#define UNIT_T20 (1 << UNIT_V_T20)
#define UNIT_KLAD (1 << UNIT_V_KLAD)
#define Q_T10 ((cpu_unit.flags & (UNIT_ITS|UNIT_T20|UNIT_KLAD)) == 0)
#define Q_ITS (cpu_unit.flags & UNIT_ITS)
#define Q_T20 (cpu_unit.flags & UNIT_T20)
#define Q_KLAD (cpu_unit.flags & UNIT_KLAD)
#define Q_IDLE (sim_idle_enab)
/* Architectural constants */
@ -384,7 +392,7 @@ typedef t_int64 d10; /* PDP-10 data (36b) */
#define EBR_MASK (EBR_T20P | EBR_PGON | (EBR_M_EBR << EBR_V_EBR))
#define EBR_GETEBR(x) ((int32) (((x) >> EBR_V_EBR) & PAG_M_PPN))
#define PAGING (ebr & EBR_PGON)
#define T20 (ebr & EBR_T20P)
#define T20PAG (ebr & EBR_T20P)
/* AC and mapping contexts
@ -647,6 +655,8 @@ typedef struct pdp_dib DIB;
#define IOLN_UBMNT3 001
#define IOBA_XU (IO_UBA3 + 0774510) /* DEUNA/DELUA */
#define IOLN_XU 010
#define IOBA_CR (IO_UBA3 + 0777160) /* CD/CR/CM */
#define IOLN_CR 010
#define IOBA_RY (IO_UBA3 + 0777170) /* RX211 */
#define IOLN_RY 004
#define IOBA_TU (IO_UBA3 + 0772440) /* RH11/tape */
@ -689,6 +699,7 @@ typedef struct pdp_dib DIB;
#define INT_V_PTR 24 /* PC11 */
#define INT_V_PTP 25
#define INT_V_LP20 26 /* LPT20 */
#define INT_V_CR 27 /* CD20 (CD11) */
#define INT_RP (1u << INT_V_RP)
#define INT_TU (1u << INT_V_TU)
@ -699,6 +710,7 @@ typedef struct pdp_dib DIB;
#define INT_PTR (1u << INT_V_PTR)
#define INT_PTP (1u << INT_V_PTP)
#define INT_LP20 (1u << INT_V_LP20)
#define INT_CR (1u << INT_V_CR)
#define IPL_RP 6 /* int levels */
#define IPL_TU 6
@ -709,6 +721,7 @@ typedef struct pdp_dib DIB;
#define IPL_PTR 4
#define IPL_PTP 4
#define IPL_LP20 4
#define IPL_CR 4
#define INT_UB1 INT_RP /* on Unibus 1 */
#define INT_UB3 (0xFFFFFFFFu & ~INT_UB1) /* on Unibus 3 */
@ -723,6 +736,7 @@ typedef struct pdp_dib DIB;
#define VEC_PTP 0074
#define VEC_XU 0120
#define VEC_TU 0224
#define VEC_CR 0230
#define VEC_RP 0254
#define VEC_RY 0264
#define VEC_DZRX 0340
@ -748,4 +762,10 @@ t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat auto_config (char *name, int32 num);
int32 clk_cosched (int32 wait);
/* Global data */
extern t_bool sim_idle_enab;
#endif

View file

@ -1,6 +1,6 @@
/* pdp10_fe.c: PDP-10 front end (console terminal) simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
fe KS10 console front end
17-Oct-06 RMS Synced keyboard to clock for idling
28-May-04 RMS Removed SET FE CTRL-C
29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support
@ -40,6 +41,7 @@
extern d10 *M;
extern int32 apr_flg;
extern int32 tmxr_poll;
t_stat fei_svc (UNIT *uptr);
t_stat feo_svc (UNIT *uptr);
t_stat fe_reset (DEVICE *dptr);
@ -56,14 +58,14 @@ t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc);
#define feo_unit fe_unit[1]
UNIT fe_unit[] = {
{ UDATA (&fei_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&fei_svc, 0, 0), 0 },
{ UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT }
};
REG fe_reg[] = {
{ ORDATA (IBUF, fei_unit.buf, 8) },
{ DRDATA (ICOUNT, fei_unit.pos, T_ADDR_W), REG_RO + PV_LEFT },
{ DRDATA (ITIME, fei_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (ITIME, fei_unit.wait, 24), PV_LEFT },
{ ORDATA (OBUF, feo_unit.buf, 8) },
{ DRDATA (OCOUNT, feo_unit.pos, T_ADDR_W), REG_RO + PV_LEFT },
{ DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT },
@ -139,12 +141,12 @@ t_stat fei_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&fei_unit, fei_unit.wait); /* continue poll */
sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */
fei_unit.buf = temp & 0177;
fei_unit.pos = fei_unit.pos + 1;
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */
uptr->buf = temp & 0177;
uptr->pos = uptr->pos + 1;
M[FE_CTYIN] = uptr->buf | FE_CVALID; /* put char in mem */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK;
}
@ -156,7 +158,7 @@ t_stat fe_reset (DEVICE *dptr)
fei_unit.buf = feo_unit.buf = 0;
M[FE_CTYIN] = M[FE_CTYOUT] = 0;
apr_flg = apr_flg & ~(APRF_ITC | APRF_CON);
sim_activate (&fei_unit, fei_unit.wait); /* start input poll */
sim_activate_abs (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll));
return SCPE_OK;
}

View file

@ -195,7 +195,7 @@ t_bool io710 (int32 ac, a10 ea)
{
d10 val;
if (ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */
if (Q_ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */
else { /* TIOE */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) == 0) return TRUE;
@ -212,7 +212,7 @@ t_bool io711 (int32 ac, a10 ea)
{
d10 val;
if (ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */
if (Q_ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */
else { /* TION */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) != 0) return TRUE;
@ -248,7 +248,7 @@ void io714 (d10 val, a10 ea)
d10 temp;
val = val & 0177777;
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */
if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */
else {
temp = ReadIO (ea); /* BSIO */
temp = temp | val;
@ -266,7 +266,7 @@ void io715 (d10 val, a10 ea)
d10 temp;
val = val & 0177777;
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */
if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */
else {
temp = ReadIO (ea); /* BCIO */
temp = temp & ~val;
@ -284,7 +284,7 @@ t_bool io720 (int32 ac, a10 ea)
{
d10 val;
if (ITS) { /* IORDBI */
if (Q_ITS) { /* IORDBI */
val = ReadIO (IO_UBA3 | eaRB);
AC(ac) = GETBYTE (ea, val);
}
@ -305,7 +305,7 @@ t_bool io721 (int32 ac, a10 ea)
{
d10 val;
if (ITS) { /* IORDBQ */
if (Q_ITS) { /* IORDBQ */
val = ReadIO (IO_UBA1 | eaRB);
AC(ac) = GETBYTE (ea, val);
}
@ -348,7 +348,7 @@ void io724 (d10 val, a10 ea)
d10 temp;
val = val & 0377;
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */
if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */
else {
temp = ReadIO (eaRB); /* BSIOB */
temp = GETBYTE (ea, temp);
@ -367,7 +367,7 @@ void io725 (d10 val, a10 ea)
d10 temp;
val = val & 0377;
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */
if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */
else {
temp = ReadIO (eaRB); /* BCIOB */
temp = GETBYTE (ea, temp);

View file

@ -312,7 +312,7 @@ int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode)
ITS has no MAP instruction, therefore, physical NXM traps are ok.
*/
if (ITS) { /* ITS paging */
if (Q_ITS) { /* ITS paging */
int32 acc, decvpn, pte, vpn, ptead, xpte;
d10 ptewd;
@ -349,7 +349,7 @@ if (ITS) { /* ITS paging */
user process tables.
*/
else if (!T20) { /* TOPS-10 paging */
else if (!T20PAG) { /* TOPS-10 paging */
int32 pte, vpn, ptead, xpte;
d10 ptewd;
@ -377,7 +377,7 @@ else if (!T20) { /* TOPS-10 paging */
PAGE_FAIL_TRAP;
} /* end TOPS10 paging */
/* TOPS-20 paging - checked against KS10 ucode.
/* TOPS-20 paging - checked against KS10 microcode
TOPS-20 paging has three phases:
@ -549,7 +549,7 @@ else {
}
t = EBR_GETEBR (ebr);
epta = t << PAG_V_PN;
if (ITS) upta = (int32) ubr & PAMASK;
if (Q_ITS) upta = (int32) ubr & PAMASK;
else {
t = UBR_GETUBR (ubr);
upta = t << PAG_V_PN;
@ -601,7 +601,7 @@ t_bool clrpt (a10 ea, int32 prv)
{
int32 vpn = PAG_GETVPN (ea); /* get page num */
if (ITS) { /* ITS? */
if (Q_ITS) { /* ITS? */
uptbl[vpn & ~1] = 0; /* clear double size */
uptbl[vpn | 1] = 0; /* entries in */
eptbl[vpn & ~1] = 0; /* both page tables */
@ -631,7 +631,7 @@ return FALSE;
t_bool wrubr (a10 ea, int32 prv)
{
d10 val = Read (ea, prv);
d10 ubr_mask = (ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */
d10 ubr_mask = (Q_ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */
if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */
else val = val & ~UBR_ACBMASK; /* no, keep old val */
@ -647,7 +647,7 @@ return FALSE;
t_bool rdubr (a10 ea, int32 prv)
{
ubr = ubr & (UBR_ACBMASK | (ITS? PAMASK: UBR_UBRMASK));
ubr = ubr & (UBR_ACBMASK | (Q_ITS? PAMASK: UBR_UBRMASK));
Write (ea, UBRWORD, prv);
return FALSE;
}
@ -705,7 +705,7 @@ return FALSE;
t_bool wrcstm (a10 ea, int32 prv)
{
cstm = Read (ea, prv);
if ((cpu_unit.flags & UNIT_T20V41) && (ea == 040127))
if ((cpu_unit.flags & UNIT_T20) && (ea == 040127))
cstm = 0770000000000;
return FALSE;
}

View file

@ -1256,7 +1256,7 @@ extern a10 saved_PC;
M[FE_UNIT] = unitno & CS2_M_UNIT;
for (i = 0; i < BOOT_LEN; i++)
M[BOOT_START + i] = ITS? boot_rom_its[i]: boot_rom_dec[i];
M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i];
saved_PC = BOOT_START;
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp10_sys.c: PDP-10 simulator interface
Copyright (c) 1993-2005, Robert M Supnik
Copyright (c) 1993-2007, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
01-Feb-07 RMS Added CD support
22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn)
09-Jan-03 RMS Added DEUNA/DELUA support
12-Sep-02 RMS Added RX211 support
@ -40,11 +41,18 @@
#include "pdp10_defs.h"
#include <ctype.h>
extern DEVICE cpu_dev, pag_dev;
extern DEVICE tim_dev, fe_dev, uba_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE rp_dev, tu_dev;
extern DEVICE dz_dev, ry_dev;
extern DEVICE cpu_dev;
extern DEVICE pag_dev;
extern DEVICE tim_dev;
extern DEVICE fe_dev;
extern DEVICE uba_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE rp_dev;
extern DEVICE tu_dev;
extern DEVICE dz_dev;
extern DEVICE ry_dev;
extern DEVICE cr_dev;
extern DEVICE lp20_dev;
extern DEVICE xu_dev;
extern UNIT cpu_unit;
@ -78,6 +86,7 @@ DEVICE *sim_devices[] = {
&ptp_dev,
&ry_dev,
&lp20_dev,
&cr_dev,
&rp_dev,
&tu_dev,
&dz_dev,
@ -693,7 +702,7 @@ dev = GET_DEV (inst);
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
if (((opc_val[i] & DMASK) == (inst & masks[j])) && /* match? */
(((opc_val[i] & I_ITS) == 0) || ITS)) {
(((opc_val[i] & I_ITS) == 0) || Q_ITS)) {
fprintf (of, "%s ", opcode[i]); /* opcode */
switch (j) { /* case on class */

View file

@ -1,6 +1,6 @@
/* pdp10_tim.c: PDP-10 tim subsystem simulator
Copyright (c) 1993-2005, Robert M Supnik
Copyright (c) 1993-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
tim timer subsystem
03-Nov-06 RMS Rewritten to support idling
29-Oct-06 RMS Added clock coscheduling function
02-Feb-04 RMS Exported variables needed by Ethernet simulator
29-Jan-02 RMS New data structures
06-Jan-02 RMS Added enable/disable support
@ -37,41 +39,61 @@
#include "pdp10_defs.h"
#include <time.h>
#define TIM_N_HWRE 12 /* hwre bits */
#define TIM_HWRE 0000000010000 /* hwre incr */
#define TIM_DELAY 500
#define TIM_TPS 1001 /* ticks per sec */
#define DZ_MULT (TIM_TPS / 60) /* DZ poll multiplier */
#define TB_MASK 037777777777777777777; /* 71 - 12 bits */
#define UNIT_V_Y2K (UNIT_V_UF) /* Y2K compliant OS */
/* Invariants */
#define TIM_HW_FREQ 4100000 /* 4.1Mhz */
#define TIM_HWRE_MASK 07777
#define UNIT_V_Y2K (UNIT_V_UF + 0) /* Y2K compliant OS */
#define UNIT_Y2K (1u << UNIT_V_Y2K)
/* Clock mode TOPS-10/ITS */
#define TIM_TPS_T10 60
#define TIM_WAIT_T10 8000
#define TIM_MULT_T10 1
#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10)
/* Clock mode TOPS-20/KLAD */
#define TIM_TPS_T20 1001
#define TIM_WAIT_T20 500
#define TIM_MULT_T20 16
/* Probability function for TOPS-20 idlelock */
#define PROB(x) (((rand() * 100) / RAND_MAX) >= (x))
d10 tim_base[2] = { 0, 0 }; /* 71b timebase */
d10 tim_ttg = 0; /* time to go */
d10 tim_period = 0; /* period */
d10 quant = 0; /* ITS quantum */
int32 tim_mult = TIM_MULT_T10; /* tmxr poll mult */
int32 tim_t20_prob = 33; /* TOPS-20 prob */
/* Exported variables */
int32 clk_tps = TIM_TPS_T10; /* clock ticks/sec */
int32 tmr_poll = TIM_WAIT_T10; /* clock poll */
int32 tmxr_poll = TIM_WAIT_T10 * TIM_MULT_T10; /* term mux poll */
extern int32 apr_flg, pi_act;
extern UNIT cpu_unit;
extern d10 pcst;
extern a10 pager_PC;
t_int64 timebase = 0; /* 71b timebase */
d10 ttg = 0; /* time to go */
d10 period = 0; /* period */
d10 quant = 0; /* ITS quantum */
int32 diagflg = 0; /* diagnostics? */
int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */
/* Exported variables */
int32 clk_tps = TIM_TPS; /* clock ticks/sec */
int32 tmr_poll = TIM_DELAY; /* clock poll */
extern int32 t20_idlelock;
DEVICE tim_dev;
t_stat tcu_rd (int32 *data, int32 PA, int32 access);
extern t_stat wr_nop (int32 data, int32 PA, int32 access);
t_stat tim_svc (UNIT *uptr);
t_stat tim_reset (DEVICE *dptr);
void tim_incr_base (d10 *base, d10 incr);
extern d10 Read (a10 ea, int32 prv);
extern d10 ReadM (a10 ea, int32 prv);
extern void Write (a10 ea, d10 val, int32 prv);
extern void WriteP (a10 ea, d10 val);
extern int32 pi_eval (void);
extern t_stat wr_nop (int32 data, int32 PA, int32 access);
/* TIM data structures
@ -82,16 +104,19 @@ extern int32 pi_eval (void);
DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 };
UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_DELAY };
UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_WAIT_T10 };
REG tim_reg[] = {
{ ORDATA (TIMEBASE, timebase, 71 - TIM_N_HWRE) },
{ ORDATA (TTG, ttg, 36) },
{ ORDATA (PERIOD, period, 36) },
{ BRDATA (TIMEBASE, tim_base, 8, 36, 2) },
{ ORDATA (TTG, tim_ttg, 36) },
{ ORDATA (PERIOD, tim_period, 36) },
{ ORDATA (QUANT, quant, 36) },
{ DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (DIAG, diagflg, 0) },
{ FLDATA (Y2K, tim_unit.flags, UNIT_V_Y2K), REG_HRO },
{ DRDATA (PROB, tim_t20_prob, 6), REG_NZ + PV_LEFT + REG_HIDDEN },
{ DRDATA (POLL, tmr_poll, 32), REG_HRO + PV_LEFT },
{ DRDATA (MUXPOLL, tmxr_poll, 32), REG_HRO + PV_LEFT },
{ DRDATA (MULT, tim_mult, 6), REG_HRO + PV_LEFT },
{ DRDATA (TPS, clk_tps, 12), REG_HRO + PV_LEFT },
{ NULL }
};
@ -108,79 +133,135 @@ DEVICE tim_dev = {
1, 0, 0, 0, 0, 0,
NULL, NULL, &tim_reset,
NULL, NULL, NULL,
&tcu_dib, DEV_DISABLE | DEV_UBUS
&tcu_dib, DEV_UBUS
};
/* Timer instructions */
/* Timer - if the timer is running at less than hardware frequency,
need to interpolate the value by calculating how much of the current
clock tick has elapsed, and what that equates to in msec. */
t_bool rdtim (a10 ea, int32 prv)
{
ReadM (INCA (ea), prv);
Write (ea, (timebase >> (35 - TIM_N_HWRE)) & DMASK, prv);
Write (INCA(ea), (timebase << TIM_N_HWRE) & MMASK, prv);
d10 tempbase[2];
ReadM (INCA (ea), prv); /* check 2nd word */
tempbase[0] = tim_base[0]; /* copy time base */
tempbase[1] = tim_base[1];
if (tim_mult != TIM_MULT_T20) { /* interpolate? */
int32 used;
d10 incr;
used = tmr_poll - (sim_is_active (&tim_unit) - 1);
incr = (d10) (((double) used * TIM_HW_FREQ) /
((double) tmr_poll * (double) clk_tps));
tim_incr_base (tempbase, incr);
}
tempbase[0] = tempbase[0] & ~((d10) TIM_HWRE_MASK); /* clear low 12b */
Write (ea, tempbase[0], prv);
Write (INCA(ea), tempbase[1], prv);
return FALSE;
}
t_bool wrtim (a10 ea, int32 prv)
{
timebase = (Read (ea, prv) << (35 - TIM_N_HWRE)) |
(CLRS (Read (INCA (ea), prv)) >> TIM_N_HWRE);
tim_base[0] = Read (ea, prv);
tim_base[1] = CLRS (Read (INCA (ea), prv));
return FALSE;
}
t_bool rdint (a10 ea, int32 prv)
{
Write (ea, period, prv);
Write (ea, tim_period, prv);
return FALSE;
}
t_bool wrint (a10 ea, int32 prv)
{
period = Read (ea, prv);
ttg = period;
tim_period = Read (ea, prv);
tim_ttg = tim_period;
return FALSE;
}
/* Timer routines
tim_svc process event (timer tick)
tim_reset process reset
*/
/* Timer service - the timer is only serviced when the 'ttg' register
has reached 0 based on the expected frequency of clock interrupts. */
t_stat tim_svc (UNIT *uptr)
{
int32 t;
t = diagflg? tim_unit.wait: sim_rtc_calb (TIM_TPS); /* calibrate clock */
sim_activate (&tim_unit, t); /* reactivate unit */
tmr_poll = t; /* set timer poll */
tmxr_poll = t * DZ_MULT; /* set mux poll */
timebase = (timebase + 1) & TB_MASK; /* increment timebase */
ttg = ttg - TIM_HWRE; /* decrement timer */
if (ttg <= 0) { /* timeout? */
ttg = period; /* reload */
if (cpu_unit.flags & UNIT_KLAD) /* diags? */
tmr_poll = uptr->wait; /* fixed clock */
else tmr_poll = sim_rtc_calb (clk_tps); /* else calibrate */
sim_activate (uptr, tmr_poll); /* reactivate unit */
tmxr_poll = tmr_poll * tim_mult; /* set mux poll */
tim_incr_base (tim_base, tim_period); /* incr time base */
tim_ttg = tim_period; /* reload */
apr_flg = apr_flg | APRF_TIM; /* request interrupt */
}
if (ITS) { /* ITS? */
if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK;
if (Q_ITS) { /* ITS? */
if (pi_act == 0)
quant = (quant + TIM_ITS_QUANT) & DMASK;
if (TSTS (pcst)) { /* PC sampling? */
WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */
pcst = AOB (pcst); /* add 1,,1 */
}
} /* end ITS */
else if (t20_idlelock && PROB (100 - tim_t20_prob))
t20_idlelock = 0;
return SCPE_OK;
}
t_stat tim_reset (DEVICE *dptr)
/* Clock coscheduling routine */
int32 clk_cosched (int32 wait)
{
int32 t;
period = ttg = 0; /* clear timer */
if (tim_mult == TIM_MULT_T20) return wait;
t = sim_is_active (&tim_unit);
return (t? t - 1: wait);
}
void tim_incr_base (d10 *base, d10 incr)
{
base[1] = base[1] + incr; /* add on incr */
base[0] = base[0] + (base[1] >> 35); /* carry to high */
base[0] = base[0] & DMASK; /* mask high */
base[1] = base[1] & MMASK; /* mask low */
return;
}
/* Timer reset */
t_stat tim_reset (DEVICE *dptr)
{
tim_period = 0; /* clear timer */
tim_ttg = 0;
apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */
t = sim_rtc_init (tim_unit.wait); /* init timer */
sim_activate (&tim_unit, t); /* activate unit */
tmr_poll = t; /* set timer poll */
tmxr_poll = t * DZ_MULT; /* set mux poll */
tmr_poll = sim_rtc_init (tim_unit.wait); /* init timer */
sim_activate_abs (&tim_unit, tmr_poll); /* activate unit */
tmxr_poll = tmr_poll * tim_mult; /* set mux poll */
return SCPE_OK;
}
/* Set timer parameters from CPU model */
t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (val & (UNIT_T20|UNIT_KLAD)) {
clk_tps = TIM_TPS_T20;
uptr->wait = TIM_WAIT_T20;
tmr_poll = TIM_WAIT_T20;
tim_mult = TIM_MULT_T20;
uptr->flags = uptr->flags | UNIT_Y2K;
}
else {
clk_tps = TIM_TPS_T10;
uptr->wait = TIM_WAIT_T10;
tmr_poll = TIM_WAIT_T10;
tim_mult = TIM_MULT_T10;
if (Q_ITS) uptr->flags = uptr->flags | UNIT_Y2K;
else uptr->flags = uptr->flags & ~UNIT_Y2K;
}
tmxr_poll = tmr_poll * tim_mult;
return SCPE_OK;
}

View file

@ -1225,7 +1225,7 @@ M[FE_UNIT] = 0;
M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT);
tu_unit[unitno].pos = 0;
for (i = 0; i < BOOT_LEN; i++)
M[BOOT_START + i] = ITS? boot_rom_its[i]: boot_rom_dec[i];
M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i];
saved_PC = BOOT_START;
return SCPE_OK;
}

View file

@ -1192,15 +1192,18 @@ return TestDstr (src); /* clean -0 */
dsrc = decimal string descriptor
src = decimal string structure
flag = numeric/packed flag
PSW.NZ are also set to their proper values
PSW.V will be set on overflow; it must be initialized elsewhere
(to allow for external overflow calculations)
The rules for the stored sign and the PSW sign are:
- Stored sign is negative if input is negative, string type
is signed, and the result is non-zero or there was overflow
- PSW sign is negative if input is negative, string type is
signed, and the result is non-zero
Thus, the stored sign and the PSW sign will differ in one case:
a negative zero generated by overflow is stored with a negative
sign, but PSW.N is clear
@ -1265,16 +1268,18 @@ return;
cy = carry in
Output = 1 if carry, 0 if no carry
This algorithm courtesy Anton Chernoff, circa 1992 or even earlier
This algorithm courtesy Anton Chernoff, circa 1992 or even earlier.
We trace the history of a pair of adjacent digits to see how the
carry is fixed; each parenthesized item is a 4b digit.
Assume we are adding:
(a)(b) I
+ (x)(y) J
First compute I^J:
(a^x)(b^y) TMP
Note that the low bit of each digit is the same as the low bit of
@ -1283,6 +1288,7 @@ return;
Now compute I+J+66 to get decimal addition with carry forced left
one digit:
(a+x+6+carry mod 16)(b+y+6 mod 16) SUM
Note that if there was a carry from b+y+6, then the low bit of the
@ -1357,6 +1363,7 @@ return 0;
Arguments:
dsrc = decimal string structure
Returns the non-zero length of the string, in int32 units
If the string is zero, the sign is cleared
*/
@ -1395,8 +1402,8 @@ return ((nz - 1) * 8) + i;
mtable[10] = array of decimal string structures
Note that dsrc has a high order zero nibble; this
guarantees that the largest multiple won't overflow
Also note that mtable[0] is not filled in
guarantees that the largest multiple won't overflow.
Also note that mtable[0] is not filled in.
*/
void CreateTable (DSTR *dsrc, DSTR mtable[10])
@ -1560,7 +1567,7 @@ fpd = 0; /* instr done */
return;
}
/* Test for CIS mid-instruction interrupt - stub for now */
/* Test for CIS mid-instruction interrupt */
t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st)
{

View file

@ -25,6 +25,8 @@
cpu PDP-11 CPU
27-Oct-06 RMS Added idle support
18-Oct-06 RMS Fixed bug in ASH -32 C value
24-May-06 RMS Added instruction history
03-May-06 RMS Fixed XOR operand fetch order for 11/70-style systems
22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
@ -220,8 +222,8 @@
#define calc_is(md) ((md) << VA_V_MODE)
#define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0))
#define calc_MMR1(val) ((MMR1)? (((val) << 8) | MMR1): (val))
#define GET_SIGN_W(v) ((v) >> 15)
#define GET_SIGN_B(v) ((v) >> 7)
#define GET_SIGN_W(v) (((v) >> 15) & 1)
#define GET_SIGN_B(v) (((v) >> 7) & 1)
#define GET_Z(v) ((v) == 0)
#define JMP_PC(x) PCQ_ENTRY; PC = (x)
#define BRANCH_F(x) PCQ_ENTRY; PC = (PC + (((x) + (x)) & 0377)) & 0177777
@ -300,6 +302,7 @@ extern UNIT clk_unit, pclk_unit;
extern int32 sim_int_char;
extern uint32 sim_switches;
extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern t_bool sim_idle_enab;
extern DEVICE *sim_devices[];
extern CPUTAB cpu_tab[];
@ -376,7 +379,7 @@ int32 trap_clear[TRAP_V_MAX] = { /* trap clears */
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, INIMEMSIZE) };
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX|UNIT_BINK, INIMEMSIZE) };
REG cpu_reg[] = {
{ ORDATA (PC, saved_PC, 16) },
@ -533,7 +536,7 @@ REG cpu_reg[] = {
{ BRDATA (IREQ, int_req, 8, 32, IPL_HLVL), REG_RO },
{ ORDATA (TRAPS, trap_req, TRAP_V_MAX) },
{ FLDATA (WAIT, wait_state, 0) },
{ FLDATA (WAIT_ENABLE, wait_enable, 0) },
{ FLDATA (WAIT_ENABLE, wait_enable, 0), REG_HIDDEN },
{ ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) },
{ FLDATA (STOP_VECA, stop_vecabort, 0) },
{ FLDATA (STOP_SPA, stop_spabort, 0) },
@ -583,6 +586,8 @@ MTAB cpu_mod[] = {
{ MTAB_XTD|MTAB_VDV, OPT_CIS, NULL, "NOCIS", &cpu_clr_opt },
{ MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "MMU", &cpu_set_opt },
{ MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "NOMMU", &cpu_clr_opt },
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size},
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size},
{ UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size},
@ -786,8 +791,11 @@ while (reason == 0) {
if (tbit) setTRAP (TRAP_TRC);
if (wait_state) { /* wait state? */
if (sim_qcount () != 0) sim_interval = 0; /* force check */
else reason = STOP_WAIT;
if (sim_idle_enab) /* idle enabled? */
sim_idle (TMR_CLK, TRUE);
else if (wait_enable) /* old style idle? */
sim_interval = 0; /* force check */
else sim_interval = sim_interval - 1; /* count cycle */
continue;
}
@ -846,7 +854,7 @@ while (reason == 0) {
else setTRAP (TRAP_ILL); /* no, ill inst */
break;
case 1: /* WAIT */
if (wait_enable) wait_state = 1;
wait_state = 1;
break;
case 3: /* BPT */
setTRAP (TRAP_BPT);
@ -1374,7 +1382,7 @@ while (reason == 0) {
else PWriteW (dst, last_pa);
break;
/* Opcode 07: EIS, FIS (not implemented), CIS
/* Opcode 07: EIS, FIS, CIS
Notes:
- The code assumes that the host int length is at least 32 bits.
@ -1471,7 +1479,8 @@ while (reason == 0) {
}
else if (src2 == 32) { /* [32] = -32 */
dst = -sign;
V = C = 0;
V = 0;
C = sign;
}
else { /* [33,63] = -31,-1 */
dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
@ -1505,7 +1514,7 @@ while (reason == 0) {
else if (src2 == 32) { /* [32] = -32 */
dst = -sign;
V = 0;
C = (src >> 31) & 1;
C = sign;
}
else { /* [33,63] = -31,-1 */
dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
@ -2136,7 +2145,7 @@ if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */
}
pa = relocR (va); /* relocate */
if (ADDR_IS_MEM (pa)) return (M[pa >> 1]); /* memory address? */
if ((pa < IOPAGEBASE) || /* I/O address */
if ((pa < IOPAGEBASE) || /* not I/O address */
(CPUT (CPUT_J) && (pa >= IOBA_CPU))) { /* or J11 int reg? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
@ -2158,7 +2167,7 @@ if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */
}
pa = relocR (va); /* relocate */
if (ADDR_IS_MEM (pa)) return (M[pa >> 1]); /* memory address? */
if (pa < IOPAGEBASE) { /* I/O address? */
if (pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2175,7 +2184,7 @@ int32 pa, data;
pa = relocR (va); /* relocate */
if (ADDR_IS_MEM (pa)) return (va & 1? M[pa >> 1] >> 8: M[pa >> 1]) & 0377;
if (pa < IOPAGEBASE) { /* I/O address? */
if (pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2196,7 +2205,7 @@ if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */
}
last_pa = relocW (va); /* reloc, wrt chk */
if (ADDR_IS_MEM (last_pa)) return (M[last_pa >> 1]); /* memory address? */
if (last_pa < IOPAGEBASE) { /* I/O address? */
if (last_pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2214,7 +2223,7 @@ int32 data;
last_pa = relocW (va); /* reloc, wrt chk */
if (ADDR_IS_MEM (last_pa))
return (va & 1? M[last_pa >> 1] >> 8: M[last_pa >> 1]) & 0377;
if (last_pa < IOPAGEBASE) { /* I/O address? */
if (last_pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2247,7 +2256,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */
M[pa >> 1] = data;
return;
}
if (pa < IOPAGEBASE) { /* I/O address? */
if (pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2268,7 +2277,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */
else M[pa >> 1] = (M[pa >> 1] & ~0377) | data;
return;
}
if (pa < IOPAGEBASE) { /* I/O address? */
if (pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2285,7 +2294,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */
M[pa >> 1] = data;
return;
}
if (pa < IOPAGEBASE) { /* I/O address? */
if (pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2303,7 +2312,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */
else M[pa >> 1] = (M[pa >> 1] & ~0377) | data;
return;
}
if (pa < IOPAGEBASE) { /* I/O address? */
if (pa < IOPAGEBASE) { /* not I/O address? */
setCPUERR (CPUE_NXM);
ABORT (TRAP_NXM);
}
@ -2574,8 +2583,8 @@ switch ((pa >> 1) & 3) { /* decode pa<2:1> */
case 3: /* MMR2 */
*data = MMR2;
break;
}
/* end switch pa */
} /* end switch pa */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp11_cr.c: CR/CM/CD-11 card reader simulator
Copyright (c) 2005, John A. Dundas III
Copyright (c) 2005-2007, John A. Dundas III
Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu
Portions derived from work by Robert M Supnik
@ -51,8 +51,8 @@
http://www.cs.uiowa.edu/~jones/cards/
Paul Mattes' x026 keypunch simulator
http://x3270.bgp.nu/x026.html
CDRSER.MAC - TOPS card reader driver source
http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cdrser.mac
CD2SER.MAC - TOPS card reader driver source
http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cd2ser.mac
The Card Image format code and documentation is adapted from Prof.
Jones's site, with his permission. Please see his site for additional
@ -66,14 +66,13 @@
3. No testing under RSX; volunteers needed
4. No testing under Ultrix or Unix for PDP-11; volunteers needed
5. No testing under Ultrix or Unix for VAX; volunteers needed
6. No PDP-10 support; volunteers needed
7. The simulator implements a single controller/reader combination
6. The simulator implements a single controller/reader combination
Operating System Notes
RT-11 (and CTS-300) support one CR11 or CM11, but no CD11.
VMS supports multiple CR11 controllers.
VMS supports multiple CR11 controllers, but no CD11.
RSTS/E supports either the CR11/CM11 or CD11 but not both in
the same SIL. It appears to support only one unit.
@ -84,12 +83,11 @@
Don't have any information about Unix or Ultrix-11 yet. Same
for VAX Unices.
TOPS: it appears that both the CD11 and CR11 were supported.
I don't have any knowledge on how to make this work with the
PDP-10 simulation, though.
TOPS: only the CD11 is supported, under the name CD20.
Revision History:
01-Feb-07 RMS Added PDP-10 support
12-May-06 JAD Modify the DEBUG code to use the SIMH DEBUG_x
macros. Modify the UNIT structure to include
the DEBUG bit.
@ -168,14 +166,23 @@
#if defined (VM_PDP10) /* PDP10 version */
#include "pdp10_defs.h"
extern int32 int_req;
#define DFLT_DIS (DEV_DIS)
#define DFLT_CR11 (0) /* CD11 only */
#define DFLT_CPM 1000
#elif defined (VM_VAX) /* VAX version */
#include "vax_defs.h"
extern int32 int_req[IPL_HLVL];
#define DFLT_DIS (0)
#define DFLT_CR11 (UNIT_CR11)
#define DFLT_CPM 285
#else /* PDP-11 version */
#include "pdp11_defs.h"
extern int32 int_req[IPL_HLVL];
#define DFLT_DIS (0)
#define DFLT_CR11 (UNIT_CR11)
#define DFLT_CPM 285
#endif
extern FILE *sim_deb; /* sim_console.c */
@ -294,7 +301,7 @@ static int32 blowerState = BLOW_OFF; /* reader vacuum/blower
static int32 spinUp = 3000; /* blower spin-up time: 3 seconds */
static int32 spinDown = 2000; /* blower spin-down time: 2 seconds */
static t_bool EOFcard = FALSE; /* played special card yet? */
static int32 cpm = 285; /* reader rate: cards per minute */
static int32 cpm = DFLT_CPM; /* reader rate: cards per minute */
/* card image in various formats */
static int16 hcard[82]; /* Hollerith format */
static char ccard[82]; /* DEC compressed format */
@ -343,8 +350,8 @@ static DIB cr_dib = { IOBA_CR, IOLN_CR, &cr_rd, &cr_wr,
static UNIT cr_unit = {
UDATA (&cr_svc,
UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE+UNIT_DISABLE+
UNIT_CR11+UNIT_AUTOEOF, 0),
(60 * 1000) / 285 };
DFLT_CR11+UNIT_AUTOEOF, 0),
(60 * 1000) / DFLT_CPM };
static const REG cr_reg[] = {
{ GRDATA (BUF, cr_unit.buf, DEV_RDX, 8, 0) },
@ -367,8 +374,13 @@ static const REG cr_reg[] = {
{ NULL } };
static const MTAB cr_mod[] = {
#if defined (VM_PDP11)
{ UNIT_CR11, UNIT_CR11, "CR11", "CR11", &cr_set_type },
{ UNIT_CR11, 0, "CD11", "CD11", &cr_set_type },
#else
{ UNIT_CR11, UNIT_CR11, "CR11", NULL },
{ UNIT_CR11, 0, "CD11", NULL },
#endif
{ UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", NULL },
{ UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", NULL },
/* card reader RESET switch */
@ -395,7 +407,7 @@ DEVICE cr_dev = {
1, 10, 31, 1, DEV_RDX, 8,
NULL, NULL, &cr_reset,
NULL, &cr_attach, &cr_detach,
&cr_dib, DEV_DISABLE | DEV_UBUS | DEV_DEBUG };
&cr_dib, DEV_DISABLE | DFLT_DIS | DEV_UBUS | DEV_DEBUG };
/* Utility routines */

View file

@ -26,6 +26,8 @@
The author gratefully acknowledges the help of Max Burnet, Megan Gentry,
and John Wilson in resolving questions about the PDP-11
16-Dec-06 RMS Added TA11 support
29-Oct-06 RMS Added clock coscheduling
06-Jul-06 RMS Added multiple KL11/DL11 support
26-Jun-06 RMS Added RF11 support
24-May-06 RMS Added 11/44 DR support (from CIS diagnostic)
@ -569,6 +571,8 @@ typedef struct pdp_dib DIB;
#define IOLN_HK 040
#define IOBA_RF (IOPAGEBASE + 017460) /* RF11 */
#define IOLN_RF 020
#define IOBA_TA (IOPAGEBASE + 017500) /* TA11 */
#define IOLN_TA 004
#define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */
#define IOLN_LPT 004
#define IOBA_CTL (IOPAGEBASE + 017520) /* board ctrl */
@ -613,7 +617,8 @@ typedef struct pdp_dib DIB;
#define INT_V_CLK 0 /* BR6 */
#define INT_V_PCLK 1
#define INT_V_DTA 2
#define INT_V_PIR6 3
#define INT_V_TA 3
#define INT_V_PIR6 4
#define INT_V_RK 0 /* BR5 */
#define INT_V_RL 1
@ -653,6 +658,7 @@ typedef struct pdp_dib DIB;
#define INT_CLK (1u << INT_V_CLK)
#define INT_PCLK (1u << INT_V_PCLK)
#define INT_DTA (1u << INT_V_DTA)
#define INT_TA (1u << INT_V_TA)
#define INT_PIR6 (1u << INT_V_PIR6)
#define INT_RK (1u << INT_V_RK)
#define INT_RL (1u << INT_V_RL)
@ -689,6 +695,7 @@ typedef struct pdp_dib DIB;
#define IPL_CLK 6 /* int pri levels */
#define IPL_PCLK 6
#define IPL_DTA 6
#define IPL_TA 6
#define IPL_RK 5
#define IPL_RL 5
#define IPL_RX 5
@ -749,6 +756,7 @@ typedef struct pdp_dib DIB;
#define VEC_CR 0230
#define VEC_RP 0254
#define VEC_TQ 0260
#define VEC_TA 0260
#define VEC_RX 0264
#define VEC_RY 0264
#define VEC_TTIX 0300
@ -810,4 +818,6 @@ void mba_set_don (uint32 mbus);
void mba_set_enbdis (uint32 mb, t_bool dis);
t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc);
int32 clk_cosched (int32 wait);
#endif

View file

@ -1,6 +1,6 @@
/* pdp11_dz.c: DZ11 terminal multiplexor simulator
Copyright (c) 2001-2005, Robert M Supnik
Copyright (c) 2001-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
dz DZ11 terminal multiplexor
29-Oct-06 RMS Synced poll and clock
22-Nov-05 RMS Revised for new terminal processing routines
07-Jul-05 RMS Removed extraneous externs
15-Jun-05 RMS Revised for new autoconfigure interface
@ -304,7 +305,8 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */
(dz_csr[dz] & 0377) | (data << 8):
(dz_csr[dz] & ~0377) | data;
if (data & CSR_CLR) dz_clear (dz, FALSE); /* clr? reset */
if (data & CSR_MSE) sim_activate (&dz_unit, tmxr_poll);
if (data & CSR_MSE) /* MSE? start poll */
sim_activate (&dz_unit, clk_cosched (tmxr_poll));
else dz_csr[dz] &= ~(CSR_SA | CSR_RDONE | CSR_TRDY);
if ((data & CSR_RIE) == 0) dz_clr_rxint (dz); /* RIE = 0? */
else if (((dz_csr[dz] & CSR_IE) == 0) && /* RIE 0->1? */

View file

@ -145,17 +145,25 @@
/* Double precision operations on 64b quantities */
#define F_LOAD(qd,ac,ds) ds.h = ac.h; ds.l = (qd)? ac.l: 0
#define F_LOAD_P(qd,ac,ds) ds->h = ac.h; ds->l = (qd)? ac.l: 0
#define F_LOAD_FRAC(qd,ac,ds) ds.h = (ac.h & FP_FRACH) | FP_HB; \
#define F_LOAD(qd,ac,ds) \
ds.h = ac.h; ds.l = (qd)? ac.l: 0
#define F_LOAD_P(qd,ac,ds) \
ds->h = ac.h; ds->l = (qd)? ac.l: 0
#define F_LOAD_FRAC(qd,ac,ds) \
ds.h = (ac.h & FP_FRACH) | FP_HB; \
ds.l = (qd)? ac.l: 0
#define F_STORE(qd,sr,ac) ac.h = sr.h; if ((qd)) ac.l = sr.l
#define F_STORE_P(qd,sr,ac) ac.h = sr->h; if ((qd)) ac.l = sr->l
#define F_GET_FRAC_P(sr,ds) ds.l = sr->l; \
#define F_STORE(qd,sr,ac) \
ac.h = sr.h; if ((qd)) ac.l = sr.l
#define F_STORE_P(qd,sr,ac) \
ac.h = sr->h; if ((qd)) ac.l = sr->l
#define F_GET_FRAC_P(sr,ds) \
ds.l = sr->l; \
ds.h = (sr->h & FP_FRACH) | FP_HB
#define F_ADD(s2,s1,ds) ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \
#define F_ADD(s2,s1,ds) \
ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \
ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF
#define F_SUB(s2,s1,ds) ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \
#define F_SUB(s2,s1,ds) \
ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \
ds.l = (s1.l - s2.l) & 0xFFFFFFFF
#define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l)))
#define F_LT_AP(x,y) (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \
@ -252,7 +260,8 @@ int32 i, qdouble, lenf, leni;
int32 newV, exp, sign;
fpac_t fac, fsrc, modfrac;
static const uint32 i_limit[2][2] = {
{ 0x80000000, 0x80010000 }, { 0x80000000, 0x80000001 }
{ 0x80000000, 0x80010000 },
{ 0x80000000, 0x80000001 }
};
backup_PC = PC; /* save PC for FEA */
@ -602,7 +611,8 @@ return 0;
uint32 ReadI (int32 VA, int32 spec, int32 len)
{
if ((len == WORD) || (spec == 027)) return (ReadW (VA) << 16);
return ((ReadW (VA) << 16) | ReadW ((VA & ~0177777) | ((VA + 2) & 0177777)));
return ((ReadW (VA) << 16) |
ReadW ((VA & ~0177777) | ((VA + 2) & 0177777)));
}
/* Read floating operand

View file

@ -705,6 +705,7 @@ switch (fnc) { /* case on function */
case FNC_NOP: /* no operation */
update_hkcs (CS1_DONE, drv); /* done */
break;
case FNC_PACK: /* pack acknowledge */
hkds[drv] = hkds[drv] | DS_VV; /* set volume valid */
update_hkcs (CS1_DONE, drv); /* done */

View file

@ -25,6 +25,7 @@
rf RF11 fixed head disk
25-Dec-06 RMS Fixed bug in unit mask (found by John Dundas)
26-Jun-06 RMS Cloned from RF08 simulator
The RF11 is a head-per-track disk. To minimize overhead, the entire RF11
@ -42,7 +43,7 @@
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
#define UNIT_M_PLAT 03
#define UNIT_M_PLAT (RF_NUMDK - 1)
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)

View file

@ -31,12 +31,15 @@
WARNING: The interupt logic of the RH11/RH70 is unusual and must be
simulated with great precision. The RH11 has an internal interrupt
request flop, CSTB INTR, which is controlled as follows:
- Writing IE and DONE simultaneously sets CSTB INTR
- Controller clear, INIT, and interrupt acknowledge clear CSTB INTR
(and also clear IE)
- A transition of DONE from 0 to 1 sets CSTB INTR from IE
The output of CSTB INTR is OR'd with the AND of RPCS1<SC,DONE,IE> to
create the interrupt request signal. Thus,
- The DONE interrupt is edge sensitive, but the SC interrupt is
level sensitive.
- The DONE interrupt, once set, is not disabled if IE is cleared,

View file

@ -75,7 +75,8 @@
#define RK_NUMTR (RK_NUMCY * RK_NUMSF) /* tracks/drive */
#define RK_NUMDR 8 /* drives/controller */
#define RK_M_NUMDR 07
#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */
#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD)
/* words/drive */
#define RK_CTLI 1 /* controller int */
#define RK_SCPI(x) (2u << (x)) /* drive int */
#define RK_MAXFR (1 << 16) /* max transfer */
@ -297,8 +298,10 @@ switch ((PA >> 1) & 07) { /* decode PA<3:1> */
rkds = (rkds & RKDS_ID) | RKDS_RK05 | RKDS_SC_OK |
(rand () % RK_NUMSC); /* random sector */
uptr = rk_dev.units + GET_DRIVE (rkda); /* selected unit */
if (uptr->flags & UNIT_ATT) rkds = rkds | RKDS_RDY; /* attached? */
if (!sim_is_active (uptr)) rkds = rkds | RKDS_RWS; /* idle? */
if (uptr->flags & UNIT_ATT) /* attached? */
rkds = rkds | RKDS_RDY;
if (!sim_is_active (uptr)) /* idle? */
rkds = rkds | RKDS_RWS;
if (uptr->flags & UNIT_WPRT) rkds = rkds | RKDS_WLK;
if (GET_SECT (rkda) == (rkds & RKDS_SC)) rkds = rkds | RKDS_ON_SC;
*data = rkds;
@ -356,7 +359,8 @@ switch ((PA >> 1) & 07) { /* decode PA<3:1> */
SET_INT (RK); /* set int request */
}
rkcs = (rkcs & ~RKCS_RW) | (data & RKCS_RW);
if ((rkcs & CSR_DONE) && (data & CSR_GO)) rk_go (); /* new function? */
if ((rkcs & CSR_DONE) && (data & CSR_GO)) /* new function? */
rk_go ();
return SCPE_OK;
case 3: /* RKWC */
@ -410,8 +414,9 @@ if (uptr->flags & UNIT_DIS) { /* not present? */
rk_set_done (RKER_NXD);
return;
}
if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) {
rk_set_done (RKER_DRE); /* not att or busy */
if (((uptr->flags & UNIT_ATT) == 0) || /* not att or busy? */
sim_is_active (uptr)) {
rk_set_done (RKER_DRE);
return;
}
if ((rkcs & RKCS_FMT) && /* format and */
@ -419,8 +424,9 @@ if ((rkcs & RKCS_FMT) && /* format and */
rk_set_done (RKER_PGE);
return;
}
if ((func == RKCS_WRITE) && (uptr->flags & UNIT_WPRT)) {
rk_set_done (RKER_WLK); /* write and locked? */
if ((func == RKCS_WRITE) && /* write and locked? */
(uptr->flags & UNIT_WPRT)) {
rk_set_done (RKER_WLK);
return;
}
if (func == RKCS_WLK) { /* write lock? */

View file

@ -26,6 +26,8 @@
tti,tto DL11 terminal input/output
clk KW11L (and other) line frequency clock
29-Oct-06 RMS Synced keyboard and clock
Added clock coscheduling support
05-Jul-06 RMS Added UC only support for early DOS/RSTS
22-Nov-05 RMS Revised for new terminal processing routines
22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
@ -107,7 +109,7 @@ DIB tti_dib = {
1, IVCL (TTI), VEC_TTI, { NULL }
};
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), 0 };
REG tti_reg[] = {
{ ORDATA (BUF, tti_unit.buf, 8) },
@ -117,7 +119,7 @@ REG tti_reg[] = {
{ FLDATA (DONE, tti_csr, CSR_V_DONE) },
{ FLDATA (IE, tti_csr, CSR_V_IE) },
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), PV_LEFT },
{ NULL }
};
@ -153,7 +155,7 @@ DIB tto_dib = {
1, IVCL (TTO), VEC_TTO, { NULL }
};
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_7P, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, 8) },
@ -281,7 +283,7 @@ t_stat tti_svc (UNIT *uptr)
{
int32 c;
sim_activate (uptr, uptr->wait); /* continue poll */
sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
if (c & SCPE_BREAK) uptr->buf = 0; /* break? */
else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
@ -298,7 +300,7 @@ t_stat tti_reset (DEVICE *dptr)
tti_unit.buf = 0;
tti_csr = 0;
CLR_INT (TTI);
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll));
return SCPE_OK;
}
@ -434,6 +436,16 @@ if (CPUT (CPUT_24)) clk_csr = clk_csr & ~CSR_DONE;
return clk_dib.vec;
}
/* Clock coscheduling routine */
int32 clk_cosched (int32 wait)
{
int32 t;
t = sim_is_active (&clk_unit);
return (t? t - 1: wait);
}
/* Clock reset */
t_stat clk_reset (DEVICE *dptr)

View file

@ -23,6 +23,8 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
20-Dec-06 RMS Added TA11 support
12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller)
14-Jul-06 RMS Reordered device list
06-Jul-06 RMS Added multiple KL11/DL11 support
26-Jun-06 RMS Added RF11 support
@ -85,6 +87,7 @@ extern DEVICE tm_dev;
extern DEVICE tq_dev;
extern DEVICE ts_dev;
extern DEVICE tu_dev;
extern DEVICE ta_dev;
extern DEVICE xq_dev, xqb_dev;
extern DEVICE xu_dev, xub_dev;
extern UNIT cpu_unit;
@ -141,6 +144,7 @@ DEVICE *sim_devices[] = {
&ts_dev,
&tq_dev,
&tu_dev,
&ta_dev,
&xq_dev,
&xqb_dev,
&xu_dev,
@ -311,7 +315,7 @@ return SCPE_OK;
/* Warning: for literals, the class number MUST equal the field width!! */
#define I_V_CL 18 /* class bits */
#define I_M_CL 017 /* class mask */
#define I_M_CL 037 /* class mask */
#define I_V_NPN 0 /* no operands */
#define I_V_REG 1 /* reg */
#define I_V_SOP 2 /* operand */
@ -328,6 +332,7 @@ return SCPE_OK;
#define I_V_DOP 13 /* double operand */
#define I_V_CCC 14 /* CC clear */
#define I_V_CCS 15 /* CC set */
#define I_V_SOPR 16 /* operand, reg */
#define I_NPN (I_V_NPN << I_V_CL)
#define I_REG (I_V_REG << I_V_CL)
#define I_3B (I_V_3B << I_V_CL)
@ -344,12 +349,14 @@ return SCPE_OK;
#define I_DOP (I_V_DOP << I_V_CL)
#define I_CCC (I_V_CCC << I_V_CL)
#define I_CCS (I_V_CCS << I_V_CL)
#define I_SOPR (I_V_SOPR << I_V_CL)
static const int32 masks[] = {
0177777, 0177770, 0177700, 0177770,
0177700+I_D, 0177400+I_D, 0177700, 0177400,
0177400, 0177000, 0177000, 0177400,
0177400+I_D+I_L, 0170000, 0177777, 0177777
0177400+I_D+I_L, 0170000, 0177777, 0177777,
0177000
};
static const char *opcode[] = {
@ -443,7 +450,7 @@ static const int32 opc_val[] = {
0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP,
0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP,
0050000+I_DOP, 0060000+I_DOP,
0070000+I_RSOP, 0071000+I_RSOP, 0072000+I_RSOP, 0073000+I_RSOP,
0070000+I_SOPR, 0071000+I_SOPR, 0072000+I_SOPR, 0073000+I_SOPR,
0074000+I_RSOP,
0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG,
0076020+I_REG,
@ -684,6 +691,12 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
break;
case I_V_SOPR: /* sopr */
fprintf (of, "%s ", opcode[i]);
wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
fprintf (of, ",%s", rname[srcr]);
break;
case I_V_ASOP: case I_V_ASMD: /* asop, asmd */
fprintf (of, "%s %s,", opcode[i], fname[fac]);
wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE);
@ -994,6 +1007,16 @@ switch (j) { /* case on class */
val[0] = val[0] | spec;
break;
case I_V_SOPR: /* dop, reg */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0)
return SCPE_ARG;
val[0] = val[0] | spec;
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
val[0] = val[0] | (reg << 6);
break;
case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
if ((reg = get_reg (gbuf, fname, 0)) < 0) return SCPE_ARG;

584
PDP11/pdp11_ta.c Normal file
View file

@ -0,0 +1,584 @@
/* pdp11_ta.c: PDP-11 cassette tape simulator
Copyright (c) 2006, Robert M Supnik
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 ATAION OF CONTRATA, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNETAION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ta TA11/TU60 cassette tape
Magnetic tapes are represented as a series of variable records
of the form:
32b byte count
byte 0
byte 1
:
byte n-2
byte n-1
32b byte count
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
Cassette format differs in one very significant way: it has file gaps
rather than file marks. If the controller spaces or reads into a file
gap and then reverses direction, the file gap is not seen again. This
is in contrast to magnetic tapes, where the file mark is a character
sequence and is seen again if direction is reversed.
*/
#include "pdp11_defs.h"
#include "sim_tape.h"
#define TA_NUMDR 2 /* #drives */
#define FNC u3 /* unit function */
#define UST u4 /* unit status */
#define TA_SIZE 93000 /* chars/tape */
#define TA_MAXFR (TA_SIZE) /* max record lnt */
/* Control/status - TACS */
#define TACS_ERR (1 << CSR_V_ERR) /* error */
#define TACS_CRC 0040000 /* CRC */
#define TACS_BEOT 0020000 /* BOT/EOT */
#define TACS_WLK 0010000 /* write lock */
#define TACS_EOF 0004000 /* end file */
#define TACS_TIM 0002000 /* timing */
#define TACS_EMP 0001000 /* empty */
#define TACS_V_UNIT 8 /* unit */
#define TACS_M_UNIT (TA_NUMDR - 1)
#define TACS_UNIT (TACS_M_UNIT << TACS_V_UNIT)
#define TACS_TR (1 << CSR_V_DONE) /* transfer req */
#define TACS_IE (1 << CSR_V_IE) /* interrupt enable */
#define TACS_RDY 0000040 /* ready */
#define TACS_ILBS 0000020 /* start CRC */
#define TACS_V_FNC 1 /* function */
#define TACS_M_FNC 07
#define TACS_WFG 00
#define TACS_WRITE 01
#define TACS_READ 02
#define TACS_SRF 03
#define TACS_SRB 04
#define TACS_SFF 05
#define TACS_SFB 06
#define TACS_REW 07
#define TACS_2ND 010
#define TACS_3RD 030
#define TACS_FNC (TACS_M_FNC << TACS_V_FNC)
#define TACS_GO (1 << CSR_V_GO) /* go */
#define TACS_W (TACS_UNIT|TACS_IE|TACS_ILBS|TACS_FNC)
#define TACS_XFRERR (TACS_ERR|TACS_CRC|TACS_WLK|TACS_EOF|TACS_TIM)
#define GET_UNIT(x) (((x) >> TACS_V_UNIT) & TACS_M_UNIT)
#define GET_FNC(x) (((x) >> TACS_V_FNC) & TACS_M_FNC)
/* Function code flags */
#define OP_WRI 01 /* op is a write */
#define OP_REV 02 /* op is rev motion */
#define OP_FWD 04 /* op is fwd motion */
/* Unit status flags */
#define UST_REV (OP_REV) /* last op was rev */
#define UST_GAP 01 /* last op hit gap */
extern int32 int_req[IPL_HLVL];
extern FILE *sim_deb;
uint32 ta_cs = 0; /* control/status */
uint32 ta_idb = 0; /* input data buf */
uint32 ta_odb = 0; /* output data buf */
uint32 ta_write = 0; /* TU60 write flag */
uint32 ta_bptr = 0; /* buf ptr */
uint32 ta_blnt = 0; /* buf length */
int32 ta_stime = 1000; /* start time */
int32 ta_ctime = 100; /* char latency */
uint32 ta_stopioe = 1; /* stop on error */
uint8 *ta_xb = NULL; /* transfer buffer */
static uint8 ta_fnc_tab[TACS_M_FNC + 1] = {
OP_WRI|OP_FWD, OP_WRI|OP_FWD, OP_FWD, OP_REV,
OP_REV , OP_FWD, OP_FWD, 0
};
DEVICE ta_dev;
t_stat ta_rd (int32 *data, int32 PA, int32 access);
t_stat ta_wr (int32 data, int32 PA, int32 access);
t_stat ta_svc (UNIT *uptr);
t_stat ta_reset (DEVICE *dptr);
t_stat ta_attach (UNIT *uptr, char *cptr);
t_stat ta_detach (UNIT *uptr);
void ta_go (void);
t_stat ta_map_err (UNIT *uptr, t_stat st);
UNIT *ta_busy (void);
void ta_set_tr (void);
uint32 ta_updsta (UNIT *uptr);
uint32 ta_crc (uint8 *buf, uint32 cnt);
/* TA data structures
ta_dev TA device descriptor
ta_unit TA unit list
ta_reg TA register list
ta_mod TA modifier list
*/
DIB ta_dib = {
IOBA_TA, IOLN_TA, &ta_rd, &ta_wr,
1, IVCL (TA), VEC_TA, { NULL }
};
UNIT ta_unit[] = {
{ UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) },
{ UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) },
};
REG ta_reg[] = {
{ ORDATA (TACS, ta_cs, 16) },
{ ORDATA (TAIDB, ta_idb, 8) },
{ ORDATA (TAODB, ta_odb, 8) },
{ FLDATA (WRITE, ta_write, 0) },
{ FLDATA (INT, IREQ (TA), INT_V_TA) },
{ FLDATA (ERR, ta_cs, CSR_V_ERR) },
{ FLDATA (TR, ta_cs, CSR_V_DONE) },
{ FLDATA (IE, ta_cs, CSR_V_IE) },
{ DRDATA (BPTR, ta_bptr, 17) },
{ DRDATA (BLNT, ta_blnt, 17) },
{ DRDATA (STIME, ta_stime, 24), PV_LEFT + REG_NZ },
{ DRDATA (CTIME, ta_ctime, 24), PV_LEFT + REG_NZ },
{ FLDATA (STOP_IOE, ta_stopioe, 0) },
{ URDATA (UFNC, ta_unit[0].FNC, 8, 5, 0, TA_NUMDR, 0), REG_HRO },
{ URDATA (UST, ta_unit[0].UST, 8, 2, 0, TA_NUMDR, 0), REG_HRO },
{ URDATA (POS, ta_unit[0].pos, 10, T_ADDR_W, 0,
TA_NUMDR, PV_LEFT | REG_RO) },
{ ORDATA (DEVADDR, ta_dib.ba, 32), REG_HRO },
{ ORDATA (DEVVEC, ta_dib.vec, 16), REG_HRO },
{ NULL }
};
MTAB ta_mod[] = {
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
// { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
// &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XTD|MTAB_VUN, 0, "CAPACITY", NULL,
NULL, &sim_tape_show_capac, NULL },
{ MTAB_XTD|MTAB_VDV, IOLN_TA, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
{ 0 }
};
DEVICE ta_dev = {
"TA", ta_unit, ta_reg, ta_mod,
TA_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &ta_reset,
NULL, &ta_attach, &ta_detach,
&ta_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG
};
/* I/O dispatch routines, I/O addresses 17777500 - 17777503
17777500 TACS read/write
17777502 TADB read/write
*/
t_stat ta_rd (int32 *data, int32 PA, int32 access)
{
switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TACSR */
*data = ta_updsta (NULL); /* update status */
break;
case 1: /* TADB */
*data = ta_idb; /* return byte */
ta_cs &= ~TACS_TR; /* clear tra req */
ta_updsta (NULL);
break;
}
return SCPE_OK;
}
t_stat ta_wr (int32 data, int32 PA, int32 access)
{
switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TACS */
if (access == WRITEB) data = (PA & 1)? /* byte write? */
(ta_cs & 0377) | (data << 8): /* merge old */
(ta_cs & ~0377) | data;
ta_cs = (ta_cs & ~TACS_W) | (data & TACS_W); /* merge new */
if ((data & CSR_GO) && !ta_busy ()) /* go, not busy? */
ta_go (); /* start operation */
if (ta_cs & TACS_ILBS) ta_cs &= ~TACS_TR; /* ILBS inhibits TR */
break;
case 1: /* TADB */
if (PA & 1) break; /* ignore odd byte */
ta_odb = data; /* return byte */
ta_cs &= ~TACS_TR; /* clear tra req */
break;
} /* end switch */
ta_updsta (NULL); /* update status */
return SCPE_OK;
}
/* Start a new operation - cassette is not busy */
void ta_go (void)
{
UNIT *uptr = ta_dev.units + GET_UNIT (ta_cs);
uint32 fnc = GET_FNC (ta_cs);
uint32 flg = ta_fnc_tab[fnc];
uint32 old_ust = uptr->UST;
if (DEBUG_PRS (ta_dev)) fprintf (sim_deb,
">>TA start: op=%o, old_sta = %o, pos=%d\n",
fnc, uptr->UST, uptr->pos);
ta_cs &= ~(TACS_XFRERR|TACS_EMP|TACS_TR|TACS_RDY); /* clr err, tr, rdy */
ta_bptr = 0; /* init buffer */
ta_blnt = 0;
if ((uptr->flags & UNIT_ATT) == 0) {
ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY;
return;
}
if (flg & OP_WRI) { /* write op? */
if (sim_tape_wrp (uptr)) { /* locked? */
ta_cs |= TACS_ERR|TACS_WLK|TACS_RDY; /* don't start */
return;
}
ta_odb = 0;
ta_write = 1;
}
else {
ta_idb = 0;
ta_write = 0;
}
ta_cs &= ~TACS_BEOT; /* tape in motion */
uptr->FNC = fnc; /* save function */
if ((fnc != TACS_REW) && !(flg & OP_WRI)) { /* read cmd? */
uptr->UST = flg & UST_REV; /* save direction */
if ((old_ust ^ uptr->UST) == (UST_REV|UST_GAP)) { /* reverse in gap? */
t_mtrlnt t; /* skip file mark */
if (uptr->UST) sim_tape_rdrecr (uptr, ta_xb, &t, TA_MAXFR);
else sim_tape_rdrecf (uptr, ta_xb, &t, TA_MAXFR);
if (DEBUG_PRS (ta_dev)) fprintf (sim_deb,
">>TA skip gap: op=%o, old_sta = %o, pos=%d\n",
fnc, uptr->UST, uptr->pos);
}
}
else uptr->UST = 0;
sim_activate (uptr, ta_stime); /* schedule op */
return;
}
/* Unit service */
t_stat ta_svc (UNIT *uptr)
{
uint32 i, crc;
uint32 flg = ta_fnc_tab[uptr->FNC & TACS_M_FNC];
t_mtrlnt tbc;
t_stat st, r;
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY;
ta_updsta (uptr); /* update status */
return (ta_stopioe? SCPE_UNATT: SCPE_OK);
}
if (((flg & OP_FWD) && sim_tape_eot (uptr)) || /* illegal motion? */
((flg & OP_REV) && sim_tape_bot (uptr))) {
ta_cs |= TACS_ERR|TACS_BEOT|TACS_RDY; /* error */
ta_updsta (uptr);
return SCPE_OK;
}
r = SCPE_OK;
switch (uptr->FNC) { /* case on function */
case TACS_READ: /* read start */
st = sim_tape_rdrecf (uptr, ta_xb, &ta_blnt, TA_MAXFR); /* get rec */
if (st == MTSE_RECE) ta_cs |= TACS_ERR|TACS_CRC; /* rec in err? */
else if (st != MTSE_OK) { /* other error? */
r = ta_map_err (uptr, st); /* map error */
break;
}
crc = ta_crc (ta_xb, ta_blnt); /* calculate CRC */
ta_xb[ta_blnt++] = (crc >> 8) & 0377; /* append to buffer */
ta_xb[ta_blnt++] = crc & 0377;
uptr->FNC |= TACS_2ND; /* next state */
sim_activate (uptr, ta_ctime); /* sched next char */
return SCPE_OK;
case TACS_READ|TACS_2ND: /* read char */
if (ta_bptr < ta_blnt) /* more chars? */
ta_idb = ta_xb[ta_bptr++];
else { /* no */
ta_idb = 0;
ta_cs |= TACS_ERR|TACS_CRC; /* overrun */
break; /* tape stops */
}
if (ta_cs & TACS_ILBS) { /* CRC seq? */
uptr->FNC |= TACS_3RD; /* next state */
sim_activate (uptr, ta_stime); /* sched CRC chk */
}
else {
ta_set_tr (); /* set tra req */
sim_activate (uptr, ta_ctime); /* sched next char */
}
return SCPE_OK;
case TACS_READ|TACS_3RD: /* second read CRC */
if (ta_bptr != ta_blnt) { /* partial read? */
crc = ta_crc (ta_xb, ta_bptr + 2); /* actual CRC */
if (crc != 0) ta_cs |= TACS_ERR|TACS_CRC; /* must be zero */
}
break; /* read done */
case TACS_WRITE: /* write start */
for (i = 0; i < TA_MAXFR; i++) ta_xb[i] = 0; /* clear buffer */
ta_set_tr (); /* set tra req */
uptr->FNC |= TACS_2ND; /* next state */
sim_activate (uptr, ta_ctime); /* sched next char */
return SCPE_OK;
case TACS_WRITE|TACS_2ND: /* write char */
if (ta_cs & TACS_ILBS) { /* CRC seq? */
uptr->FNC |= TACS_3RD; /* next state */
sim_activate (uptr, ta_stime); /* sched wri done */
}
else {
if ((ta_bptr < TA_MAXFR) && /* room in buf? */
((uptr->pos + ta_bptr) < uptr->capac)) /* room on tape? */
ta_xb[ta_bptr++] = ta_odb; /* store char */
ta_set_tr (); /* set tra req */
sim_activate (uptr, ta_ctime); /* sched next char */
}
return SCPE_OK;
case TACS_WRITE|TACS_3RD: /* write CRC */
if (ta_bptr) { /* anything to write? */
if (st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)) /* write, err? */
r = ta_map_err (uptr, st); /* map error */
}
break; /* op done */
case TACS_WFG: /* write file gap */
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
r = ta_map_err (uptr, st); /* map error */
break;
case TACS_REW: /* rewind */
sim_tape_rewind (uptr);
ta_cs |= TACS_BEOT; /* bot, no error */
break;
case TACS_SRB: /* space rev blk */
if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */
r = ta_map_err (uptr, st); /* map error */
break;
case TACS_SRF: /* space rev file */
while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
if (st == MTSE_TMK) /* if tape mark, */
ta_cs |= TACS_EOF; /* set EOF, no err */
else r = ta_map_err (uptr, st); /* else map error */
break;
case TACS_SFB: /* space fwd blk */
if (st = sim_tape_sprecf (uptr, &tbc)) /* space rev, err? */
r = ta_map_err (uptr, st); /* map error */
ta_cs |= TACS_CRC; /* CRC sets, no err */
break;
case TACS_SFF: /* space fwd file */
while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
if (st == MTSE_TMK) /* if tape mark, */
ta_cs |= TACS_EOF; /* set EOF, no err */
else r = ta_map_err (uptr, st); /* else map error */
break;
default: /* never get here! */
return SCPE_IERR;
} /* end case */
ta_cs |= TACS_RDY; /* set ready */
ta_updsta (uptr); /* update status */
if (DEBUG_PRS (ta_dev)) fprintf (sim_deb,
">>TA done: op=%o, status = %o, pos=%d\n",
uptr->FNC, ta_cs, uptr->pos);
return r;
}
/* Update controller status */
uint32 ta_updsta (UNIT *uptr)
{
if (uptr == NULL) { /* unit specified? */
if ((uptr = ta_busy ()) == NULL) /* use busy */
uptr = ta_dev.units + GET_UNIT (ta_cs); /* use sel unit */
}
else if (ta_cs & TACS_EOF) uptr->UST |= UST_GAP; /* save EOF */
if (uptr->flags & UNIT_ATT) ta_cs &= ~TACS_EMP; /* attached? */
else ta_cs |= TACS_EMP|TACS_RDY; /* no, empty, ready */
if ((ta_cs & TACS_IE) && /* int enabled? */
(ta_cs & (TACS_TR|TACS_RDY))) /* req or ready? */
SET_INT (TA); /* set int req */
else CLR_INT (TA); /* no, clr int req */
return ta_cs;
}
/* Set transfer request */
void ta_set_tr (void)
{
if (ta_cs & TACS_TR) ta_cs |= (TACS_ERR|TACS_TIM); /* flag still set? */
else ta_cs |= TACS_TR; /* set xfr req */
if (ta_cs & TACS_IE) SET_INT (TA); /* if ie, int req */
return;
}
/* Test if controller busy */
UNIT *ta_busy (void)
{
uint32 u;
UNIT *uptr;
for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */
uptr = ta_dev.units + u;
if (sim_is_active (uptr)) return uptr;
}
return NULL;
}
/* Calculate CRC on buffer */
uint32 ta_crc (uint8 *buf, uint32 cnt)
{
uint32 crc, i, j;
crc = 0;
for (i = 0; i < cnt; i++) {
crc = crc ^ (((uint32) buf[i]) << 8);
for (j = 0; j < 8; j++) {
if (crc & 1) crc = (crc >> 1) ^ 0xA001;
else crc = crc >> 1;
}
}
return crc;
}
/* Map error status */
t_stat ta_map_err (UNIT *uptr, t_stat st)
{
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* unattached */
ta_cs |= TACS_ERR|TACS_CRC;
case MTSE_OK: /* no error */
return SCPE_IERR; /* never get here! */
case MTSE_TMK: /* end of file */
ta_cs |= TACS_ERR|TACS_EOF;
break;
case MTSE_IOERR: /* IO error */
ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */
if (ta_stopioe) return SCPE_IOERR;
break;
case MTSE_INVRL: /* invalid rec lnt */
ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */
return SCPE_MTRLNT;
case MTSE_RECE: /* record in error */
case MTSE_EOM: /* end of medium */
ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */
break;
case MTSE_BOT: /* reverse into BOT */
ta_cs |= TACS_ERR|TACS_BEOT; /* set bot */
break;
case MTSE_WRP: /* write protect */
ta_cs |= TACS_ERR|TACS_WLK; /* set wlk err */
break;
}
return SCPE_OK;
}
/* Reset routine */
t_stat ta_reset (DEVICE *dptr)
{
uint32 u;
UNIT *uptr;
ta_cs = 0;
ta_idb = 0;
ta_odb = 0;
ta_write = 0;
ta_bptr = 0;
ta_blnt = 0;
CLR_INT (TA); /* clear interrupt */
for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */
uptr = ta_dev.units + u;
sim_cancel (uptr); /* cancel activity */
sim_tape_reset (uptr); /* reset tape */
}
if (ta_xb == NULL) ta_xb = (uint8 *) calloc (TA_MAXFR + 2, sizeof (uint8));
if (ta_xb == NULL) return SCPE_MEM;
return SCPE_OK;
}
/* Attach routine */
t_stat ta_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK) return r;
ta_updsta (NULL);
uptr->UST = 0;
return r;
}
/* Detach routine */
t_stat ta_detach (UNIT* uptr)
{
t_stat r;
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check attached */
r = sim_tape_detach (uptr);
ta_updsta (NULL);
uptr->UST = 0;
return r;
}

Some files were not shown because too many files have changed in this diff Show more