Notes For V3.0-1

RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially
debugged.  Do NOT enable these features for normal operations.

1. New Features in 3.0-1

1.1 PDP-1

- Added block loader format support to LOAD.
- Changed BOOT PTR to allow loading of all of the first bank of memory.

1.2 PDP-18b Family

- Added PDP-4 EAE support.
- Added PDP-15 FP15 support.
- Added PDP-15 XVM support.
- Added PDP-15 "re-entrancy ECO".
- Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR.

2. Bugs Fixed in 3.0-1

2.1 PDP-11/VAX

- Fixed bug in user disk size (found by Chaskiel M Grundman).

2.2 PDP-1

- Updated CPU, line printer, standard devices to detect indefinite I/O wait.
- Fixed incorrect logical, missing activate, break in drum simulator.
- Fixed bugs in instruction decoding, overprinting for line printer.

2.3 PDP-10

- Fixed bug in RP read header.

2.4 PDP-18b Family

- Fixed bug in PDP-4 line printer overprinting.
- Fixed bug in PDP-15 memory protect/skip interaction.
- Fixed bug in RF set size routine.
- Increased PTP TIME for PDP-15 operating systems.

2.5 PDP-8

- Fixed bug in DF, RF set size routine.

2.6 Nova

- Fixed bug in DSK set size routine.

2.7 1401

- Revised fetch to model hardware more closely.

2.8 Ibm1130

- Fixed bugs found by APL 1130.

2.9 Altairz80

- Fixed bug in real-time clock on Windows host.

2.10 HP2100

-- Fixed DR drum sizes.
-- Fixed DR variable capacity interaction with SAVE/RESTORE.

3. New Features in 3.0 vs prior releases

3.1 SCP and Libraries

- Added ASSIGN/DEASSIGN (logical name) commands.
- Changed RESTORE to unconditionally detach files.
- Added E11 and TPC format support to magtape library.
- Fixed bug in SHOW CONNECTIONS.
- Added USE_ADDR64 support

3.2 All magtapes

- Magtapes support SIMH format, E11 format, and TPC format (read only).
- SET <tape_unit> FORMAT=format sets the specified tape unit's format.
- SHOW <tape_unit> FORMAT displays the specified tape unit's format.
- Tape format can also be set as part of the ATTACH command, using
  the -F switch.

3.3 VAX

- VAX can be compiled without USE_INT64.
- If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support
  files > 2GB.
- VAX ROM has speed control (SET ROM DELAY/NODELAY).

4. Bugs Fixed in 3.0 vs prior releases

4.1 VAX

- Fixed CVTfi bug: integer overflow not set if exponent out of range
- Fixed EMODx bugs:
  o First and second operands reversed
  o Separated fraction received wrong exponent
  o Overflow calculation on separated integer incorrect
  o Fraction not set to zero if exponent out of range
- Fixed interval timer and ROM access to pass power-up self-test even on very
  fast host processors (fixes from Mark Pizzolato).

4.2 1401

- Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS.
- Fixed MCE bug, BS off by 1 if zero suppress.
- Fixed chaining bug, D lost if return to SCP.
- Fixed H branch, branch occurs after continue.
- Added check for invalid 8 character MCW, LCA.
- Fixed magtape load-mode end of record response.

4.3 Nova

- Fixed DSK variable size interaction with restore.

4.4 PDP-1

- Fixed DT variable size interaction with restore.

4.5 PDP-11

- Fixed DT variable size interaction with restore.
- Fixed bug in MMR1 update (found by Tim Stark).
- Added XQ features and fixed bugs:
  o Corrected XQ interrupts on IE state transition (code by Tom Evans).
  o Added XQ interrupt clear on soft reset.
  o Removed XQ interrupt when setting XL or RL (multiple people).
  o Added SET/SHOW XQ STATS.
  o Added SHOW XQ FILTERS.
  o Added ability to split received packet into multiple buffers.
  o Added explicit runt and giant packet processing.

4.6 PDP-18B

- Fixed DT, RF variable size interaction with restore.
- Fixed MT bug in MTTR.

4.7 PDP-8

- Fixed DT, DF, RF, RX variable size interaction with restore.
- Fixed MT bug in SKTR.

4.8 HP2100

- Fixed bug in DP (13210A controller only), DQ read status.
- Fixed bug in DP, DQ seek complete.

4.9 GRI

- Fixed bug in SC queue pointer management.
This commit is contained in:
Bob Supnik 2003-07-31 16:17:00 -07:00 committed by Mark Pizzolato
parent 4ffd3be790
commit f9564b81b9
74 changed files with 6938 additions and 2812 deletions

View file

@ -1,11 +1,75 @@
Notes For V3.0-0
Notes For V3.0-1
Because some key files have changed, V3.0 should be unzipped to a
clean directory.
RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially
debugged. Do NOT enable these features for normal operations.
1. New Features in 3.0-0
1. New Features in 3.0-1
1.1 SCP and Libraries
1.1 PDP-1
- Added block loader format support to LOAD.
- Changed BOOT PTR to allow loading of all of the first bank of memory.
1.2 PDP-18b Family
- Added PDP-4 EAE support.
- Added PDP-15 FP15 support.
- Added PDP-15 XVM support.
- Added PDP-15 "re-entrancy ECO".
- Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR.
2. Bugs Fixed in 3.0-1
2.1 PDP-11/VAX
- Fixed bug in user disk size (found by Chaskiel M Grundman).
2.2 PDP-1
- Updated CPU, line printer, standard devices to detect indefinite I/O wait.
- Fixed incorrect logical, missing activate, break in drum simulator.
- Fixed bugs in instruction decoding, overprinting for line printer.
2.3 PDP-10
- Fixed bug in RP read header.
2.4 PDP-18b Family
- Fixed bug in PDP-4 line printer overprinting.
- Fixed bug in PDP-15 memory protect/skip interaction.
- Fixed bug in RF set size routine.
- Increased PTP TIME for PDP-15 operating systems.
2.5 PDP-8
- Fixed bug in DF, RF set size routine.
2.6 Nova
- Fixed bug in DSK set size routine.
2.7 1401
- Revised fetch to model hardware more closely.
2.8 Ibm1130
- Fixed bugs found by APL 1130.
2.9 Altairz80
- Fixed bug in real-time clock on Windows host.
2.10 HP2100
-- Fixed DR drum sizes.
-- Fixed DR variable capacity interaction with SAVE/RESTORE.
3. New Features in 3.0 vs prior releases
3.1 SCP and Libraries
- Added ASSIGN/DEASSIGN (logical name) commands.
- Changed RESTORE to unconditionally detach files.
@ -13,7 +77,7 @@ clean directory.
- Fixed bug in SHOW CONNECTIONS.
- Added USE_ADDR64 support
1.2 All magtapes
3.2 All magtapes
- Magtapes support SIMH format, E11 format, and TPC format (read only).
- SET <tape_unit> FORMAT=format sets the specified tape unit's format.
@ -21,16 +85,16 @@ clean directory.
- Tape format can also be set as part of the ATTACH command, using
the -F switch.
1.3 VAX
3.3 VAX
- VAX can be compiled without USE_INT64.
- If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support
files > 2GB.
- VAX ROM has speed control (SET ROM DELAY/NODELAY).
2. Bugs Fixed in 3.01-0
4. Bugs Fixed in 3.0 vs prior releases
2.1 VAX
4.1 VAX
- Fixed CVTfi bug: integer overflow not set if exponent out of range
- Fixed EMODx bugs:
@ -41,7 +105,7 @@ clean directory.
- Fixed interval timer and ROM access to pass power-up self-test even on very
fast host processors (fixes from Mark Pizzolato).
2.2 1401
4.2 1401
- Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS.
- Fixed MCE bug, BS off by 1 if zero suppress.
@ -50,15 +114,15 @@ clean directory.
- Added check for invalid 8 character MCW, LCA.
- Fixed magtape load-mode end of record response.
2.3 Nova
4.3 Nova
- Fixed DSK variable size interaction with restore.
2.4 PDP-1
4.4 PDP-1
- Fixed DT variable size interaction with restore.
2.5 PDP-11
4.5 PDP-11
- Fixed DT variable size interaction with restore.
- Fixed bug in MMR1 update (found by Tim Stark).
@ -71,40 +135,21 @@ clean directory.
o Added ability to split received packet into multiple buffers.
o Added explicit runt and giant packet processing.
2.6 PDP-18B
4.6 PDP-18B
- Fixed DT, RF variable size interaction with restore.
- Fixed MT bug in MTTR.
2.7 PDP-8
4.7 PDP-8
- Fixed DT, DF, RF, RX variable size interaction with restore.
- Fixed MT bug in SKTR.
2.8 HP2100
4.8 HP2100
- Fixed bug in DP (13210A controller only), DQ read status.
- Fixed bug in DP, DQ seek complete.
2.9 GRI
4.9 GRI
- Fixed bug in SC queue pointer management.
3. New Features in 3.0 vs prior releases
N/A
4. Bugs Fixed in 3.0 vs prior releases
N/A
5. General Notes
WARNING: The RESTORE command has changed. RESTORE will now
detach an attached file on a unit, if that unit did not have
an attached file in the saved configuration. This is required
to assure that the unit flags and the file state are consistent.
WARNING: The compilation scheme for the PDP-10, PDP-11, and VAX
has changed. Use one of the supplied build files, or read the
documentation carefully, before compiling any of these simulators.

View file

@ -1,6 +1,6 @@
/* altairz80_defs.h: MITS Altair simulator definitions
Copyright (c) 2002, Peter Schorn
Copyright (c) 2002-2003, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -126,13 +126,13 @@ extern UNIT cpu_unit;
/* SIMH pseudo device status registers */
/* ZSDOS clock definitions */
static int32 ClockZSDOSDelta = 0; /* delta between real clock and Altair clock */
static time_t ClockZSDOSDelta = 0; /* delta between real clock and Altair clock */
static int32 setClockZSDOSPos = 0; /* determines state for receiving address of parameter block */
static int32 setClockZSDOSAdr = 0; /* address in M of 6 byte parameter block for setting time */
static int32 getClockZSDOSPos = 0; /* determines state for sending clock information */
/* CPM3 clock definitions */
static int32 ClockCPM3Delta = 0; /* delta between real clock and Altair clock */
static time_t ClockCPM3Delta = 0; /* delta between real clock and Altair clock */
static int32 setClockCPM3Pos = 0; /* determines state for receiving address of parameter block */
static int32 setClockCPM3Adr = 0; /* address in M of 5 byte parameter block for setting time */
static int32 getClockCPM3Pos = 0; /* determines state for sending clock information */
@ -658,11 +658,12 @@ enum simhPseudoDeviceCommands { /* do not change order or remove commands, add o
#define cpmCommandLineLength 128
#define splimit 10 /* stack depth of timer stack */
static uint32 markTime[splimit]; /* timer stack */
static struct tm *currentTime = NULL;
static struct tm currentTime;
static int32 currentTimeValid = FALSE;
static char version[] = "SIMH002";
static t_stat simh_dev_reset(DEVICE *dptr) {
currentTime = NULL;
currentTimeValid = FALSE;
ClockZSDOSDelta = 0;
setClockZSDOSPos = 0;
getClockZSDOSPos = 0;
@ -783,7 +784,7 @@ static void setClockCPM3(void) {
}
static int32 simh_in(const int32 port) {
int32 result;
int32 result = 0;
switch(lastCommand) {
case attachPTRCmd:
case attachPTPCmd:
@ -791,31 +792,31 @@ static int32 simh_in(const int32 port) {
lastCommand = 0;
break;
case getClockZSDOSCmd:
if (currentTime) {
if (currentTimeValid) {
switch(getClockZSDOSPos) {
case 0:
result = toBCD(currentTime -> tm_year > 99 ?
currentTime -> tm_year - 100 : currentTime -> tm_year);
result = toBCD(currentTime.tm_year > 99 ?
currentTime.tm_year - 100 : currentTime.tm_year);
getClockZSDOSPos = 1;
break;
case 1:
result = toBCD(currentTime -> tm_mon + 1);
result = toBCD(currentTime.tm_mon + 1);
getClockZSDOSPos = 2;
break;
case 2:
result = toBCD(currentTime -> tm_mday);
result = toBCD(currentTime.tm_mday);
getClockZSDOSPos = 3;
break;
case 3:
result = toBCD(currentTime -> tm_hour);
result = toBCD(currentTime.tm_hour);
getClockZSDOSPos = 4;
break;
case 4:
result = toBCD(currentTime -> tm_min);
result = toBCD(currentTime.tm_min);
getClockZSDOSPos = 5;
break;
case 5:
result = toBCD(currentTime -> tm_sec);
result = toBCD(currentTime.tm_sec);
getClockZSDOSPos = lastCommand = 0;
break;
}
@ -825,7 +826,7 @@ static int32 simh_in(const int32 port) {
}
break;
case getClockCPM3Cmd:
if (currentTime) {
if (currentTimeValid) {
switch(getClockCPM3Pos) {
case 0:
result = daysCPM3SinceOrg & 0xff;
@ -836,15 +837,15 @@ static int32 simh_in(const int32 port) {
getClockCPM3Pos = 2;
break;
case 2:
result = toBCD(currentTime -> tm_hour);
result = toBCD(currentTime.tm_hour);
getClockCPM3Pos = 3;
break;
case 3:
result = toBCD(currentTime -> tm_min);
result = toBCD(currentTime.tm_min);
getClockCPM3Pos = 4;
break;
case 4:
result = toBCD(currentTime -> tm_sec);
result = toBCD(currentTime.tm_sec);
getClockCPM3Pos = lastCommand = 0;
break;
}
@ -1012,7 +1013,8 @@ static int32 simh_out(const int32 port, const int32 data) {
case getClockZSDOSCmd:
time(&now);
now += ClockZSDOSDelta;
currentTime = localtime(&now);
currentTime = *localtime(&now);
currentTimeValid = TRUE;
getClockZSDOSPos = 0;
break;
case setClockZSDOSCmd:
@ -1021,7 +1023,8 @@ static int32 simh_out(const int32 port, const int32 data) {
case getClockCPM3Cmd:
time(&now);
now += ClockCPM3Delta;
currentTime = localtime(&now);
currentTime = *localtime(&now);
currentTimeValid = TRUE;
daysCPM3SinceOrg = (now - mkCPM3Origin()) / secondsPerDay;
getClockCPM3Pos = 0;
break;

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: H316 Simulator Usage
Date: 20-Apr-2003
Date: 15-Jul-2003
COPYRIGHT NOTICE
@ -51,7 +51,7 @@ sim/h316/ h316_defs.h
h316_cpu.c
h316_lp.c
h316_stddev.c
h316_cpu.c
h316_sys.c
2. H316/H516 Features
@ -230,7 +230,7 @@ The clock implements these registers:
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.2.5 316/5116 Line Printer (LPT)
2.2.5 316/516 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
@ -294,9 +294,8 @@ where * signifies indirect, C a current sector reference, Z a sector zero
reference, and 1 indexed. The address is an octal number in the range 0 -
077777; if C or Z is specified, the address is a page offset in the range
0 - 0777. Normally, C is not needed; the simulator figures out from the
address what mode to use. However, when referencing memory outside the CPU
(eg, disks), there is no valid PC, and C must be used to specify current
sector addressing.
address what mode to use. However, when referencing memory outside the CPU,
there is no valid PC, and C must be used to specify current sector addressing.
I/O instructions have the format

View file

@ -1,14 +1,14 @@
To: Users
From: Bob Supnik
Subj: HP2100 Simulator Usage
Date: 15-Nov-2002
Date: 15-Jul-2003
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik
Copyright (c) 1993-2002, Robert M Supnik
Copyright (c) 1993-2003, 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"),
@ -39,10 +39,12 @@ This memorandum documents the HP 2100 simulator.
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tape.h
sim_tmxr.h
scp.c
scp_tty.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/hp2100/ hp2100_defs.h
@ -563,7 +565,6 @@ Both IPLI and IPLO implement these registers:
TIME 24 polling interval for input
STOP_IOE 1 stop on I/O error
2.5 12557A Disk Controller (DPC, DPD) with 2781 Drives
13210A Disk Controller (DPC, DPD) with 7900 Drives

View file

@ -35,6 +35,8 @@
The drum control channel does not have any of the traditional flip-flops.
27-Jul-03 RMS Fixed drum sizes
Fixed variable capacity interaction with SAVE/RESTORE
10-Nov-02 RMS Added BOOT command
*/
@ -48,8 +50,21 @@
#define DR_DNUMSC 32 /* drum sec/track */
#define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)
#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */
#define UNIT_V_DR (UNIT_V_UF) /* disk vs drum */
#define UNIT_DR (1 << UNIT_V_DR)
#define UNIT_V_SZ (UNIT_V_UF) /* disk vs drum */
#define UNIT_M_SZ 017 /* size */
#define UNIT_SZ (UNIT_M_SZ << UNIT_V_SZ)
#define UNIT_DR (1 << UNIT_V_SZ) /* low order bit */
#define SZ_180K 000 /* disks */
#define SZ_360K 002
#define SZ_720K 004
#define SZ_1024K 001 /* drums: default size */
#define SZ_1536K 003
#define SZ_384K 005
#define SZ_512K 007
#define SZ_640K 011
#define SZ_768K 013
#define SZ_896K 015
#define DR_GETSZ(x) (((x) >> UNIT_V_SZ) & UNIT_M_SZ)
/* Command word */
@ -105,11 +120,16 @@ int32 drd_ptr = 0; /* sector pointer */
int32 dr_stopioe = 1; /* stop on error */
int32 dr_time = 10; /* time per word */
static int32 sz_tab[16] = {
184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288,
0, 655360, 0, 786432, 0, 917504, 0, 0 };
DEVICE drd_dev, drc_dev;
int32 drdio (int32 inst, int32 IR, int32 dat);
int32 drcio (int32 inst, int32 IR, int32 dat);
t_stat drc_svc (UNIT *uptr);
t_stat drc_reset (DEVICE *dptr);
t_stat drc_attach (UNIT *uptr, char *cptr);
t_stat drc_boot (int32 unitno, DEVICE *dptr);
int32 dr_incda (int32 trk, int32 sec, int32 ptr);
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
@ -175,21 +195,22 @@ REG drc_reg[] = {
{ DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, dr_stopioe, 0) },
{ ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO },
{ DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO },
{ NULL } };
MTAB drc_mod[] = {
{ UNIT_DR, 0, "disk", NULL, NULL },
{ UNIT_DR, UNIT_DR, "drum", NULL, NULL },
{ UNIT_DR, 184320, NULL, "180K", &dr_set_size },
{ UNIT_DR, 368640, NULL, "360K", &dr_set_size },
{ UNIT_DR, 737280, NULL, "720K", &dr_set_size },
{ UNIT_DR, 368640+1, NULL, "384K", &dr_set_size },
{ UNIT_DR, 524280+1, NULL, "512K", &dr_set_size },
{ UNIT_DR, 655360+1, NULL, "640K", &dr_set_size },
{ UNIT_DR, 786432+1, NULL, "768K", &dr_set_size },
{ UNIT_DR, 917504+1, NULL, "896K", &dr_set_size },
{ UNIT_DR, 1048576+1, NULL, "1024K", &dr_set_size },
{ UNIT_DR, 1572864+1, NULL, "1536K", &dr_set_size },
{ UNIT_SZ, (SZ_180K << UNIT_V_SZ), NULL, "180K", &dr_set_size },
{ UNIT_SZ, (SZ_360K << UNIT_V_SZ), NULL, "360K", &dr_set_size },
{ UNIT_SZ, (SZ_720K << UNIT_V_SZ), NULL, "720K", &dr_set_size },
{ UNIT_SZ, (SZ_384K << UNIT_V_SZ), NULL, "384K", &dr_set_size },
{ UNIT_SZ, (SZ_512K << UNIT_V_SZ), NULL, "512K", &dr_set_size },
{ UNIT_SZ, (SZ_640K << UNIT_V_SZ), NULL, "640K", &dr_set_size },
{ UNIT_SZ, (SZ_768K << UNIT_V_SZ), NULL, "768K", &dr_set_size },
{ UNIT_SZ, (SZ_896K << UNIT_V_SZ), NULL, "896K", &dr_set_size },
{ UNIT_SZ, (SZ_1024K << UNIT_V_SZ), NULL, "1024K", &dr_set_size },
{ UNIT_SZ, (SZ_1536K << UNIT_V_SZ), NULL, "1536K", &dr_set_size },
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &drd_dev },
{ 0 } };
@ -198,7 +219,7 @@ DEVICE drc_dev = {
"DRC", &drc_unit, drc_reg, drc_mod,
1, 8, 21, 1, 8, 16,
NULL, NULL, &drc_reset,
&drc_boot, NULL, NULL,
&drc_boot, &drc_attach, NULL,
&drc_dib, DEV_DISABLE };
/* IOT routines */
@ -336,14 +357,26 @@ sim_cancel (&drc_unit);
return SCPE_OK;
}
/* Attach routine */
t_stat drc_attach (UNIT *uptr, char *cptr)
{
int32 sz = sz_tab[DR_GETSZ (uptr->flags)];
if (sz == 0) return SCPE_IERR;
uptr->capac = sz;
return attach_unit (uptr, cptr);
}
/* Set size routine */
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 sz;
if (val < 0) return SCPE_IERR;
if ((sz = sz_tab[DR_GETSZ (val)]) == 0) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
if (val & 1) uptr->flags = uptr->flags | UNIT_DR;
else uptr->flags = uptr->flags & ~UNIT_DR;
uptr->capac = val & ~1;
uptr->capac = sz;
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* hp2100_fp.c: HP 2100 floating point instructions
Copyright (c) 2003, Robert M. Supnik
Copyright (c) 2002-2003, 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 @@
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.
15-Jul-03 RMS Fixed signed/unsigned warning
21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms
The HP2100 uses a unique binary floating point format:
@ -153,7 +154,7 @@ UnpackFP (&fop1, FPAB); /* unpack A-B */
UnpackFP (&fop2, opnd); /* get op */
if (sub) { /* subtract? */
fop2.fr = FR_NEG (fop2.fr); /* negate frac */
if (fop2.fr == FP_SIGN) { /* -1/2? */
if (fop2.fr == ((uint32) FP_SIGN)) { /* -1/2? */
fop2.fr = fop2.fr >> 1; /* special case */
fop2.exp = fop2.exp + 1; } }
if (fop1.fr == 0) fop1 = fop2; /* op1 = 0? res = op2 */

View file

@ -23,6 +23,9 @@
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.
12-Jul-03 RMS Moved ASCII/BCD tables to included file
Revised fetch to model hardware
Removed length checking in fetch phase
16-Mar-03 RMS Fixed mnemonic, instruction lengths, and reverse
scan length check bug for MCS
Fixed MCE bug, BS off by 1 if zero suppress
@ -114,6 +117,7 @@
*/
#include "i1401_defs.h"
#include "i1401_dat.h"
#define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1)
@ -268,7 +272,7 @@ const int32 op_table[64] = {
L1, /* punch feed */
0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ | MA, /* modify address */
L7 | AREQ | BREQ | MDV, /* multiply */
L1 | L4 | L7 | AREQ | BREQ | MDV, /* multiply */
0, /* illegal */
0, /* illegal */
0, /* illegal */
@ -284,7 +288,7 @@ const int32 op_table[64] = {
L1 | L4 | L7 | AREQ | BREQ, /* move supress zero */
0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ | NOWM, /* set word mark */
L7 | AREQ | BREQ | MDV, /* divide */
L1 | L4 | L7 | AREQ | BREQ | MDV, /* divide */
0, /* illegal */
0, /* illegal */
0, /* illegal */
@ -293,7 +297,7 @@ const int32 op_table[64] = {
L2 | L5, /* select stacker */
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* load */
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* move */
HNOP | L1 | L4 | L7, /* nop */
HNOP | L1 | L2 | L4 | L5 | L7 | L8, /* nop */
0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ | MR, /* move to record */
L1 | L4 | AREQ | MLS, /* 50: store A addr */
@ -315,7 +319,7 @@ const int32 op_table[64] = {
L1 | L4 | L7 | AREQ | MLS, /* 70: store B addr */
0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ, /* zero and add */
HNOP | L1 | L4 | L7, /* halt */
HNOP | L1 | L2 | L4 | L5 | L7 | L8, /* halt */
L1 | L4 | L7 | AREQ | BREQ, /* clear word mark */
0, /* illegal */
0, /* illegal */
@ -362,38 +366,6 @@ const int32 bin_to_bcd[16] = {
const int32 bcd_to_bin[16] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7 };
/* ASCII to BCD conversion */
const char ascii_to_bcd[128] = {
000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */
000, 000, 000, 000, 000, 000, 000, 000,
000, 000, 000, 000, 000, 000, 000, 000,
000, 000, 000, 000, 000, 000, 000, 000,
000, 052, 077, 013, 053, 034, 060, 032, /* 040 - 077 */
017, 074, 054, 037, 033, 040, 073, 021,
012, 001, 002, 003, 004, 005, 006, 007,
010, 011, 015, 056, 076, 035, 016, 072,
014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */
070, 071, 041, 042, 043, 044, 045, 046,
047, 050, 051, 022, 023, 024, 025, 026,
027, 030, 031, 075, 036, 055, 020, 057,
000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */
070, 071, 041, 042, 043, 044, 045, 046,
047, 050, 051, 022, 023, 024, 025, 026,
027, 030, 031, 000, 000, 000, 000, 000 };
/* BCD to ASCII conversion - also the "full" print chain */
char bcd_to_ascii[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '#', '@', ':', '>', '(',
'^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '\'', ',', '%', '=', '\\', '+',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '_',
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '?', '.', ')', '[', '<', '"' };
/* Indicator resets - a 1 marks an indicator that resets when tested */
static const int32 ind_table[64] = {
@ -501,9 +473,30 @@ if (sim_brk_summ && sim_brk_test (IS, SWMASK ('E'))) { /* breakpoint? */
sim_interval = sim_interval - 1;
/* Instruction fetch */
/* Instruction fetch - 1401 fetch works as follows:
if ((M[IS] & WM) == 0) { /* WM under op? */
- Each character fetched enters the B register. This register is not
visible; the variable t represents the B register.
- Except for the first and last cycles, each character fetched enters
the A register. This register is not visible; the variable D represents
the A register, because this is the instruction modifier for 2, 5, and 8
character instructions.
- At the start of the second cycle (first address character), the A-address
register and, for most instructions, the B-address register, are cleared
to blanks. The simulator represents addresses in binary and creates the
effect of blanks (address is bad) if less than three A-address characters
are found. Further, the simulator accumulates only the A-address, and
replicates it to the B-address at the appropriate point.
- At the start of the fifth cycle (fourth address character), the B-address
register is cleared to blanks. Again, the simulator creates the effect of
blanks (address is bad) if less than three B-address characters are found.
The 1401 does explicitly check for valid instruction lengths. Most 2,3,5,6
character instructions will be invalid because the A-address or B-address
(or both) are invalid.
*/
if ((M[IS] & WM) == 0) { /* I-Op: WM under op? */
reason = STOP_NOWM; /* no, error */
break; }
op = M[IS] & CHAR; /* get opcode */
@ -514,25 +507,26 @@ if ((flags == 0) || (flags & ALLOPT & ~cpu_unit.flags)) {
if (op == OP_SAR) BS = AS; /* SAR? save ASTAR */
PP (IS);
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* WM? 1 char inst */
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* I-1: WM? 1 char inst */
D = ioind = t; /* could be D char, % */
AS = hun_table[t]; /* could be A addr */
PP (IS); /* if %xy, BA is set */
if ((t = M[IS]) & WM) { /* WM? 2 char inst */
if ((t = M[IS]) & WM) { /* I-2: WM? 2 char inst */
AS = AS | BA; /* ASTAR bad */
if (!(flags & MLS)) BS = AS;
goto CHECK_LENGTH; }
D = dev = t; /* could be D char, dev */
AS = AS + ten_table[t]; /* build A addr */
dev = t; /* save char as dev */
PP (IS);
if ((t = M[IS]) & WM) { /* WM? 3 char inst */
if ((t = M[IS]) & WM) { /* I-3: WM? 3 char inst */
AS = AS | BA; /* ASTAR bad */
if (!(flags & MLS)) BS = AS;
goto CHECK_LENGTH; }
D = unit = t; /* could be D char, unit */
if (unit == BCD_ZERO) unit = 0; /* convert unit to binary */
AS = AS + one_table[t]; /* finish A addr */
unit = (t == BCD_ZERO)? 0: t; /* save char as unit */
xa = (AS >> V_INDEX) & M_INDEX; /* get index reg */
if (xa && (ioind != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */
AS = AS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] +
@ -541,21 +535,23 @@ if (xa && (ioind != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */
if (!(flags & MLS)) BS = AS; /* not MLS? B = A */
PP (IS);
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* WM? 4 char inst */
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* I-4: WM? 4 char inst */
if ((op == OP_B) && (t == BCD_BLANK)) goto CHECK_LENGTH; /* BR + space? */
D = t; /* could be D char */
BS = hun_table[t]; /* could be B addr */
PP (IS);
if ((t = M[IS]) & WM) { /* WM? 5 char inst */
if ((t = M[IS]) & WM) { /* I-5: WM? 5 char inst */
BS = BS | BA; /* BSTAR bad */
goto CHECK_LENGTH; }
D = t; /* could be D char */
BS = BS + ten_table[t]; /* build B addr */
PP (IS);
if ((t = M[IS]) & WM) { /* WM? 6 char inst */
if ((t = M[IS]) & WM) { /* I-6: WM? 6 char inst */
BS = BS | BA; /* BSTAR bad */
goto CHECK_LENGTH; }
D = t; /* could be D char */
BS = BS + one_table[t]; /* finish B addr */
xa = (BS >> V_INDEX) & M_INDEX; /* get index reg */
if (xa && (cpu_unit.flags & XSA)) { /* indexed? */
@ -564,39 +560,43 @@ if (xa && (cpu_unit.flags & XSA)) { /* indexed? */
BS = (BS & INDEXMASK) % MAXMEMSIZE; }
PP (IS);
if ((M[IS] & WM) || (flags & NOWM)) goto CHECK_LENGTH; /* WM? 7 chr */
D = M[IS]; /* last char is D */
do { PP (IS); } while ((M[IS] & WM) == 0); /* find word mark */
if (flags & NOWM) goto CHECK_LENGTH; /* I-7: SWM? done */
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* WM? 7 char inst */
D = t; /* last char is D */
for (;;) { /* I-8: repeats until WM */
if ((t = M[IS]) & WM) break; /* WM? done */
D = t; /* last char is D */
PP (IS); }
CHECK_LENGTH:
ilnt = IS - saved_IS; /* get lnt */
if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) && /* valid lnt? */
((flags & HNOP) == 0)) reason = STOP_INVL;
//if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) && /* valid lnt? */
// ((flags & HNOP) == 0)) reason = STOP_INVL;
if ((flags & BREQ) && ADDR_ERR (BS)) reason = STOP_INVB; /* valid A? */
if ((flags & AREQ) && ADDR_ERR (AS)) reason = STOP_INVA; /* valid B? */
if (reason) break; /* error in fetch? */
switch (op) { /* case on opcode */
/* Move instructions A check B check
/* Move/load character instructions A check B check
MCW: copy A to B, preserving B WM, here fetch
until either A or B WM
LCA: copy A to B, overwriting B WM, here fetch
until A WM
MCM: copy A to B, preserving B WM, fetch fetch
until record or group mark
MCS: copy A to B, clearing B WM, until A WM; fetch fetch
reverse scan and suppress leading zeroes
MN: copy A char digit to B char digit, fetch fetch
preserving B zone and WM
MZ: copy A char zone to B char zone, fetch fetch
preserving B digit and WM
MCW copy A to B, preserving B WM, here fetch
until either A or B WM
LCA copy A to B, overwriting B WM, here fetch
until A WM
Instruction lengths:
1 chained A and B
2,3 invalid A-address
4 chained B address
5,6 invalid B-address
7 normal
8+ normal + modifier
*/
case OP_MCW: /* move char */
if (ilnt >= 8) { /* I/O form? */
if (ioind != BCD_PERCNT) reason = STOP_INVL;
else reason = iodisp (dev, unit, MD_NORM, D);
if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */
reason = iodisp (dev, unit, MD_NORM, D); /* dispatch I/O */
break; }
if (ADDR_ERR (AS)) { /* check A addr */
reason = STOP_INVA;
@ -609,9 +609,8 @@ case OP_MCW: /* move char */
break;
case OP_LCA: /* load char */
if (ilnt >= 8) { /* I/O form? */
if (ioind != BCD_PERCNT) reason = STOP_INVL;
else reason = iodisp (dev, unit, MD_WM, D);
if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */
reason = iodisp (dev, unit, MD_WM, D);
break; }
if (ADDR_ERR (AS)) { /* check A addr */
reason = STOP_INVA;
@ -621,6 +620,27 @@ case OP_LCA: /* load char */
MM (AS); MM (BS); } /* decr pointers */
while ((wm & WM) == 0); /* stop on A WM */
break;
/* Other move instructions A check B check
MCM copy A to B, preserving B WM, fetch fetch
until record or group mark
MCS copy A to B, clearing B WM, until A WM; fetch fetch
reverse scan and suppress leading zeroes
MN copy A char digit to B char digit, fetch fetch
preserving B zone and WM
MZ copy A char zone to B char zone, fetch fetch
preserving B digit and WM
Instruction lengths:
1 chained
2,3 invalid A-address
4 self (B-address = A-address)
5,6 invalid B-address
7 normal
8+ normal + ignored modifier
*/
case OP_MCM: /* move to rec/group */
do {
@ -662,38 +682,18 @@ case OP_MZ: /* move zone */
MM (AS); MM (BS); /* decr pointers */
break;
/* Compare - A and B are checked in fetch */
/* Branch instruction A check B check
case OP_C: /* compare */
if (ilnt != 1) { /* if not chained */
ind[IN_EQU] = 1; /* clear indicators */
ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0; }
do {
a = M[AS]; /* get characters */
b = M[BS];
wm = a | b; /* get word marks */
if ((a & CHAR) != (b & CHAR)) { /* unequal? */
ind[IN_EQU] = 0; /* set indicators */
ind[IN_UNQ] = 1;
ind[IN_HGH] = col_table[b & CHAR] > col_table [a & CHAR];
ind[IN_LOW] = ind[IN_HGH] ^ 1; }
MM (AS); MM (BS); } /* decr pointers */
while ((wm & WM) == 0); /* stop on A, B WM */
if ((a & WM) && !(b & WM)) { /* short A field? */
ind[IN_EQU] = ind[IN_LOW] = 0;
ind[IN_UNQ] = ind[IN_HGH] = 1; }
if (!(cpu_unit.flags & HLE)) /* no HLE? */
ind[IN_EQU] = ind[IN_LOW] = ind[IN_HGH] = 0;
break;
/* Branch instructions A check B check
Instruction lengths:
B 1/8 char: branch if B char equals d if branch here
B 4 char: unconditional branch if branch
B 5 char: branch if indicator[d] is set if branch
BWZ: branch if (d<0>: B char WM) if branch here
(d<1>: B char zone = d zone)
BBE: branch if B char & d non-zero if branch here
1 branch if B char equals d, chained if branch here
2,3 invalid B-address if branch here
4 unconditional branch if branch
5 branch if indicator[d] is set if branch
6 invalid B-address if branch here
7 branch if B char equals d, if branch here
d is last character of B-address
8 branch if B char equals d if branch here
*/
case OP_B: /* branch */
@ -701,14 +701,29 @@ case OP_B: /* branch */
else if (ilnt == 5) { /* branch on ind? */
if (ind[D]) { BRANCH; } /* test indicator */
if (ind_table[D]) ind[D] = 0; } /* reset if needed */
else {
if (ADDR_ERR (BS)) { /* branch char eq */
reason = STOP_INVB; /* validate B addr */
else { /* branch char eq */
if (ADDR_ERR (BS)) { /* validate B addr */
reason = STOP_INVB;
break; }
if ((M[BS] & CHAR) == D) { BRANCH; } /* char equal? */
else { MM (BS); } }
break;
/* Other branch instructions A check B check
BWZ branch if (d<0>: B char WM) if branch here
(d<1>: B char zone = d zone)
BBE branch if B char & d non-zero if branch here
Instruction lengths:
1 chained
2,3 invalid A-address and B-address
4 self (B-address = A-address, d = last character of A-address)
5,6 invalid B-address
7 normal, d = last character of B-address
8+ normal
*/
case OP_BWZ: /* branch wm or zone */
if (((D & 1) && (M[BS] & WM)) || /* d1? test wm */
((D & 2) && ((M[BS] & ZONE) == (D & ZONE)))) /* d2? test zone */
@ -721,14 +736,24 @@ case OP_BBE: /* branch if bit eq */
else { MM (BS); } /* decr pointer */
break;
/* Arithmetic instructions A check B check
/* Arithmetic instructions A check B check
ZA: move A to B, normalizing A sign, fetch fetch
preserving B WM, until B WM
ZS: move A to B, complementing A sign, fetch fetch
preserving B WM, until B WM
A: add A to B fetch fetch
S: subtract A from B fetch fetch
ZA move A to B, normalizing A sign, fetch fetch
preserving B WM, until B WM
ZS move A to B, complementing A sign, fetch fetch
preserving B WM, until B WM
A add A to B fetch fetch
S subtract A from B fetch fetch
C compare A to B fetch fetch
Instruction lengths:
1 chained
2,3 invalid A-address
4 self (B-address = A-address)
5,6 invalid B-address
7 normal
8+ normal + ignored modifier
*/
case OP_ZA: case OP_ZS: /* zero and add/sub */
@ -787,42 +812,71 @@ case OP_A: case OP_S: /* add/sub */
carry = (t >= 10);
M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t]; } }
break;
/* I/O instructions A check B check
R: read a card if branch
W: write to line printer if branch
WR: write and read if branch
P: punch a card if branch
RP: read and punch if branch
WP: write and punch if branch
WRP: write read and punch if branch
RF: read feed (nop)
PF: punch feed (nop)
SS: select stacker if branch
CC: carriage control if branch
MTF: magtape functions
case OP_C: /* compare */
if (ilnt != 1) { /* if not chained */
ind[IN_EQU] = 1; /* clear indicators */
ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0; }
do {
a = M[AS]; /* get characters */
b = M[BS];
wm = a | b; /* get word marks */
if ((a & CHAR) != (b & CHAR)) { /* unequal? */
ind[IN_EQU] = 0; /* set indicators */
ind[IN_UNQ] = 1;
ind[IN_HGH] = col_table[b & CHAR] > col_table [a & CHAR];
ind[IN_LOW] = ind[IN_HGH] ^ 1; }
MM (AS); MM (BS); } /* decr pointers */
while ((wm & WM) == 0); /* stop on A, B WM */
if ((a & WM) && !(b & WM)) { /* short A field? */
ind[IN_EQU] = ind[IN_LOW] = 0;
ind[IN_UNQ] = ind[IN_HGH] = 1; }
if (!(cpu_unit.flags & HLE)) /* no HLE? */
ind[IN_EQU] = ind[IN_LOW] = ind[IN_HGH] = 0;
break;
/* I/O instructions A check B check
R read a card if branch
W write to line printer if branch
WR write and read if branch
P punch a card if branch
RP read and punch if branch
WP : write and punch if branch
WRP write read and punch if branch
RF read feed (nop)
PF punch feed (nop)
SS select stacker if branch
CC carriage control if branch
Instruction lengths:
1 normal
2,3 normal, with modifier
4 branch; modifier, if any, is last character of branch address
5 branch + modifier
6+ normal, with modifier
*/
case OP_R: /* read */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
reason = read_card (ilnt, D); /* read card */
BS = CDR_BUF + CDR_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break;
case OP_W: /* write */
if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */
reason = write_line (ilnt, D); /* print line */
BS = LPT_BUF + LPT_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break;
case OP_P: /* punch */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
reason = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break;
case OP_WR: /* write and read */
@ -830,7 +884,7 @@ case OP_WR: /* write and read */
reason = write_line (ilnt, D); /* print line */
r1 = read_card (ilnt, D); /* read card */
BS = CDR_BUF + CDR_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = r1; /* merge errors */
break;
@ -839,7 +893,7 @@ case OP_WP: /* write and punch */
reason = write_line (ilnt, D); /* print line */
r1 = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = r1; /* merge errors */
break;
@ -848,7 +902,7 @@ case OP_RP: /* read and punch */
reason = read_card (ilnt, D); /* read card */
r1 = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = r1; /* merge errors */
break;
@ -858,24 +912,36 @@ case OP_WRP: /* write, read, punch */
r1 = read_card (ilnt, D); /* read card */
r2 = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = (r1 == SCPE_OK)? r2: r1;
break;
case OP_SS: /* select stacker */
if (reason = iomod (ilnt, D, ss_mod)) break; /* valid modifier? */
if (reason = select_stack (D)) break; /* sel stack, error? */
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break;
case OP_CC: /* carriage control */
if (reason = carriage_control (D)) break; /* car ctrl, error? */
if (ilnt >= 4) { BRANCH; } /* check for branch */
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break;
/* MTF - magtape functions - must be at least 4 characters
Instruction lengths:
1-3 invalid I/O address
4 normal, d-character is unit
5 normal
6+ normal, d-character is last character
*/
case OP_MTF: /* magtape function */
if (reason = iomod (ilnt, D, mtf_mod)) break; /* valid modifier? */
if (reason = mt_func (unit, D)) break; /* mt func, error? */
if (ilnt < 4) reason = STOP_INVL; /* too short? */
else if (ioind != BCD_PERCNT) reason = STOP_INVA;
else if (reason = iomod (ilnt, D, mtf_mod)) break; /* valid modifier? */
reason = mt_func (unit, D); /* mt func, error? */
break; /* can't branch */
case OP_RF: case OP_PF: /* read, punch feed */
@ -902,6 +968,15 @@ case OP_RF: case OP_PF: /* read, punch feed */
The first A field character is masked to its digit part, all others
are copied intact
Instruction lengths:
1 chained
2,3 invalid A-address
4 self (B-address = A-address)
5,6 invalid B-address
7 normal
8+ normal + ignored modifier
*/
case OP_MCE: /* edit */
@ -1040,6 +1115,15 @@ case OP_MCE: /* edit */
LD + 1 + length of multiplier. Locate the low order multiplier digit,
and at the same time zero out the product field. Then compute the sign
of the result.
Instruction lengths:
1 chained
2,3 invalid A-address
4 self (B-address = A-address)
5,6 invalid B-address
7 normal
8+ normal + ignored modifier
*/
case OP_MUL:
@ -1085,7 +1169,7 @@ case OP_MUL:
/* Divide. Comments from the PDP-10 based simulator by Len Fehskens.
Divide is done, like multiply, pretty muchy the same way you do it with
Divide is done, like multiply, pretty much the same way you do it with
pencil and paper; successive subtraction of the divisor from a substring
of the dividend while counting up the corresponding quotient digit.
@ -1106,6 +1190,15 @@ case OP_MUL:
Start by locating the high order non-zero digit of the divisor. This
also tests for a divide by zero.
Instruction lengths:
1 chained
2,3 invalid A-address
4 self (B-address = A-address)
5,6 invalid B-address
7 normal
8+ normal + ignored modifier
*/
case OP_DIV:
@ -1170,16 +1263,19 @@ case OP_DIV:
BS = qs - 2; /* BS = quo 10's pos */
break;
/* Miscellaneous instructions A check B check
/* Word mark instructions A check B check
SWM: set WM on A char and B char fetch fetch
CWM: clear WM on A char and B char fetch fetch
CS: clear from B down to nearest hundreds address if branch fetch
MA: add A addr and B addr, store at B addr fetch fetch
SAR: store A* at A addr fetch
SBR: store B* at A addr fetch
NOP: no operation
H: halt
SWM set WM on A char and B char fetch fetch
CWM clear WM on A char and B char fetch fetch
Instruction lengths:
1 chained
2,3 invalid A-address
4 one operand (B-address = A-address)
5,6 invalid B-address
7 two operands (SWM cannot be longer than 7)
8+ two operands + ignored modifier
*/
case OP_SWM: /* set word mark */
@ -1194,13 +1290,41 @@ case OP_CWM: /* clear word mark */
MM (AS); MM (BS); /* decr pointers */
break;
/* Clear storage instruction A check B check
CS clear from B down to nearest hundreds if branch fetch
address
Instruction lengths:
1 chained
2,3 invalid A-address and B-address
4 one operand (B-address = A-address)
5,6 invalid B-address
7 branch
8+ one operand, branch ignored
*/
case OP_CS: /* clear storage */
t = (BS / 100) * 100; /* lower bound */
while (BS >= t) M[BS--] = 0; /* clear region */
if (BS < 0) BS = BS + MEMSIZE; /* wrap if needed */
if (ilnt >= 7) { BRANCH; } /* branch variant? */
if (ilnt == 7) { BRANCH; } /* branch variant? */
break;
/* Modify address instruction A check B check
MA add A addr and B addr, store at B addr fetch fetch
Instruction lengths:
1 chained
2,3 invalid A-address and B-address
4 self (B-address = A-address)
5,6 invalid B-address
7 normal
8+ normal + ignored modifier
*/
case OP_MA: /* modify address */
a = one_table[M[AS] & CHAR]; MM (AS); /* get A address */
a = a + ten_table[M[AS] & CHAR]; MM (AS);
@ -1215,15 +1339,32 @@ case OP_MA: /* modify address */
if (((a % 4000) + (b % 4000)) >= 4000) BS = BS + 2; /* carry? */
break;
/* Store address instructions A-check B-check
SAR store A* at A addr fetch
SBR store B* at A addr fetch
Instruction lengths:
1 chained
2,3 invalid A-address
4 normal
5+ B-address overwritten from instruction;
invalid address ignored
*/
case OP_SAR: case OP_SBR: /* store A, B reg */
M[AS] = (M[AS] & WM) | store_addr_u (BS); MM (AS);
M[AS] = (M[AS] & WM) | store_addr_t (BS); MM (AS);
M[AS] = (M[AS] & WM) | store_addr_h (BS); MM (AS);
break;
/* NOP - no validity checking, all instructions length ok */
case OP_NOP: /* nop */
break;
/* HALT - unless length = 4 (branch), no validity checking; all lengths ok */
case OP_H: /* halt */
if (ilnt == 4) hb_pend = 1; /* set pending branch */
reason = STOP_HALT; /* stop simulator */

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: IBM 1401 Simulator Usage
Date: 20-Apr-2003
Date: 15-Jul-2003
COPYRIGHT NOTICE
@ -39,13 +39,16 @@ This memorandum documents the IBM 1401 simulator.
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tape.h
sim_tmxr.h
scp.c
scp_tty.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/i1401/ i1401_defs.h
i1401_dat.h
i1401_cpu.c
i1401_cd.c
i1401_iq.c

View file

@ -138,7 +138,7 @@ standard on the Model 2.
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initially, the CPU is a Model I, memory size is
portion of memory is lost. Initially, the CPU is a Model 1, memory size is
20K, and indirect addressing, editing instructions, and divide are enabled.
Memory is implemented as 5 bit BCD digits, as follows:
@ -393,7 +393,7 @@ controlled by command line switches:
-s display as flag terminated numeric string
(CPU and DP only)
-m display instruction mnemonics
(CPU and only)
(CPU and DP only)
-d display 50 characters per line, with word
marks denoted by "_" on the line above

View file

@ -72,7 +72,8 @@ BSC32_SBRS= \
$(INTDIR)/scp.sbr \
$(INTDIR)/scp_tty.sbr \
$(INTDIR)/sim_tmxr.sbr \
$(INTDIR)/sim_sock.sbr
$(INTDIR)/sim_sock.sbr \
$(INTDIR)/ibm1130_fmt.sbr
$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
@ -99,7 +100,8 @@ LINK32_OBJS= \
$(INTDIR)/scp.obj \
$(INTDIR)/scp_tty.obj \
$(INTDIR)/sim_tmxr.obj \
$(INTDIR)/sim_sock.obj
$(INTDIR)/sim_sock.obj \
$(INTDIR)/ibm1130_fmt.obj
$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
@ -149,7 +151,8 @@ BSC32_SBRS= \
$(INTDIR)/scp.sbr \
$(INTDIR)/scp_tty.sbr \
$(INTDIR)/sim_tmxr.sbr \
$(INTDIR)/sim_sock.sbr
$(INTDIR)/sim_sock.sbr \
$(INTDIR)/ibm1130_fmt.sbr
$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
@ -176,7 +179,8 @@ LINK32_OBJS= \
$(INTDIR)/scp.obj \
$(INTDIR)/scp_tty.obj \
$(INTDIR)/sim_tmxr.obj \
$(INTDIR)/sim_sock.obj
$(INTDIR)/sim_sock.obj \
$(INTDIR)/ibm1130_fmt.obj
$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
@ -249,7 +253,7 @@ $(INTDIR)/ibm1130_stddev.obj : $(SOURCE) $(DEP_IBM1130_) $(INTDIR)
SOURCE=.\ibm1130.rc
DEP_IBM1130_R=\
.\1130consoleblank.bmp\
.\HAND.CUR
.\hand.cur
$(INTDIR)/ibm1130.res : $(SOURCE) $(DEP_IBM1130_R) $(INTDIR)
$(RSC) $(RSC_PROJ) $(SOURCE)
@ -354,6 +358,14 @@ DEP_SIM_S=\
$(INTDIR)/sim_sock.obj : $(SOURCE) $(DEP_SIM_S) $(INTDIR)
$(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=.\ibm1130_fmt.c
$(INTDIR)/ibm1130_fmt.obj : $(SOURCE) $(INTDIR)
# End Source File
# End Group
# End Project

View file

@ -9,26 +9,27 @@
* Mail to sim@ibm1130.org
*/
// ctrl-M (Enter) => EOF
// ctrl-U => Erase field
// ctrl-Q => Interrupt request (not here)
// ctrl-C => Program stop (not here)
// \ => "not"
// Del => backspace
// Ctrl-H => backspace
// 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) */
{
/* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */
/* 00 */ 0, 0, 0, 0, 0, 0, 0, 0,0x0004, 0, 0, 0, 0,0x0008, 0, 0,
/* 01 */ 0, 0, 0, 0, 0,0x0002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10 */ 0, 0,0x8820, 0, 0,0x0002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 20 */ 0x0001,0x4820,0x0060,0x0420,0x4420,0x2220,0x8000,0x0120,0x8120,0x4120,0x4220,0x80a0,0x2420,0x4000,0x8420,0x3000,
/* 30 */ 0x2000,0x1000,0x0800,0x0400,0x0200,0x0100,0x0080,0x0040,0x0020,0x0010,0x0820,0x40a0,0x8220,0x00a0,0x20a0,0x2060,
/* 40 */ 0x0220,0x9000,0x8800,0x8400,0x8200,0x8100,0x8080,0x8040,0x8020,0x8010,0x5000,0x4800,0x4400,0x4200,0x4100,0x4080,
/* 50 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010,0xa420, 0,0xc420,0x4060,0x2120,
/* 50 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010, 0, 0, 0, 0,0x2120,
/* 60 */ 0,0x9000,0x8800,0x8400,0x8200,0x8100,0x8080,0x8040,0x8020,0x8010,0x5000,0x4800,0x4400,0x4200,0x4100,0x4080,
/* 70 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010,0xa420, 0,0x8060, 0,0x0004,
/* 70 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010, 0,0xB060, 0, 0,0x0004,
/* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -38,4 +39,3 @@ static uint16 ascii_to_conin[] = /* ASCII to ((hollerith << 4) | special key
/* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0x0004,
};

View file

@ -12,31 +12,47 @@
#define _0_ '\0'
#define CENT '\xA2'
#define REST IGNR
#define RDRSTP '?'
#define NOT '\xAC'
#define IGNR '\xFF'
#define CRLF '\r'
#define CENT_ '\xA2' /* cent and not: standard DOS mapping */
#define NOT_ '\xAC'
#define IGNR_ '\xFF'
#define CRLF_ '\r'
static char conout_to_ascii[] = /* console output code to ASCII */
#define COUT_IS_CTRL 0x01 /* conout characters with bit 1 set are controls: */
#define COUT_CTRL_BLACK 0x04 /* none or one of these bits */
#define COUT_CTRL_RED 0x08
#define COUT_CTRL_LINEFEED 0x02 /* plus none or one of these bits */
#define COUT_CTRL_BACKSPACE 0x10
#define COUT_CTRL_SPACE 0x20
#define COUT_CTRL_TAB 0x40
#define COUT_CTRL_RETURN 0x80
#ifdef _MSC_VER
# pragma warning(disable:4245) /* enable int->char demotion warning caused by characters with high-bit set */
#endif
static unsigned char conout_to_ascii[] = /* console output code to ASCII */
{
/* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */
/* 00 */ '.', _0_, CENT, '\n', '@', REST, '%', _0_, _0_,RDRSTP, _0_, _0_, _0_, _0_, _0_, _0_,
/* 10 */ 'f', '\b', 'F', _0_, 'g', _0_, 'G', _0_, 'b', _0_, 'B', _0_, 'c', _0_, 'C', _0_,
/* 20 */ 'i', ' ', 'I', _0_, 'h', _0_, 'H', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 30 */ 'd', _0_, 'D', _0_, 'e', _0_, 'E', _0_, _0_, _0_, _0_, _0_, 'a', _0_, 'A', _0_,
/* 40 */ '$', _0_, '!', _0_, '&', _0_, '>', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 50 */ 'o', _0_, 'O', _0_, 'p', _0_, 'P', _0_, 'k', _0_, 'K', _0_, 'l', _0_, 'L', _0_,
/* 60 */ 'r', _0_, 'R', _0_, 'q', _0_, 'Q', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 70 */ 'm', _0_, 'M', _0_, 'n', _0_, 'N', _0_, _0_, _0_, _0_, _0_, 'j', _0_, _0_, _0_,
/* 80 */ ',', CRLF, ':', _0_, '-', _0_, '?', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 90 */ 'w', _0_, 'W', _0_, 'x', _0_, 'X', _0_, 's', _0_, 'S', _0_, 't', _0_, 'T', _0_,
/* A0 */ 'z', _0_, 'Z', _0_, 'y', _0_, 'Y', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* B0 */ 'u', _0_, 'U', _0_, 'v', _0_, 'V', _0_, _0_, _0_, _0_, _0_, '/', _0_, '_', _0_,
/* C0 */ '#', _0_, '=', _0_, '0', _0_, '|', _0_, _0_, _0_, _0_, _0_, _0_, _0_, 'J', _0_,
/* 00 */ '.', IGNR_,CENT_, '\n', '@', IGNR_,'%', _0_, _0_, IGNR_,_0_, _0_, _0_, _0_, _0_, _0_,
/* 10 */ 'F', '\b', 'f', _0_, 'G', _0_, 'g', _0_, 'B', _0_, 'b', _0_, 'C', _0_, 'c', _0_,
/* 20 */ 'I', ' ', 'i', _0_, 'H', _0_, 'h', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 30 */ 'D', _0_, 'd', _0_, 'E', _0_, 'e', _0_, _0_, _0_, _0_, _0_, 'A', _0_, 'a', _0_,
/* 40 */ '$', '\t', '!', _0_, '&', _0_, '>', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 50 */ 'O', _0_, 'o', _0_, 'P', _0_, 'o', _0_, 'K', _0_, 'k', _0_, 'L', _0_, 'l', _0_,
/* 60 */ 'R', _0_, 'r', _0_, 'Q', _0_, 'q', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 70 */ 'M', _0_, 'm', _0_, 'N', _0_, 'n', _0_, _0_, _0_, _0_, _0_, 'J', _0_, 'j', _0_,
/* 80 */ ',', CRLF_, ':', _0_, '-', _0_, '?', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* 90 */ 'W', _0_, 'w', _0_, 'X', _0_, 'x', _0_, 'S', _0_, 's', _0_, 'T', _0_, 't', _0_,
/* A0 */ 'Z', _0_, 'z', _0_, 'Y', _0_, 'y', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* B0 */ 'U', _0_, 'u', _0_, 'V', _0_, 'v', _0_, _0_, _0_, _0_, _0_, '/', _0_, '_', _0_,
/* C0 */ '#', _0_, '=', _0_, '0', _0_, '|', _0_, _0_, _0_, _0_, _0_, 'J', _0_, 'j', _0_,
/* D0 */ '6', _0_, ';', _0_, '7', _0_, '*', _0_, '2', _0_, '+', _0_, '3', _0_, '<', _0_,
/* E0 */ '9', _0_, '"', _0_, '8', _0_, '\'', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
/* F0 */ '4', _0_, NOT, _0_, '5', _0_, ')', _0_, _0_, _0_, _0_, _0_, '1', _0_, '(', _0_,
/* F0 */ '4', _0_, NOT_, _0_, '5', _0_, ')', _0_, _0_, _0_, _0_, _0_, '1', _0_, '(', _0_,
};
#ifdef _MSC_VER
# pragma warning(default:4245) /* enable int->char demotion warning */
#endif

View file

@ -9,13 +9,14 @@
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
* Mail to simh@ibm1130.org
25-Jun-01 BLK Written
10-May-02 BLK Fixed bug in MDX instruction
27-Mar-02 BLK Made BOSC work even in short form
16-Aug-02 BLK Fixed bug in multiply instruction; didn't work with negative values
18-Mar-03 BLK Fixed bug in divide instruction; didn't work with negative values
23-Jul-03 BLK Prevented tti polling in CGI mode
The register state for the IBM 1130 CPU is:
@ -470,23 +471,17 @@ t_stat sim_instr (void)
if (wait_state) { /* waiting? */
sim_interval = 0; /* run the clock out */
if (sim_qcount() <= 1) { /* waiting for keyboard only */
if (keyboard_is_locked()) { /* CPU is not expecting a keystroke */
if (sim_qcount() <= (cgi ? 0 : 1)) { /* one routine queued? we're waiting for keyboard only */
if (keyboard_is_busy()) { /* we are actually waiting for a keystroke */
if ((status = sim_process_event()) != 0) /* get it with wait_state still set */
reason = status;
}
else { /* CPU is not expecting a keystroke (keyboard interrupt) */
if (wait_state == WAIT_OP)
reason = STOP_WAIT; /* end the simulation */
reason = STOP_WAIT; /* end the simulation */
else
reason = STOP_INVALID_INSTR;
}
else { /* we are actually waiting for a keystroke */
if ((status = sim_process_event()) != 0) /* get it with wait_state still set */
reason = status;
}
}
else if (sim_clock_queue == NULL) { /* not waiting for anything */
if (wait_state == WAIT_OP)
reason = STOP_WAIT; /* end the simulation */
else
reason = STOP_INVALID_INSTR;
}
if (gdu_active()) /* but don't stop simulator if 2250 GDU is running */
@ -1254,7 +1249,7 @@ void xio_error (char *msg)
* register_cmd - add a command to the extensible command table
* ------------------------------------------------------------------------ */
t_stat register_cmd (char *name, t_stat (*action)(int32, char *), int arg, char *help)
t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help)
{
int i;

File diff suppressed because it is too large Load diff

View file

@ -258,23 +258,23 @@ void xio_2250_display (int32 addr, int32 func, int32 modify); // vector displ
void xio_error (char *msg);
void bail (char *msg);
t_stat load_cr_boot (int drv);
t_stat load_cr_boot (int drv, int switches);
t_stat cr_boot (int unitno, DEVICE *dptr);
void calc_ints (void); /* recalculate interrupt bitmask */
void trace_io (char *fmt, ...); /* debugging printout */
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 */
char hollerith_to_ascii (int16 hol); /* for debugging use only */
char hollerith_to_ascii (uint16 hol); /* for debugging use only */
t_bool gdu_active (void);
void remark_cmd (char *remark);
void stuff_cmd (char *cmd);
void update_gui (t_bool force);
void sim_init (void);
t_stat register_cmd (char *name, t_stat (*action)(int32, char *), int arg, char *help);
t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help);
/* GUI interface routines */
t_bool keyboard_is_locked (void);
t_bool keyboard_is_busy (void);
void forms_check (int set); /* device notification to console lamp display */
void print_check (int set);
void keyboard_selected (int select);

View file

@ -13,14 +13,17 @@ commands may NOT be accurate. This should probably be fixed.
* 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 sim@ibm1130.org
*
* Revision History
* 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)
*
* 01-sep-02 corrected treatment of -m and -r flags in dsk_attach
* in cgi mode, so that file is opened readonly but emulated
* disk is writable.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org
*/
#include "ibm1130_defs.h"
@ -75,6 +78,7 @@ static int16 dsk_sec[DSK_NUMDR] = {0}; /* next-sector-up */
static char dsk_lastio[DSK_NUMDR]; /* last stdio operation: IO_READ or IO_WRITE */
int32 dsk_swait = 50; /* seek time -- see how short a delay we can get away with */
int32 dsk_rwait = 50; /* rotate time */
static t_bool raw_disk_debug = FALSE;
static t_stat dsk_svc (UNIT *uptr);
static t_stat dsk_reset (DEVICE *dptr);
@ -141,6 +145,15 @@ static int32 dsk_ilswlevel[DSK_NUMDR] =
2, 2, 2, 2
};
typedef enum {DSK_FUNC_IDLE, DSK_FUNC_READ, DSK_FUNC_VERIFY, DSK_FUNC_WRITE, DSK_FUNC_SEEK, DSK_FUNC_FAILED} DSK_FUNC;
static struct tag_dsk_action { /* stores data needed for pending IO activity */
int32 io_address;
uint32 io_filepos;
int io_nwords;
int io_sector;
} dsk_action[DSK_NUMDR];
/* xio_disk - XIO command interpreter for the disk drives */
/*
* device status word:
@ -167,7 +180,7 @@ 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;
t_addr newpos;
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];
@ -195,7 +208,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
nwords = M[iocc_addr++ & mem_mask]; /* get word count w/o upsetting SAR/SBR */
if (nwords == 0) /* this is bad -- locks up disk controller ! */
if (nwords == 0) /* this is bad -- on real 1130, this locks up disk controller ! */
break;
if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */
@ -205,49 +218,32 @@ 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 real if not a read check */
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.
newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD;
if (MEM_MAPPED(uptr)) {
memcpy(buf, (char *) uptr->filebuf + newpos, 2*DSK_NUMWD);
}
else {
if (uptr->pos != newpos || dsk_lastio[drv] != IO_READ) {
fseek(uptr->fileref, newpos, SEEK_SET);
dsk_lastio[drv] = IO_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;
}
dsk_action[drv].io_address = iocc_addr;
dsk_action[drv].io_nwords = nwords;
dsk_action[drv].io_sector = sec;
dsk_action[drv].io_filepos = newpos;
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
// if (nwords >= 3)
// 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);
i = uptr->CYL*8 + sec;
if (buf[0] != i)
printf("*DSK read bad sector#\n");
for (i = 0; i < nwords; i++)
M[(iocc_addr+i) & mem_mask] = buf[i];
#ifdef TRACE_DMS_IO
if (trace_dms)
tracesector(0, nwords, iocc_addr & mem_mask, uptr->CYL*8 + sec);
#endif
uptr->FUNC = DSK_FUNC_READ;
}
else
else {
trace_io("* DSK%d verify %d.%d (%x)", drv, uptr->CYL, sec, uptr->CYL*8 + sec);
uptr->FUNC = func;
sim_activate(uptr, dsk_rwait);
if (raw_disk_debug)
printf("* DSK%d verify %d.%d (%x)", drv, uptr->CYL, sec, uptr->CYL*8 + sec);
uptr->FUNC = DSK_FUNC_VERIFY;
}
sim_activate(uptr, dsk_rwait);
break;
case XIO_INITW:
@ -279,7 +275,8 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
trace_io("* DSK%d wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)", drv, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, uptr->CYL*8 + sec, newpos);
// printf("* DSK%d XIO @ %04x wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)\n", drv, prev_IAR, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, uptr->CYL*8 + sec, newpos);
if (raw_disk_debug)
printf("* DSK%d XIO @ %04x wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)\n", drv, prev_IAR, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, uptr->CYL*8 + sec, newpos);
#ifdef TRACE_DMS_IO
if (trace_dms)
@ -309,7 +306,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
uptr->pos = newpos + 2*DSK_NUMWD;
}
uptr->FUNC = func;
uptr->FUNC = DSK_FUNC_WRITE;
sim_activate(uptr, dsk_rwait);
break;
@ -332,7 +329,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
else if (newcyl >= DSK_NUMCY)
newcyl = DSK_NUMCY-1;
uptr->FUNC = func;
uptr->FUNC = DSK_FUNC_SEEK;
uptr->CYL = newcyl;
sim_activate(uptr, dsk_swait); /* schedule interrupt */
@ -371,30 +368,78 @@ static void diskfail (UNIT *uptr, int errflag)
{
sim_cancel(uptr); /* cancel any pending ops */
SETBIT(uptr->flags, errflag); /* set the error flag */
uptr->FUNC = XIO_FAILED; /* tell svc routine why it failed */
uptr->FUNC = DSK_FUNC_FAILED; /* tell svc routine why it failed */
sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */
}
t_stat dsk_svc (UNIT *uptr)
{
int drv = uptr - dsk_unit;
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
int32 iocc_addr;
if (uptr->FUNC == DSK_FUNC_IDLE) /* service function called with no activity? not good, but ignore */
return SCPE_OK;
CLRBIT(dsk_dsw[drv], DSK_DSW_DISK_BUSY); /* activate operation complete interrupt */
CLRBIT(dsk_dsw[drv], DSK_DSW_DISK_BUSY); /* activate operation complete interrupt */
SETBIT(dsk_dsw[drv], DSK_DSW_OP_COMPLETE);
if (uptr->flags & (UNIT_OPERR|UNIT_HARDERR)) { /* word count error or data error */
SETBIT(dsk_dsw[drv], DSK_DSW_DATA_ERROR);
CLRBIT(uptr->flags, UNIT_OPERR); /* but don't clear hard error */
CLRBIT(uptr->flags, UNIT_OPERR); /* soft error is one time occurrence; don't clear hard error */
}
/* schedule interrupt */
SETBIT(ILSW[dsk_ilswlevel[drv]], dsk_ilswbit[drv]);
#ifdef XXXX
switch (uptr->FUNC) {
case XIO_CONTROL:
case XIO_INITR:
case XIO_INITW:
case XIO_FAILED:
switch (uptr->FUNC) { /* take care of business */
case DSK_FUNC_IDLE:
case DSK_FUNC_VERIFY:
case DSK_FUNC_WRITE:
case DSK_FUNC_SEEK:
case DSK_FUNC_FAILED:
break;
case DSK_FUNC_READ: /* actually read the data into core */
iocc_addr = dsk_action[drv].io_address; /* recover saved parameters */
nwords = dsk_action[drv].io_nwords;
newpos = dsk_action[drv].io_filepos;
sec = dsk_action[drv].io_sector;
if (MEM_MAPPED(uptr)) {
memcpy(buf, (char *) uptr->filebuf + newpos, 2*DSK_NUMWD);
}
else {
if (uptr->pos != newpos || dsk_lastio[drv] != IO_READ) {
fseek(uptr->fileref, newpos, SEEK_SET);
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
uptr->pos = newpos + 2*DSK_NUMWD;
}
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
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);
i = uptr->CYL*8 + sec;
if (buf[0] != i)
printf("*DSK read bad sector #\n");
for (i = 0; i < nwords; i++)
M[(iocc_addr+i) & mem_mask] = buf[i];
#ifdef TRACE_DMS_IO
if (trace_dms)
tracesector(0, nwords, iocc_addr & mem_mask, uptr->CYL*8 + sec);
#endif
break;
default:
@ -402,8 +447,8 @@ t_stat dsk_svc (UNIT *uptr)
break;
}
uptr->FUNC = -1; // we're done with this operation
#endif
uptr->FUNC = DSK_FUNC_IDLE; // we're done with this operation
return SCPE_OK;
}
@ -428,7 +473,7 @@ t_stat dsk_reset (DEVICE *dptr)
CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR);
uptr->CYL = 0;
uptr->FUNC = -1;
uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = (uptr->flags & UNIT_ATT) ? DSK_DSW_CARRIAGE_HOME : 0;
}
@ -450,7 +495,7 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr)
return rval;
uptr->CYL = 0; // reset the device
uptr->FUNC = -1;
uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME;
CLRBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_BUFABLE|UNIT_BUF|UNIT_RONLY|UNIT_OPERR|UNIT_HARDERR);
@ -479,6 +524,7 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr)
}
enable_dms_tracing(sim_switches & SWMASK('D'));
raw_disk_debug = sim_switches & SWMASK('G');
return SCPE_OK;
}
@ -498,7 +544,7 @@ static t_stat dsk_detach (UNIT *uptr)
calc_ints();
uptr->CYL = 0;
uptr->FUNC = -1;
uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = DSK_DSW_NOT_READY;
if (drv == 0) {
@ -518,7 +564,7 @@ static t_stat dsk_boot (int unitno, DEVICE *dptr)
if ((rval = reset_all(0)) != SCPE_OK)
return rval;
return load_cr_boot(unitno);
return load_cr_boot(unitno, sim_switches);
}
#ifdef TRACE_DMS_IO

303
Ibm1130/ibm1130_fmt.c Normal file
View file

@ -0,0 +1,303 @@
// 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 <string.h>
#include <stdlib.h>
#include <memory.h>
#include <ctype.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 MIN(a,b) ((a < b) ? a : b)
#define AMSG " with Assembler Reformat"
#define FMSG " with FORTRAN Reformat"
#define AFORMAT "%20.20s%-60.60s"," "
#define ACOMMENTFMT "%20.20s%-60.60s"," "
#define ABLANKLINE "%20.20s*"," "
#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
short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};// tab stops for just plain tabs
// ///////////////
// helper routines
///////////////////////////////////////////////////
// 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
{
short iI, // input position
iO, // output position
iT; // next tab stop
char cX; // character to test
iI = 0; // init input position
iO = 0; // init output position
iT = 0; // init tab stop
while (cX = *(p_szInbuf + iI)) // 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 (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 .. not tab
*(p_szOutbuf + iO++) = cX; // .. save the input char
iI++; // next input character
}
*(p_szOutbuf + iO) = 0; // end the string..
return p_szOutbuf; // .. return output area addr
}
/////////////////////////////////////
// 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
{
int iI; // work integer
char* pszX; // work pointer
pszX = *p_pszToken; // get pointer to token
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
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
}
/////////////////////////////////////////////////////////
// EditToAsm - convert tab-formatted text line to 1130 Assembler format
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
if (p_pszEdit == NULL) // q. null request?
return AMSG; // a. yes .. return display message
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
}
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
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 (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?
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
}
sprintf(gszOutput, AFORMAT, pszLine); // format the line
return gszOutput; // return formatted line
}
/////////////////////////////////////////////////////////
// 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 pszLine[MAXLINE]; // source line
char* pszWork; // work pointer
size_t iI; // work integer
char bContinue; // true if continue
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 (*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
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.
}
// 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++; // skip tab/whitespace
// 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
strncpy(gszArg, pszWork, 75); // copy rest to argument
sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, // format the line
gszLabel, // .. statement #
gszArg); // .. code
return gszOutput; // return formatted line
}
/////////////////////////////////////////////////////////
// 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
if (p_pszEdit == NULL) // q. null request?
return AMSG; // a. yes .. return display message
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
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.
}
return gszOutput; /* ... return buffer */
}

17
Ibm1130/ibm1130_fmt.h Normal file
View file

@ -0,0 +1,17 @@
/*
* (C) Copyright 2003, Bob Flander.
* 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 bob@jftr.com
*/
/* 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

View file

@ -18,7 +18,7 @@
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
* Mail to simh@ibm1130.org
*/
#define BLIT_MODE // normally defined, undefine when debugging generate_image()

View file

@ -9,7 +9,7 @@
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
* Mail to simh@ibm1130.org
*
* 17-May-02 BLK Pulled out of ibm1130_cpu.c
*/
@ -168,30 +168,30 @@ static int bmwid, bmht;
static struct tag_btn {
int x, y;
char *txt;
BOOL pushable;
BOOL pushable, state;
COLORREF clr;
HBRUSH hbrLit, hbrDark;
HWND hBtn;
} btn[] = {
0, 0, "KEYBOARD\nSELECT", FALSE, RGB(255,255,180), NULL, NULL, NULL,
0, 1, "DISK\nUNLOCK", FALSE, RGB(255,255,180), NULL, NULL, NULL,
0, 2, "RUN", FALSE, RGB(0,255,0), NULL, NULL, NULL,
0, 3, "PARITY\nCHECK", FALSE, RGB(255,0,0), NULL, NULL, NULL,
0, 0, "KEYBOARD\nSELECT", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
0, 1, "DISK\nUNLOCK", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL,
0, 2, "RUN", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL,
0, 3, "PARITY\nCHECK", FALSE, FALSE, RGB(255,0,0), NULL, NULL, NULL,
1, 0, "", FALSE, RGB(255,255,180), NULL, NULL, NULL,
1, 1, "FILE\nREADY", FALSE, RGB(0,255,0), NULL, NULL, NULL,
1, 2, "FORMS\nCHECK", FALSE, RGB(255,255,0), NULL, NULL, NULL,
1, 3, "POWER\nON", FALSE, RGB(255,255,180), NULL, NULL, NULL,
1, 0, "", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
1, 1, "FILE\nREADY", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL,
1, 2, "FORMS\nCHECK", FALSE, FALSE, RGB(255,255,0), NULL, NULL, NULL,
1, 3, "POWER\nON", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL,
2, 0, "POWER", TRUE, RGB(255,255,180), NULL, NULL, NULL,
2, 1, "PROGRAM\nSTART", TRUE, RGB(0,255,0), NULL, NULL, NULL,
2, 2, "PROGRAM\nSTOP", TRUE, RGB(255,0,0), NULL, NULL, NULL,
2, 3, "LOAD\nIAR", TRUE, RGB(0,0,255), NULL, NULL, NULL,
2, 0, "POWER", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
2, 1, "PROGRAM\nSTART", TRUE, FALSE, RGB(0,255,0), NULL, NULL, NULL,
2, 2, "PROGRAM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL,
2, 3, "LOAD\nIAR", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL,
3, 0, "KEYBOARD", TRUE, RGB(255,255,180), NULL, NULL, NULL,
3, 1, "IMM\nSTOP", TRUE, RGB(255,0,0), NULL, NULL, NULL,
3, 2, "CHECK\nRESET", TRUE, RGB(0,0,255), NULL, NULL, NULL,
3, 3, "PROGRAM\nLOAD", TRUE, RGB(0,0,255), NULL, NULL, NULL,
3, 0, "KEYBOARD", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
3, 1, "IMM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL,
3, 2, "CHECK\nRESET", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL,
3, 3, "PROGRAM\nLOAD", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL,
};
#define NBUTTONS (sizeof(btn) / sizeof(btn[0]))
@ -318,7 +318,8 @@ static void RepaintRegion (HWND hWnd, int left, int top, int right, int bottom)
void update_gui (BOOL force)
{
int i, sts;
int i;
BOOL state;
static int in_here = FALSE;
static int32 displayed = 0;
@ -385,25 +386,33 @@ void update_gui (BOOL force)
int_lamps = 0;
// this loop works with lamp buttons that are calculated on-the-fly only
for (i = 0; i < NBUTTONS; i++) {
if (btn[i].pushable)
continue;
switch (i) {
case IDC_RUN: sts = hFlashTimer || (running && ! wait_state); break;
// case IDC_PARITY_CHECK: sts = FALSE; break;
// case IDC_POWER_ON: sts = TRUE; break;
default:
continue;
case IDC_RUN:
state = hFlashTimer || (running && ! wait_state);
break;
// case IDC_FILE_READY: these windows are enabled&disabled directly
// 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:
default:
continue;
}
if (sts != IsWindowEnabled(btn[i].hBtn)) // status has changed
EnableWindow(btn[i].hBtn, sts);
if (state != btn[i].state) { // state has changed
EnableWindow(btn[i].hBtn, state);
btn[i].state = state;
}
}
in_here = FALSE;
@ -423,6 +432,7 @@ LRESULT CALLBACK ButtonProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (! btn[i].pushable) {
if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK)
return 0;
if (uMsg == WM_CHAR)
if ((TCHAR) wParam == ' ')
return 0;
@ -622,9 +632,9 @@ static DWORD WINAPI Pump (LPVOID arg)
class_defined = TRUE;
}
hbWhite = GetStockObject(WHITE_BRUSH); /* create or fetch useful GDI objects */
hbBlack = GetStockObject(BLACK_BRUSH); /* create or fetch useful GDI objects */
hbGray = GetStockObject(GRAY_BRUSH);
hbWhite = GetStockObject(WHITE_BRUSH); /* create or fetch useful GDI objects */
hbBlack = GetStockObject(BLACK_BRUSH); /* create or fetch useful GDI objects */
hbGray = GetStockObject(GRAY_BRUSH);
hSwitchPen = CreatePen(PS_SOLID, 5, RGB(255,255,255));
hWhitePen = GetStockObject(WHITE_PEN);
@ -633,8 +643,8 @@ static DWORD WINAPI Pump (LPVOID arg)
hGreyPen = CreatePen(PS_SOLID, 1, RGB(128,128,128));
hDkGreyPen = CreatePen(PS_SOLID, 1, RGB(64,64,64));
hcArrow = LoadCursor(NULL, IDC_ARROW);
hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_HAND));
hcArrow = LoadCursor(NULL, IDC_ARROW);
hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_HAND));
if (hBitmap == NULL)
hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_CONSOLE));
@ -656,11 +666,12 @@ static DWORD WINAPI Pump (LPVOID arg)
bmwid = bm.bmWidth;
bmht = bm.bmHeight;
for (i = 0; i < NBUTTONS; i++)
for (i = 0; i < NBUTTONS; i++) {
CreateSubclassedButton(hConsoleWnd, i);
EnableWindow(btn[IDC_POWER_ON].hBtn, TRUE);
EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, TRUE);
if (! btn[i].pushable)
EnableWindow(btn[i].hBtn, btn[i].state);
}
GetWindowRect(hConsoleWnd, &r); /* get window size as created */
wx = r.right - r.left + 1;
@ -913,12 +924,19 @@ void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam)
reset_all(0);
if (running && ! power) { /* turning off */
reason = STOP_POWER_OFF;
while (running)
Sleep(10); /* 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); /* wait for execution thread to exit */
}
btn[IDC_POWER_ON].state = power;
EnableWindow(btn[IDC_POWER_ON].hBtn, power);
for (i = 0; i < NBUTTONS; i++)
InvalidateRect(btn[i].hBtn, NULL, TRUE);
for (i = 0; i < NBUTTONS; i++) /* repaint all of the lamps */
if (! btn[i].pushable)
InvalidateRect(btn[i].hBtn, NULL, TRUE);
break;
case IDC_PROGRAM_START: /* begin execution */
@ -967,8 +985,11 @@ void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam)
case IDC_IMM_STOP:
if (running) {
reason = STOP_WAIT; /* terminate execution without setting wait_mode */
while (running)
Sleep(10); /* 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); /* wait for execution thread to exit */
}
break;
@ -1084,10 +1105,14 @@ void forms_check (int set)
btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0);
EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
btn[IDC_FORMS_CHECK].state = printerstatus;
if (btn[IDC_FORMS_CHECK].clr != oldcolor)
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case
if (btn[IDC_FORMS_CHECK].hBtn != NULL) {
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
}
}
void print_check (int set)
@ -1101,25 +1126,38 @@ void print_check (int set)
btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0);
EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
btn[IDC_FORMS_CHECK].state = printerstatus;
if (btn[IDC_FORMS_CHECK].clr != oldcolor)
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case
if (btn[IDC_FORMS_CHECK].hBtn != NULL) {
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
}
}
void keyboard_selected (int select)
{
EnableWindow(btn[IDC_KEYBOARD_SELECT].hBtn, select);
btn[IDC_KEYBOARD_SELECT].state = select;
if (btn[IDC_KEYBOARD_SELECT].hBtn != NULL)
EnableWindow(btn[IDC_KEYBOARD_SELECT].hBtn, select);
}
void disk_ready (int ready)
{
EnableWindow(btn[IDC_FILE_READY].hBtn, ready);
btn[IDC_FILE_READY].state = ready;
if (btn[IDC_FILE_READY].hBtn != NULL)
EnableWindow(btn[IDC_FILE_READY].hBtn, ready);
}
void disk_unlocked (int unlocked)
{
EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked);
btn[IDC_DISK_UNLOCK].state = unlocked;
if (btn[IDC_DISK_UNLOCK].hBtn != NULL)
EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked);
}
CRITICAL_SECTION critsect;

View file

@ -23,7 +23,7 @@
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
* Mail to simh@ibm1130.org
*/
#include "ibm1130_defs.h"

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,7 @@
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
* Mail to simh@ibm1130.org
*/
#include "ibm1130_defs.h"

View file

@ -58,9 +58,11 @@ ibm1130D = ./
ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \
${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \
${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.c \
${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c
${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c \
${ibm1130D}ibm1130_fmt.c
ibm1130_INC = ibm1130res.h ibm1130_conin.h ibm1130_conout.h \
ibm1130_defs.h ibm1130_prtwheel.h \
ibm1130_defs.h ibm1130_prtwheel.h ibm1130_fmt.h \
dmsr2v12phases.h dmsr2v12slet.h
#

View file

@ -1,5 +1,10 @@
Here's the 1130 simulator as it stands now.
Status: 22Jul2003
* Added support for APL\1130 output translations
and some bug fixes uncovered by APL.
Status: 13Sep2002
* Added support for 1403 printer. It's MUCH faster

View file

@ -1,7 +1,11 @@
Version: 18 March 2003
Version: 10 July 2003
History (partial):
2003-07-10 Fixed disk and console terminal bugs uncovered by
APL\1130. Added APL keyboard and output font support
to enable use of APL\1130. APL will be released soon.
2003-03-18 Fixed bug in asm1130 that produced an error message
with a (legal) offset of +127 in MDX instructions.

View file

@ -13,6 +13,7 @@
// ASM1130 - IBM 1130 Cross Assembler
//
// Version
// 1.08 - 2003Mar18 - Fixed bug that complained about valid MDX displacement of +127
// 1.07 - 2003Jan05 - Filenames are now left in lower case. SYMBOLS.SYS stays all upper case
// 1.06 - 2002May02 - Fixed bug in ebdic constants (data goes into low byte)
// First stab at adding ISS level # info, this is iffy
@ -156,7 +157,7 @@
#define TRUE 1
#define FALSE 0
#define VERSION "ASM1130 CROSS ASSEMBLER V1.07"
#define VERSION "ASM1130 CROSS ASSEMBLER V1.08"
#define ISTV 0x33 // magic number from DMS R2V12 monitorm symbol @ISTV
@ -3392,7 +3393,7 @@ void mdx_op (struct tag_op *op, char *label, char *mods, char *arg)
else
getexpr(tok, FALSE, &incr);
if (incr.value < -128 || incr.value >= 127) // displacement style
if (incr.value < -128 || incr.value > 127) // displacement style (fixed in ver 1.08)
asm_error("Invalid increment value (8 bits signed)");
opcode |= (incr.value & 0xFF);

View file

@ -426,7 +426,7 @@ void show_data (void)
(reloc == R_LIBF) ? 'L' : '@';
printf("%04x%c ", buf[9+i], ch);
rflag << 2;
rflag <<= 2;
nout++;
}
putchar('\n');

View file

@ -337,7 +337,7 @@ void show_data (unsigned short *buf)
(reloc == R_LIBF) ? 'L' : '@';
printf("%04x%c ", buf[9+i], ch);
rflag << 2;
rflag <<= 2;
nout++;
}
putchar('\n');

View file

@ -15,25 +15,61 @@
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef int BOOL;
int hollerith_to_ascii (unsigned short h);
void bail (char *msg);
void format_coldstart (unsigned short *buf);
int main (int argc, char **argv)
{
FILE *fd;
char line[82];
char *fname = NULL, line[82], *arg;
BOOL coldstart = FALSE;
unsigned short buf[80];
int i, lastnb;
static char usestr[] =
"Usage: viewdeck [-c] deckfile\n"
"\n"
"-c: convert cold start card to 16-bit format as a C array initializer\n";
if (argc != 2)
bail("Usage: viewdeck deckfile");
for (i = 1; i < argc; i++) { // process command line arguments
arg = argv[i];
if ((fd = fopen(argv[1], "rb")) == NULL) {
perror(argv[1]);
if (*arg == '-') {
arg++;
while (*arg) {
switch (*arg++) {
case 'c':
coldstart = TRUE;
break;
default:
bail(usestr);
}
}
}
else if (fname == NULL) // first non-switch arg is file name
fname = arg;
else
bail(usestr); // there can be only one name
}
if (fname == NULL) // there must be a name
bail(usestr);
if ((fd = fopen(fname, "rb")) == NULL) {
perror(fname);
return 1;
}
while (fread(buf, sizeof(short), 80, fd) == 80) {
if (coldstart) {
format_coldstart(buf);
break;
}
lastnb = -1;
for (i = 0; i < 80; i++) {
line[i] = hollerith_to_ascii(buf[i]);
@ -45,11 +81,39 @@ int main (int argc, char **argv)
fputs(line, stdout);
}
if (coldstart) {
if (fread(buf, sizeof(short), 1, fd) == 1)
bail("Coldstart deck has more than one card");
}
fclose(fd);
return 0;
}
void format_coldstart (unsigned short *buf)
{
int i, nout = 0;
unsigned short word;
for (i = 0; i < 80; i++) {
word = buf[i]; // expand 12-bit card data to 16-bit instruction
word = (word & 0xF800) | ((word & 0x0400) ? 0x00C0 : 0x0000) | ((word & 0x03F0) >> 4);
if (nout >= 8) {
fputs(",\n", stdout);
nout = 0;
}
else if (i > 0)
fputs(", ", stdout);
printf("0x%04x", word);
nout++;
}
putchar('\n');
}
typedef struct {
unsigned short hollerith;
char ascii;
@ -103,7 +167,7 @@ static CPCODE cardcode_029[] =
0x0120, '\'',
0x00A0, '=',
0x0060, '"',
0x8820, 'c', // cent
0x8820, '\xA2', // cent, in MS-DOS encoding
0x8420, '.',
0x8220, '<', // ) in 026 Fortran
0x8120, '(',
@ -114,13 +178,47 @@ static CPCODE cardcode_029[] =
0x4220, '*',
0x4120, ')',
0x40A0, ';',
0x4060, 'n', // not
0x2820, 'x', // what?
0x4060, '\xAC', // not, in MS-DOS encoding
0x2420, ',',
0x2220, '%', // ( in 026 Fortran
0x2120, '_',
0x20A0, '>',
0x2060, '>',
0xB000, 'a',
0xA800, 'b',
0xA400, 'c',
0xA200, 'd',
0xA100, 'e',
0xA080, 'f',
0xA040, 'g',
0xA020, 'h',
0xA010, 'i',
0xD000, 'j',
0xC800, 'k',
0xC400, 'l',
0xC200, 'm',
0xC100, 'n',
0xC080, 'o',
0xC040, 'p',
0xC020, 'q',
0xC010, 'r',
0x6800, 's',
0x6400, 't',
0x6200, 'u',
0x6100, 'v',
0x6080, 'w',
0x6040, 'x',
0x6020, 'y',
0x6010, 'z', // these odd punch codes are used by APL:
0x1010, '\001', // no corresponding ASCII using ^A
0x0810, '\002', // SYN using ^B
0x0410, '\003', // no corresponding ASCII using ^C
0x0210, '\004', // PUNCH ON using ^D
0x0110, '\005', // READER STOP using ^E
0x0090, '\006', // UPPER CASE using ^F
0x0050, '\013', // EOT using ^K
0x0030, '\016', // no corresponding ASCII using ^N
0x1030, '\017', // no corresponding ASCII using ^O
0x0830, '\020', // no corresponding ASCII using ^P
};
int hollerith_to_ascii (unsigned short h)

View file

@ -23,6 +23,7 @@
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.
15-Jul-03 RMS Fixed signed/unsigned bug in get_imm
27-Feb-03 RMS Added relative addressing support
23-Dec-01 RMS Cloned from ID4 sources
*/
@ -481,7 +482,7 @@ return reg;
t_stat get_imm (char *cptr, uint32 *imm, uint32 *inst, uint32 max)
{
char *tptr;
uint32 idx;
int32 idx;
errno = 0;
*imm = strtoul (cptr, &tptr, 16); /* get immed */

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: Interdata 16b/32b Simulator Usage
Date: 15-Mar-2003
Date: 15-Jul-2003
COPYRIGHT NOTICE
@ -39,10 +39,12 @@ This memorandum documents the Interdata 16b and 32b simulators.
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tape.h
sim_tmxr.h
scp.c
scp_tty.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/interdata/ id_defs.h
@ -519,8 +521,7 @@ The programmable interval clock (PIC) implements these registers:
IARM 1 clock interrupt armed
If the interval requested is an exact multiple of 1 msec, the
programmable clock auto-calibrates; if not, it simply counts
counts instructions.
programmable clock auto-calibrates; if not, it counts instructions.
2.4.7 Floppy Disk Controller (FD)
@ -822,7 +823,7 @@ line switches:
alphabetic instruction mnemonic
numeric octal number
2.7.1 16b Instruction Input
2.8.1 16b Instruction Input
Instruction input uses standard Interdata assembler syntax. There are
seven instruction classes: short branch, extended short branch, short
@ -883,7 +884,7 @@ preceded by R, between 0 and F (15), the address is a hex number
between 0 and 0xFFFF, and the index register is a hex (decimal)
number, optionally preceded by R, between 1 and F (15).
2.7.2 32b Instruction Input
2.8.2 32b Instruction Input
Instruction input uses standard Interdata assembler syntax. There are
nine instruction classes: short branch, extended short branch, short

View file

@ -305,8 +305,8 @@ The clock implements these registers:
TIME2 24 clock frequency, select = 2
TIME3 24 clock frequency, select = 3
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
The real-time clock autocalibrates; the clock interval is adjusted up
or down so that the clock tracks actual elapsed time.
2.2.7 Plotter (PTP)

View file

@ -25,6 +25,7 @@
dsk fixed head disk
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable capacity interaction with save/restore
03-Mar-03 RMS Fixed variable capacity and autosizing
03-Oct-02 RMS Added DIB
@ -133,14 +134,14 @@ REG dsk_reg[] = {
{ NULL } };
MTAB dsk_mod[] = {
{ UNIT_PLAT, 0, NULL, "1P", &dsk_set_size },
{ UNIT_PLAT, 1, NULL, "2P", &dsk_set_size },
{ UNIT_PLAT, 2, NULL, "3P", &dsk_set_size },
{ UNIT_PLAT, 3, NULL, "4P", &dsk_set_size },
{ UNIT_PLAT, 4, NULL, "5P", &dsk_set_size },
{ UNIT_PLAT, 5, NULL, "6P", &dsk_set_size },
{ UNIT_PLAT, 6, NULL, "7P", &dsk_set_size },
{ UNIT_PLAT, 7, NULL, "8P", &dsk_set_size },
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &dsk_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &dsk_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &dsk_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &dsk_set_size },
{ UNIT_PLAT, (4 << UNIT_V_PLAT), NULL, "5P", &dsk_set_size },
{ UNIT_PLAT, (5 << UNIT_V_PLAT), NULL, "6P", &dsk_set_size },
{ UNIT_PLAT, (6 << UNIT_V_PLAT), NULL, "7P", &dsk_set_size },
{ UNIT_PLAT, (7 << UNIT_V_PLAT), NULL, "8P", &dsk_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ 0 } };
@ -289,9 +290,9 @@ return attach_unit (uptr, cptr);
t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if ((val < 0) || (val >= DSK_NUMDK)) return SCPE_IERR;
if (val < 0) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = (val + 1) * DSK_DKSIZE;
uptr->capac = UNIT_GETP (val) * DSK_DKSIZE;
uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK;
}

View file

@ -25,6 +25,7 @@
cpu PDP-1 central processor
23-Jul-03 RMS Revised to detect I/O wait hang
05-Dec-02 RMS Added drum support
06-Oct-02 RMS Revised for V2.10
20-Aug-02 RMS Added DECtape support
@ -239,6 +240,7 @@ int32 sbs = 0; /* sequence break */
int32 sbs_init = 0; /* seq break startup */
int32 ioh = 0; /* I/O halt */
int32 ioc = 0; /* I/O completion */
int32 cpls = 0; /* pending completions */
int32 extm = 0; /* ext mem mode */
int32 extm_init = 0; /* ext mem startup */
int32 stop_inst = 0; /* stop on rsrv inst */
@ -257,13 +259,13 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
extern int32 ptr (int32 inst, int32 dev, int32 IO);
extern int32 ptp (int32 inst, int32 dev, int32 IO);
extern int32 tti (int32 inst, int32 dev, int32 IO);
extern int32 tto (int32 inst, int32 dev, int32 IO);
extern int32 lpt (int32 inst, int32 dev, int32 IO);
extern int32 dt (int32 inst, int32 dev, int32 IO);
extern int32 drm (int32 inst, int32 dev, int32 IO);
extern int32 ptr (int32 inst, int32 dev, int32 dat);
extern int32 ptp (int32 inst, int32 dev, int32 dat);
extern int32 tti (int32 inst, int32 dev, int32 dat);
extern int32 tto (int32 inst, int32 dev, int32 dat);
extern int32 lpt (int32 inst, int32 dev, int32 dat);
extern int32 dt (int32 inst, int32 dev, int32 dat);
extern int32 drm (int32 inst, int32 dev, int32 dat);
int32 sc_map[512] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */
@ -403,7 +405,7 @@ xct_count = 0; /* track nested XCT's */
sim_interval = sim_interval - 1;
xct_instr: /* label for XCT */
if ((IR == 0610001) && ((MA & EPCMASK) == 0) && (sbs & SB_ON)) {
if ((IR == (OP_JMP+IA+1)) && ((MA & EPCMASK) == 0) && (sbs & SB_ON)) {
sbs = sbs & ~SB_IP; /* seq debreak */
PCQ_ENTRY; /* save old PC */
OV = (M[1] >> 17) & 1; /* restore OV */
@ -432,12 +434,15 @@ switch (op) { /* decode IR<0:4> */
case 001: /* AND */
AC = AC & M[MA];
break;
case 002: /* IOR */
AC = AC | M[MA];
break;
case 003: /* XOR */
AC = AC ^ M[MA];
break;
case 004: /* XCT */
if (xct_count >= xct_max) { /* too many XCT's? */
reason = STOP_XCT;
@ -445,6 +450,7 @@ case 004: /* XCT */
xct_count = xct_count + 1; /* count XCT's */
IR = M[MA]; /* get instruction */
goto xct_instr; /* go execute */
case 007: /* CAL, JDA */
MA = (PC & EPCMASK) | ((IR & IA)? (IR & DAMASK): 0100);
PCQ_ENTRY;
@ -452,24 +458,31 @@ case 007: /* CAL, JDA */
AC = EPC_WORD;
PC = INCR_ADDR (MA);
break;
case 010: /* LAC */
AC = M[MA];
break;
case 011: /* LIO */
IO = M[MA];
break;
case 012: /* DAC */
if (MEM_ADDR_OK (MA)) M[MA] = AC;
break;
case 013: /* DAP */
if (MEM_ADDR_OK (MA)) M[MA] = (AC & DAMASK) | (M[MA] & ~DAMASK);
break;
case 014: /* DIP */
if (MEM_ADDR_OK (MA)) M[MA] = (AC & ~DAMASK) | (M[MA] & DAMASK);
break;
case 015: /* DIO */
if (MEM_ADDR_OK (MA)) M[MA] = IO;
break;
case 016: /* DZM */
if (MEM_ADDR_OK (MA)) M[MA] = 0;
break;
@ -498,6 +511,7 @@ case 020: /* ADD */
if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1;
if (AC == 0777777) AC = 0; /* minus 0 cleanup */
break;
case 021: /* SUB */
t = AC ^ 0777777; /* complement AC */
AC = t + M[MA]; /* -AC + MB */
@ -505,32 +519,39 @@ case 021: /* SUB */
if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1;
AC = AC ^ 0777777; /* recomplement AC */
break;
case 022: /* IDX */
AC = M[MA] + 1;
if (AC >= 0777777) AC = (AC + 1) & 0777777;
if (MEM_ADDR_OK (MA)) M[MA] = AC;
break;
case 023: /* ISP */
AC = M[MA] + 1;
if (AC >= 0777777) AC = (AC + 1) & 0777777;
if (MEM_ADDR_OK (MA)) M[MA] = AC;
if (AC < 0400000) PC = INCR_ADDR (PC);
break;
case 024: /* SAD */
if (AC != M[MA]) PC = INCR_ADDR (PC);
break;
case 025: /* SAS */
if (AC == M[MA]) PC = INCR_ADDR (PC);
break;
case 030: /* JMP */
PCQ_ENTRY;
PC = MA;
break;
case 031: /* JSP */
AC = EPC_WORD;
PCQ_ENTRY;
PC = MA;
break;
case 034: /* LAW */
AC = (IR & 07777) ^ ((IR & IA)? 0777777: 0);
break;
@ -691,8 +712,11 @@ case 035:
if (ioh) { /* I/O halt? */
if (ioc) ioh = 0; /* comp pulse? done */
else { /* wait more */
sim_interval = 0; /* force event */
PC = DECR_ADDR (PC); } /* re-execute */
PC = DECR_ADDR (PC); /* re-execute */
if (cpls == 0) { /* any pending pulses? */
reason = STOP_WAIT; /* no, CPU hangs */
break; }
sim_interval = 0; } /* force event */
break; } /* skip iot */
ioh = 1; /* turn on halt */
PC = DECR_ADDR (PC); } /* re-execute */
@ -745,6 +769,7 @@ case 035:
if (io_data & IOT_SKP) PC = INCR_ADDR (PC); /* skip? */
if (io_data >= IOT_REASON) reason = io_data >> IOT_V_REASON;
break;
default: /* undefined */
reason = STOP_RSRV; /* halt */
break; } /* end switch opcode */
@ -759,7 +784,7 @@ t_stat cpu_reset (DEVICE *dptr)
{
sbs = sbs_init;
extm = extm_init;
ioh = ioc = 0;
ioh = ioc = cpls = 0;
OV = 0;
PF = 0;
pcq_r = find_reg ("PCQ", NULL, dptr);

View file

@ -23,6 +23,8 @@
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.
22-Jul-03 RMS Updated for "hardware" RIM loader
Revised to detect I/O wait hang
05-Dec-02 RMS Added IOT skip support (required by drum)
14-Apr-99 RMS Changed t_addr to unsigned
@ -34,7 +36,9 @@
Automatic multiply/divide Type 10
Memory extension control Type 15
Serial drum Type 24
Line printer control Type 62
Microtape (DECtape) control Type 550
*/
#include "sim_defs.h"
@ -46,7 +50,7 @@
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_XCT 4 /* nested XCT's */
#define STOP_IND 5 /* nested indirects */
#define STOP_WAIT 6 /* wait state */
#define STOP_WAIT 6 /* IO wait hang */
/* Memory */
@ -59,11 +63,14 @@
/* Architectural constants */
#define DMASK 0777777 /* data mask */
#define DAMASK 007777 /* direct addr */
#define DAMASK 0007777 /* direct addr */
#define EPCMASK (AMASK & ~DAMASK) /* extended addr */
#define IA 010000 /* indirect flag */
#define IO_WAIT 010000 /* I/O sync wait */
#define IO_CPLS 004000 /* completion pulse */
#define IA 0010000 /* indirect flag */
#define IO_WAIT 0010000 /* I/O sync wait */
#define IO_CPLS 0004000 /* completion pulse */
#define OP_DAC 0240000 /* DAC */
#define OP_DIO 0320000 /* DIO */
#define OP_JMP 0600000 /* JMP */
#define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */
/* IOT subroutine return codes */
@ -96,6 +103,17 @@
#define IOS_PNT (1 << IOS_V_PNT)
#define IOS_SPC (1 << IOS_V_SPC)
/* Completion pulses */
#define CPLS_V_PTR 5
#define CPLS_V_PTP 4
#define CPLS_V_TTO 3
#define CPLS_V_LPT 2
#define CPLS_PTR (1 << CPLS_V_PTR)
#define CPLS_PTP (1 << CPLS_V_PTP)
#define CPLS_TTO (1 << CPLS_V_TTO)
#define CPLS_LPT (1 << CPLS_V_LPT)
/* Sequence break flags */
#define SB_V_IP 0 /* in progress */

View file

@ -1,14 +1,14 @@
To: Users
From: Bob Supnik
Subj: PDP-1 Simulator Usage
Date: 15-Dec-2002
Date: 15-Jul-2003
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik
Copyright (c) 1993-2002, Robert M Supnik
Original code published in 1993-2003, written by Robert M Supnik
Copyright (c) 1993-2003, 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"),
@ -75,8 +75,8 @@ The PDP-1 simulator implements the following unique stop conditions:
memory reference address decoding
- more than XCTMAX nested executes are detected during
instruction execution
- wait state entered, and no I/O operations outstanding
(ie, no interrupt can ever occur)
- I/O wait, and no I/O operations outstanding (i.e, no I/O
completion will ever occur)
The PDP-1 loader supports RIM format tapes. The DUMP command is not
implemented.

View file

@ -1,4 +1,4 @@
/* pdp1_drm.c: drum/fixed head disk simulator
/* pdp1_drm.c: PDP-1 drum simulator
Copyright (c) 1993-2002, Robert M Supnik
@ -25,6 +25,7 @@
drm Type 24 serial drum
23-Jul-03 RMS Fixed incorrect logical, missing activate
05-Dec-02 RMS Cloned from pdp18b_drm.c
*/
@ -95,45 +96,44 @@ DEVICE drm_dev = {
/* IOT routines */
int32 drm (int32 IR, int32 dev, int32 IO)
int32 drm (int32 IR, int32 dev, int32 dat)
{
int32 t;
int32 pulse = (IR >> 6) & 037;
if (drm_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | IO; /* stop if requested */
if ((pulse != 001) & (pulse != 011)) /* invalid pulse? */
return (stop_inst << IOT_V_REASON) | IO; /* stop if requested */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
if ((pulse != 001) && (pulse != 011)) /* invalid pulse? */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
switch (dev) { /* switch on device */
case 061: /* DWR, DRD */
drm_ma = IO & 0177777; /* load mem addr */
drm_ma = dat & 0177777; /* load mem addr */
drm_unit.FUNC = pulse & DRM_WRITE; /* save function */
break;
case 062: /* DBL, DCN */
if (pulse & 010) drm_da = IO & DRM_SMASK; /* load sector # */
if (pulse & 010) drm_da = dat & DRM_SMASK; /* load sector # */
iosta = iosta & ~IOS_DRM; /* clear flags */
drm_err = 0;
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t <= 0) t = t + DRM_NUMWDT; /* wrap around? */
sim_activate (&drm_unit, t); /* start operation */
break;
case 063: /* DTD */
if (iosta & IOS_DRM) return (IO | IOT_SKP); /* skip if done */
if (pulse == 011) return (stop_inst << IOT_V_REASON) | dat;
if (iosta & IOS_DRM) return (dat | IOT_SKP); /* skip if done */
break;
case 064: /* DSE, DSP */
if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
return (IO | IOT_SKP);
return (dat | IOT_SKP);
}
return IO;
return dat;
}
/* Unit service
This code assumes the entire drum is buffered.
*/
/* Unit service - this code assumes the entire drum is buffered */
t_stat drm_svc (UNIT *uptr)
{
int32 i;
uint32 da;
uint32 i, da;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */

View file

@ -334,23 +334,23 @@ DEVICE dt_dev = {
NULL, &dt_attach, &dt_detach,
NULL, DEV_DISABLE };
int32 dt (int32 IR, int32 dev, int32 IO)
int32 dt (int32 IR, int32 dev, int32 dat)
{
int32 pulse = (IR >> 6) & 037;
int32 fnc, mot, unum;
UNIT *uptr = NULL;
if (dt_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | IO; /* stop if requested */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
unum = DTA_GETUNIT (dtsa); /* get unit no */
if (unum >= 0) uptr = dt_dev.units + unum; /* get unit */
if (pulse == 003) { /* MSE */
if ((dtsa ^ IO) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */
dtsa = (dtsa & ~DTA_UNIT) | (IO & DTA_UNIT);
if ((dtsa ^ dat) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */
dtsa = (dtsa & ~DTA_UNIT) | (dat & DTA_UNIT);
dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); }
if (pulse == 004) { /* MLC */
dtsa = (dtsa & ~DTA_RW) | (IO & DTA_RW); /* load dtsa */
dtsa = (dtsa & ~DTA_RW) | (dat & DTA_RW); /* load dtsa */
dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR);
fnc = DTA_GETFNC (dtsa); /* get fnc */
if ((uptr == NULL) || /* invalid? */
@ -361,10 +361,10 @@ if (pulse == 004) { /* MLC */
dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); }
if (pulse == 005) { /* MRD */
IO = (IO & ~DMASK) | dtdb;
dat = (dat & ~DMASK) | dtdb;
dtsb = dtsb & ~(DTB_DTF | DTB_BEF); }
if (pulse == 006) { /* MWR */
dtdb = IO & DMASK;
dtdb = dat & DMASK;
dtsb = dtsb & ~(DTB_DTF | DTB_BEF); }
if (pulse == 007) { /* MRS */
dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */
@ -373,9 +373,9 @@ if (pulse == 007) { /* MRS */
if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */
if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700))
dtsb = dtsb | DTB_GO; } /* accel? go */
IO = (IO & ~DMASK) | dtsb; }
dat = (dat & ~DMASK) | dtsb; }
DT_UPDINT;
return IO;
return dat;
}
/* Unit deselect */

View file

@ -25,6 +25,8 @@
lpt Type 62 line printer for the PDP-1
23-Jul-03 RMS Fixed bugs in instruction decoding, overprinting
Revised to detect I/O wait hang
25-Apr-03 RMS Revised for extended file support
30-May-02 RMS Widened POS to 32b
13-Apr-01 RMS Revised for register arrays
@ -36,10 +38,10 @@
#define LPT_BSIZE (BPTR_MAX * 3) /* line size */
#define BPTR_MASK 077 /* buf ptr mask */
extern int32 ioc, sbs, iosta;
extern int32 stop_inst;
int32 lpt_rpls = 0, lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
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 */
char lpt_buf[LPT_BSIZE + 1] = { 0 };
static const unsigned char lpt_trans[64] = {
' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<',
@ -47,6 +49,9 @@ static const unsigned char lpt_trans[64] = {
'@','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(',
'_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' };
extern int32 ioc, cpls, sbs, iosta;
extern int32 stop_inst;
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
@ -64,9 +69,10 @@ REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (PNT, iosta, IOS_V_PNT) },
{ FLDATA (SPC, iosta, IOS_V_SPC) },
{ FLDATA (RPLS, lpt_rpls, 0) },
{ DRDATA (BPTR, bptr, 6) },
{ ORDATA (LPT_STATE, lpt_iot, 6), REG_HRO },
{ FLDATA (RPLS, cpls, CPLS_V_LPT) },
{ DRDATA (BPTR, lpt_bptr, 6) },
{ ORDATA (LPT_STATE, lpt_spc, 6), REG_HRO },
{ FLDATA (LPT_OVRPR, lpt_ovrpr, 0), REG_HRO },
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
@ -82,38 +88,39 @@ DEVICE lpt_dev = {
/* Line printer IOT routine */
int32 lpt (int32 inst, int32 dev, int32 data)
int32 lpt (int32 inst, int32 dev, int32 dat)
{
int32 i;
if (lpt_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | data; /* stop if requested */
if ((inst & 0700) == 0100) { /* fill buf */
if (bptr < BPTR_MAX) { /* limit test ptr */
i = bptr * 3; /* cvt to chr ptr */
lpt_buf[i] = lpt_trans[(data >> 12) & 077];
lpt_buf[i + 1] = lpt_trans[(data >> 6) & 077];
lpt_buf[i + 2] = lpt_trans[data & 077]; }
bptr = (bptr + 1) & BPTR_MASK;
return data; }
lpt_rpls = 0;
if ((inst & 0700) == 0200) { /* space */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
if ((inst & 07000) == 01000) { /* fill buf */
if (lpt_bptr < BPTR_MAX) { /* limit test ptr */
i = lpt_bptr * 3; /* cvt to chr ptr */
lpt_buf[i] = lpt_trans[(dat >> 12) & 077];
lpt_buf[i + 1] = lpt_trans[(dat >> 6) & 077];
lpt_buf[i + 2] = lpt_trans[dat & 077]; }
lpt_bptr = (lpt_bptr + 1) & BPTR_MASK;
return dat; }
if ((inst & 07000) == 02000) { /* space */
iosta = iosta & ~IOS_SPC; /* space, clear flag */
lpt_iot = (inst >> 6) & 077; } /* state = space n */
else { iosta = iosta & ~IOS_PNT; /* clear flag */
lpt_iot = 0; } /* state = print */
lpt_spc = (inst >> 6) & 077; } /* state = space n */
else if ((inst & 07000) == 00000) { /* print */
iosta = iosta & ~IOS_PNT; /* clear flag */
lpt_spc = 0; } /* state = print */
else return (stop_inst << IOT_V_REASON) | dat; /* not implemented */
if (GEN_CPLS (inst)) { /* comp pulse? */
ioc = 0; /* clear flop */
lpt_rpls = 1; } /* request completion */
cpls = cpls | CPLS_LPT; } /* request completion */
else cpls = cpls & ~CPLS_LPT;
sim_activate (&lpt_unit, lpt_unit.wait); /* activate */
return data;
return dat;
}
/* Unit service, printer is in one of three states
lpt_iot = 000 write buffer to file, set state to
lpt_iot = 010 write cr, then write buffer to file
lpt_iot = 02x space command x, then set state to 0
lpt_spc = 000 write buffer to file, set overprint
lpt_iot = 02x space command x, clear overprint
*/
t_stat lpt_svc (UNIT *uptr)
@ -129,30 +136,32 @@ static const char *lpt_cc[] = {
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\f" };
if (cpls & CPLS_LPT) { /* completion pulse? */
ioc = 1; /* restart */
cpls = cpls & ~CPLS_LPT; } /* clr pulse pending */
sbs = sbs | SB_RQ; /* req seq break */
ioc = ioc | lpt_rpls; /* restart */
if (lpt_iot & 020) { /* space? */
if (lpt_spc) { /* space? */
iosta = iosta | IOS_SPC; /* set flag */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
fputs (lpt_cc[lpt_iot & 07], lpt_unit.fileref); /* print cctl */
fputs (lpt_cc[lpt_spc & 07], lpt_unit.fileref); /* print cctl */
if (ferror (lpt_unit.fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
lpt_iot = 0; } /* clear state */
lpt_ovrpr = 0; } /* dont overprint */
else { iosta = iosta | IOS_PNT; /* print */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
if (lpt_iot & 010) fputc ('\r', lpt_unit.fileref);
if (lpt_ovrpr) fputc ('\r', lpt_unit.fileref); /* overprint? */
fputs (lpt_buf, lpt_unit.fileref); /* print buffer */
if (ferror (lpt_unit.fileref)) { /* test error */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
bptr = 0;
lpt_bptr = 0;
for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
lpt_iot = 010; } /* set state */
lpt_ovrpr = 1; } /* set overprint */
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
return SCPE_OK;
}
@ -163,11 +172,12 @@ t_stat lpt_reset (DEVICE *dptr)
{
int32 i;
iosta = iosta & ~(IOS_PNT | IOS_SPC); /* clear flags */
bptr = 0; /* clear buffer ptr */
lpt_bptr = 0; /* clear buffer ptr */
for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
lpt_iot = 0; /* clear state */
lpt_rpls = 0;
lpt_spc = 0; /* clear state */
lpt_ovrpr = 0; /* clear overprint */
cpls = cpls & ~CPLS_LPT;
iosta = iosta & ~(IOS_PNT | IOS_SPC); /* clear flags */
sim_cancel (&lpt_unit); /* deactivate unit */
return SCPE_OK;
}

View file

@ -28,6 +28,7 @@
tti keyboard
tto teleprinter
23-Jul-03 RMS Revised to detect I/O wait hang
25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support
29-Nov-02 RMS Fixed output flag initialization (found by Derek Peschel)
@ -52,16 +53,16 @@
#define TTI 0
#define TTO 1
extern int32 sbs, ioc, iosta, PF, IO, PC;
extern int32 M[];
int32 ptr_rpls = 0, ptr_stopioe = 0, ptr_state = 0;
int32 ptp_rpls = 0, ptp_stopioe = 0;
int32 ptr_state = 0;
int32 ptr_stopioe = 0;
int32 ptp_stopioe = 0;
int32 tti_hold = 0; /* tti hold buf */
int32 tto_rpls = 0; /* tto restart */
int32 tty_buf = 0; /* tty buffer */
int32 tty_uc = 0; /* tty uc/lc */
extern int32 sbs, ioc, cpls, iosta, PF, IO, PC;
extern int32 M[];
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat tti_svc (UNIT *uptr);
@ -123,7 +124,7 @@ UNIT ptr_unit = {
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 18) },
{ FLDATA (DONE, iosta, IOS_V_PTR) },
{ FLDATA (RPLS, ptr_rpls, 0) },
{ FLDATA (RPLS, cpls, CPLS_V_PTR) },
{ ORDATA (STATE, ptr_state, 5), REG_HRO },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
@ -150,7 +151,7 @@ UNIT ptp_unit = {
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (DONE, iosta, IOS_V_PTP) },
{ FLDATA (RPLS, ptp_rpls, 0) },
{ FLDATA (RPLS, cpls, CPLS_V_PTP) },
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
@ -177,7 +178,7 @@ UNIT tty_unit[] = {
REG tty_reg[] = {
{ ORDATA (BUF, tty_buf, 6) },
{ FLDATA (UC, tty_uc, UC_V) },
{ FLDATA (RPLS, tto_rpls, 0) },
{ 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 },
@ -196,18 +197,18 @@ DEVICE tty_dev = {
/* Paper tape reader: IOT routine */
int32 ptr (int32 inst, int32 dev, int32 data)
int32 ptr (int32 inst, int32 dev, int32 dat)
{
iosta = iosta & ~IOS_PTR; /* clear flag */
if (dev == 0030) return ptr_unit.buf; /* RRB */
ptr_state = (dev == 0002)? 18: 0; /* mode = bin/alp */
ptr_rpls = 0;
ptr_unit.buf = 0; /* clear buffer */
sim_activate (&ptr_unit, ptr_unit.wait);
if (GEN_CPLS (inst)) { /* comp pulse? */
ioc = 0;
ptr_rpls = 1; }
return data;
cpls = cpls | CPLS_PTR; }
else cpls = cpls & ~CPLS_PTR;
sim_activate (&ptr_unit, ptr_unit.wait);
return dat;
}
/* Unit service */
@ -231,10 +232,12 @@ else if (temp & 0200) { /* binary */
ptr_state = ptr_state - 6;
ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); }
if (ptr_state == 0) { /* done? */
if (ptr_rpls) IO = ptr_unit.buf; /* restart? fill IO */
if (cpls & CPLS_PTR) { /* completion pulse? */
IO = ptr_unit.buf; /* fill IO */
ioc = 1; /* restart */
cpls = cpls & ~CPLS_PTR; }
iosta = iosta | IOS_PTR; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
ioc = ioc | ptr_rpls; } /* restart */
sbs = sbs | SB_RQ; } /* req seq break */
else sim_activate (&ptr_unit, ptr_unit.wait); /* get next char */
return SCPE_OK;
}
@ -245,7 +248,7 @@ t_stat ptr_reset (DEVICE *dptr)
{
ptr_state = 0; /* clear state */
ptr_unit.buf = 0;
ptr_rpls = 0;
cpls = cpls & ~CPLS_PTR;
iosta = iosta & ~IOS_PTR; /* clear flag */
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
@ -253,48 +256,61 @@ return SCPE_OK;
/* Bootstrap routine */
#define BOOT_START 07772
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
int32 ptr_getw (UNIT *uptr)
{
int32 i, tmp, word;
static const int32 boot_rom[] = {
0730002, /* r, rpb + wait */
0327776, /* dio x */
0107776, /* xct x */
0730002, /* rpb + wait */
0760400, /* x, halt */
0607772 /* jmp r */
};
for (i = word = 0; i < 3;) {
if ((tmp = getc (uptr->fileref)) == EOF) return -1;
uptr->pos = uptr->pos + 1;
if (tmp & 0200) {
word = (word << 6) | (tmp & 077);
i++; } }
return word;
}
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
int32 i;
int32 origin, val;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
PC = BOOT_START;
return SCPE_OK;
for (;;) {
if ((val = ptr_getw (&ptr_unit)) < 0) return SCPE_FMT;
if (((val & 0760000) == OP_DIO) || /* DIO? */
((val & 0760000) == OP_DAC)) { /* hack - Macro1 err */
origin = val & 07777;
if ((val = ptr_getw (&ptr_unit)) < 0) return SCPE_FMT;
M[origin] = val; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */
PC = val & 007777;
break; }
else return SCPE_FMT; /* bad instr */
}
return SCPE_OK; /* done */
}
/* Paper tape punch: IOT routine */
int32 ptp (int32 inst, int32 dev, int32 data)
int32 ptp (int32 inst, int32 dev, int32 dat)
{
iosta = iosta & ~IOS_PTP; /* clear flag */
ptp_rpls = 0;
ptp_unit.buf = (dev == 0006)? ((data >> 12) | 0200): (data & 0377);
sim_activate (&ptp_unit, ptp_unit.wait); /* start unit */
ptp_unit.buf = (dev == 0006)? ((dat >> 12) | 0200): (dat & 0377);
if (GEN_CPLS (inst)) { /* comp pulse? */
ioc = 0;
ptp_rpls = 1; }
return data;
cpls = cpls | CPLS_PTP; }
else cpls = cpls & ~CPLS_PTP;
sim_activate (&ptp_unit, ptp_unit.wait); /* start unit */
return dat;
}
/* Unit service */
t_stat ptp_svc (UNIT *uptr)
{
if (cpls & CPLS_PTP) { /* completion pulse? */
ioc = 1; /* restart */
cpls = cpls & ~CPLS_PTP; }
iosta = iosta | IOS_PTP; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
ioc = ioc | ptp_rpls; /* process restart */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */
@ -310,7 +326,7 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0; /* clear state */
ptp_rpls = 0;
cpls = cpls & ~CPLS_PTP;
iosta = iosta & ~IOS_PTP; /* clear flag */
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
@ -318,7 +334,7 @@ return SCPE_OK;
/* Typewriter IOT routines */
int32 tti (int32 inst, int32 dev, int32 data)
int32 tti (int32 inst, int32 dev, int32 dat)
{
iosta = iosta & ~IOS_TTI; /* clear flag */
if (inst & (IO_WAIT | IO_CPLS)) /* wait or sync? */
@ -326,16 +342,16 @@ if (inst & (IO_WAIT | IO_CPLS)) /* wait or sync? */
return tty_buf & 077;
}
int32 tto (int32 inst, int32 dev, int32 data)
int32 tto (int32 inst, int32 dev, int32 dat)
{
iosta = iosta & ~IOS_TTO; /* clear flag */
tto_rpls = 0;
tty_buf = data & TT_WIDTH; /* load buffer */
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); /* activate unit */
tty_buf = dat & TT_WIDTH; /* load buffer */
if (GEN_CPLS (inst)) { /* comp pulse? */
ioc = 0;
tto_rpls = 1; }
return data;
cpls = cpls | CPLS_TTO; }
else cpls = cpls & ~CPLS_TTO;
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); /* activate unit */
return dat;
}
/* Unit service routines */
@ -373,9 +389,11 @@ t_stat tto_svc (UNIT *uptr)
{
int32 out;
if (cpls & CPLS_TTO) { /* completion pulse? */
ioc = 1; /* restart */
cpls = cpls & ~CPLS_TTO; }
iosta = iosta | IOS_TTO; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
ioc = ioc | tto_rpls; /* process restart */
if (tty_buf == FIODEC_UC) { /* upper case? */
tty_uc = UC;
return SCPE_OK; }
@ -399,7 +417,7 @@ t_stat tty_reset (DEVICE *dptr)
tty_buf = 0; /* clear buffer */
tty_uc = 0; /* clear case */
tti_hold = 0; /* clear hold buf */
tto_rpls = 0; /* clear reset pulse */
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 */

View file

@ -23,6 +23,7 @@
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.
22-Jul-03 RMS Updated for "hardware" RIM loader
05-Dec-02 RMS Added drum support
21-Nov-02 RMS Changed typewriter to half duplex
20-Aug-02 RMS Added DECtape support
@ -52,6 +53,7 @@ extern int32 M[];
extern int32 PC;
extern int32 ascii_to_fiodec[], fiodec_to_ascii[];
extern int32 sc_map[];
extern int32 sim_switches;
/* SCP data structures and interface routines
@ -86,44 +88,83 @@ const char *sim_stop_messages[] = {
"Breakpoint",
"Nested XCT's",
"Nested indirect addresses",
"Infinite wait state" };
"Infinite I/O wait state" };
/* Binary loader
/* Binary loader - supports both RIM format and Macro block format */
At the moment, implements RIM loader format
*/
int32 getword (FILE *fileref)
int32 getw (FILE *inf)
{
int32 i, tmp, word;
word = 0;
for (i = 0; i < 3;) {
if ((tmp = getc (fileref)) == EOF) return -1;
if ((tmp = getc (inf)) == EOF) return -1;
if (tmp & 0200) {
word = (word << 6) | (tmp & 077);
i++; } }
return word;
}
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
t_stat rim_load (FILE *inf)
{
int32 origin, val;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
for (;;) {
if ((val = getword (fileref)) < 0) return SCPE_FMT;
if (((val & 0770000) == 0320000) || /* DIO? */
((val & 0770000) == 0240000)) { /* DAC? - incorrect */
if ((val = getw (inf)) < 0) return SCPE_FMT;
if (((val & 0760000) == OP_DIO) || /* DIO? */
((val & 0760000) == OP_DAC)) { /* hack - Macro1 err */
origin = val & 07777;
if ((val = getword (fileref)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
else if ((val & 0770000) == 0600000) { /* JMP? */
if ((val = getw (inf)) < 0) return SCPE_FMT;
M[origin] = val; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */
PC = val & 007777;
break; }
else return SCPE_FMT; /* bad instr */
}
return SCPE_OK; /* done */
}
t_stat blk_load (FILE *inf)
{
int32 val, start, count, csum;
for (;;) {
if ((val = getw (inf)) < 0) return SCPE_FMT; /* get word, EOF? */
if ((val & 0760000) == OP_DIO) { /* DIO? */
csum = val; /* init checksum */
start = val & 07777; /* starting addr */
if ((val = 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 & 07777) - start + 1; /* block count */
if (count <= 0) return SCPE_FMT;
while (count--) { /* loop on data */
if ((val = getw (inf)) < 0) return SCPE_FMT;
csum = csum + val;
if (csum > 0777777) csum = (csum + 1) & 0777777;
M[start++] = val; }
if ((val = getw (inf)) < 0) return SCPE_FMT;
if (val != csum) return SCPE_CSUM; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */
PC = val & 007777;
break; }
else return SCPE_FMT; /* bad instr */
}
return SCPE_OK; /* done */
}
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
t_stat sta;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
sta = rim_load (fileref);
if (sta != SCPE_OK) return sta;
if ((sim_switches & SWMASK ('B')) || match_ext (fnam, "BIN"))
return blk_load (fileref);
return SCPE_OK;
}
/* Symbol tables */

View file

@ -40,15 +40,17 @@ To compile the PDP-10, you must define VM_PDP10 and USE_INT64 as part of the
compilation command line.
sim/ sim_defs.h
sim_ether.h
sim_rev.h
sim_sock.h
sim_tape.h
sim_tmxr.h
sim_ether.h
scp.c
scp_tty.c
sim_sock.c
sim_tmxr.c
sim_ether.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/pdp10/ pdp10_defs.h
pdp10_cpu.c
@ -117,11 +119,14 @@ the file format to try to determine the file type.
The CPU options allow the user to specify standard microcode, standard
microcode with a bug fix for a boostrap problem in TOPS-20 V4.1, or ITS
microcode
microcode:
SET CPU STANDARD Standard microcode
SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix
SET CPU ITS ITS compatible microcode
The CPU implements a SHOW command to display the I/O space address map:
SHOW CPU IOSPACE show I/O space address map
CPU registers include the visible state of the processor as well as the
@ -200,7 +205,7 @@ The front end is the system console. The keyboard input is unit 0,
the console output is unit 1. It supports two options:
SET FE STOP halts the PDP-10 operating system
SET FE CTLC simulates typing ^C (for Windoze)
SET FE CTLC simulates typing ^C
The front end has the following registers:
@ -333,7 +338,10 @@ the port to be used:
where port is a decimal number between 1 and 65535 that is not being used
for other TCP/IP activities. The optional switch -m turns on the DZ11's
modem controls; the optional switch -a turns on active disconnects
(disconnect session if computer clears Data Terminal Ready).
(disconnect session if computer clears Data Terminal Ready). Without
modem control, the DZ behaves as though terminals were directly connected;
disconnecting the Telnet session does not cause any operating system-
visible change in line status.
Once the DZ is attached and the simulator is running, the DZ will listen
for connections on the specified port. It assumes that the incoming
@ -526,8 +534,6 @@ locked, single or double density, or autosized:
SET RYn DOUBLE set unit n double density (default)
SET RYn AUTOSIZE set unit n autosized
The RX211 supports the BOOT command, but only for double density.
The floppy disk requires an unsupported driver under TOPS-10 and
is not supported under TOPS-20 or ITS.

View file

@ -25,6 +25,7 @@
rp RH/RP/RM moving head disks
23-Jul-03 RMS Fixed bug in read header stub
25-Apr-03 RMS Revised for extended file support
21-Nov-02 RMS Fixed bug in bootstrap (reported by Michael Thompson)
29-Sep-02 RMS Added variable vector support
@ -834,14 +835,14 @@ case FNC_READH: /* read headers */
vpn = PAG_GETVPN (pa10); /* map addr */
if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || (rpwc & XWC_MBZ) ||
((ubmap[0][vpn] & (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != UMAP_VLD)) {
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
mpa10 = (ubmap[0][vpn] + PAG_GETOFF (pa10)) & PAMASK;
if (MEM_ADDR_NXM (mpa10)) { /* nx memory? */
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
dbuf[twc10] = M[mpa10]; /* write to disk */
if ((rpcs2 & CS2_UAI) == 0) ba = ba + 4; }
if (fc10 = twc10 & (RP_NUMWD - 1)) { /* fill? */
@ -850,7 +851,7 @@ case FNC_READH: /* read headers */
fxwrite (dbuf, sizeof (d10), twc10 + fc10, uptr->fileref);
err = ferror (uptr->fileref);
} /* end if */
else { /* read, wchk */
else { /* read, wchk, readh */
awc10 = fxread (dbuf, sizeof (d10), wc10, uptr->fileref);
err = ferror (uptr->fileref);
for ( ; awc10 < wc10; awc10++) dbuf[awc10] = 0;
@ -859,18 +860,20 @@ case FNC_READH: /* read headers */
vpn = PAG_GETVPN (pa10); /* map addr */
if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || (rpwc & XWC_MBZ) ||
((ubmap[0][vpn] & (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != UMAP_VLD)) {
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
mpa10 = (ubmap[0][vpn] + PAG_GETOFF (pa10)) & PAMASK;
if (MEM_ADDR_NXM (mpa10)) { /* nx memory? */
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
if (uptr->FUNC == FNC_READ) M[mpa10] = dbuf[twc10];
else if (M[mpa10] != dbuf[twc10]) {
rpcs2 = rpcs2 | CS2_WCE; /* set error */
break; }
rpcs2 = rpcs2 | CS2_NEM; /* set error */
ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */
break; }
if ((uptr->FUNC == FNC_READ) || /* read or */
(uptr->FUNC == FNC_READH)) /* read header */
M[mpa10] = dbuf[twc10];
else if (M[mpa10] != dbuf[twc10]) { /* wchk, mismatch? */
rpcs2 = rpcs2 | CS2_WCE; /* set error */
break; }
if ((rpcs2 & CS2_UAI) == 0) ba = ba + 4; }
} /* end else */

View file

@ -678,7 +678,7 @@ if (trap_req) { /* check traps, ints */
if (t = trap_req & TRAP_ALL) { /* if a trap */
for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) {
if ((t >> trapnum) & 1) { /* trap set? */
trapea = trap_vec[trapnum]; /* get vec, clr */
trapea = trap_vec[trapnum]; /* get vec, clr */
trap_req = trap_req & ~trap_clear[trapnum];
if ((stop_trap >> trapnum) & 1) /* stop on trap? */
reason = trapnum + 1;
@ -785,7 +785,7 @@ case 000:
setCPUERR (CPUE_HALT); }
break;
case 1: /* WAIT */
if (cm == MD_KER && wait_enable) wait_state = 1;
if ((cm == MD_KER) && wait_enable) wait_state = 1;
break;
case 3: /* BPT */
setTRAP (TRAP_BPT);
@ -838,8 +838,8 @@ case 000:
if ((IR == 000002) && tbit) setTRAP (TRAP_TRC);
break;
case 7: /* MFPT */
R[0] = 5; /* report J-11 */
break; } /* end switch no ops */
R[0] = 5; /* report J-11 */
break; } /* end switch no ops */
break; /* end case no ops */
/* Opcode 0: specials, continued */
@ -1378,7 +1378,7 @@ case 007:
case 5: /* FIS - not impl */
setTRAP (TRAP_ILL);
break;
case 6: /* CIS - not impl */
case 6: /* CIS */
if (cpu_unit.flags & UNIT_CIS) cis11 (IR);
else setTRAP (TRAP_ILL);
break;

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: PDP-11 Simulator Usage
Date: 15-Mar-2003
Date: 15-Jul-2003
COPYRIGHT NOTICE
@ -40,11 +40,13 @@ sim/ sim_defs.h
sim_ether.h
sim_rev.h
sim_sock.h
sim_tape.h
sim_tmxr.h
scp.c
scp_tty.c
sim_ether.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/pdp11/ pdp11_defs.h
@ -154,6 +156,9 @@ with RH70-style controllers, 22b Unibus with RH11 style controllers, and
SET CPU 2048K (or 2M) set memory size = 2048KB
SET CPU 3072K (or 3M) set memory size = 3072KB
SET CPU 4096K (or 4M) set memory size = 4096KB
The CPU implements a show command to display the I/O address space map:
SHOW CPU IOSPACE show I/O space address map
If memory size is being reduced, and the memory being truncated contains
@ -486,7 +491,7 @@ clock is disabled by default.
The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines)
are supported. The number of lines can be changed with the command
SET DZ LINES=n set line count to n
SET DZ LINES=n set line count to n
The line count must be a multiple of 8, with a maximum of 32.
@ -501,12 +506,15 @@ The terminal lines perform input and output through Telnet sessions
connected to a user-specified port. The ATTACH command specifies
the port to be used:
ATTACH {-am} DZ <port> set up listening port
ATTACH {-am} DZ <port> set up listening port
where port is a decimal number between 1 and 65535 that is not being used
for other TCP/IP activities. The optional switch -m turns on the DZ11's
modem controls; the optional switch -a turns on active disconnects
(disconnect session if computer clears Data Terminal Ready).
(disconnect session if computer clears Data Terminal Ready). Without
modem control, the DZ behaves as though terminals were directly connected;
disconnecting the Telnet session does not cause any operating system-
visible change in line status.
Once the DZ is attached and the simulator is running, the DZ will listen
for connections on the specified port. It assumes that the incoming
@ -876,6 +884,10 @@ of many disk types:
SET RQn RAUSER{=n} set type to RA81 with n LBNs
The type options can be used only when a unit is not attached to a file.
RAUSER is a "user specified" disk; the user can specify the size of the
disk in logical block numbers (LBN's, 512 bytes each). The minimum size
is 50MB; the maximum size is 2GB.
Units can also be set ONLINE or OFFLINE. Each RQ controller supports the
BOOT command. In a Unibus system, an RQ supports 18b addressing. In
a Qbus (22B) system, an RQ supports 22b addressing.
@ -928,13 +940,13 @@ crash on boot or to hang during operation.
Error handling is as follows:
error processed as
error processed as
not attached disk not ready
not attached disk not ready
end of file assume rest of disk is zero
end of file assume rest of disk is zero
OS I/O error report error and stop
OS I/O error report error and stop
2.8 TC11/TU56 DECtape (DT)
@ -1227,18 +1239,18 @@ controller will behave as though the ethernet cable were unplugged.
XQ has the following registers:
name size comments
name size comments
SA0 16 station address word 0
SA1 16 station address word 1
SA2 16 station address word 2
SA3 16 station address word 3
SA4 16 station address word 4
SA5 16 station address word 5
CSR 16 control status register
VAR 16 vector address register
RBDL 32 receive buffer descriptor list
XBDL 32 trans(X)mit buffer descriptorlList
SA0 16 station address word 0
SA1 16 station address word 1
SA2 16 station address word 2
SA3 16 station address word 3
SA4 16 station address word 4
SA5 16 station address word 5
CSR 16 control status register
VAR 16 vector address register
RBDL 32 receive buffer descriptor list
XBDL 32 trans(X)mit buffer descriptorlList
One final note: because of it's asynchronous nature, the XQ controller is
not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers,

View file

@ -26,6 +26,7 @@
rq RQDX3 disk controller
11-Jul-03 RMS Fixed bug in user disk size (found by Chaskiel M Grundman)
19-May-03 RMS Revised for new conditional compilation scheme
25-Apr-03 RMS Revised for extended file support
14-Mar-03 RMS Fixed variable size interaction with save/restore
@ -2009,7 +2010,7 @@ if ((val < 0) || (val > RA8U_DTYPE) || ((val != RA8U_DTYPE) && cptr))
return SCPE_ARG;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
if (cptr) {
cap = (int32) get_uint (cptr, 10, RA8U_MAXC, &r);
cap = (int32) get_uint (cptr, 10, max, &r);
if ((r != SCPE_OK) || (cap < RA8U_MINC)) return SCPE_ARG;
drv_tab[val].lbn = cap << (20 - 9); }
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (val << UNIT_V_DTYPE);

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,9 @@
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.
18-Jul-03 RMS Added FP15 support
Added XVM support
Added EAE option for PDP-4
25-Apr-03 RMS Revised for extended file support
04-Feb-03 RMS Added RB09, LP09 support
22-Nov-02 RMS Added PDP-4 drum support
@ -48,7 +51,7 @@
model memory CPU options I/O options
PDP4 8K ??Type 18 EAE Type 65 KSR-28 Teletype (Baudot)
PDP4 8K Type 18 EAE Type 65 KSR-28 Teletype (Baudot)
integral paper tape reader
Type 75 paper tape punch
integral real time clock
@ -79,19 +82,19 @@
KA15 auto pri intr PC15 paper tape reader and punch
KF15 power detection KW15 real time clock
KM15 mem protection LP09 line printer
??KT15 mem relocation LP15 line printer
RP15 disk pack
RF15/RF09 fixed head disk
KT15 mem relocation LP15 line printer
FP15 floating point RP15 disk pack
XVM option RF15/RF09 fixed head disk
TC59D magnetic tape
TC15/TU56 DECtape
LT15 second Teletype
??Indicates not implemented. The PDP-4 manual refers to both an EAE
??and a memory extension control; there is no documentation on either.
??Indicates not implemented. The PDP-4 manual refers to a memory
??extension control; there is no documentation on it.
*/
#if !defined (PDP4) && !defined (PDP7) && !defined (PDP9) && !defined (PDP15)
#define PDP9 0 /* default to PDP-9 */
#define PDP15 0 /* default to PDP-15 */
#endif
/* Simulator stop codes */
@ -102,6 +105,7 @@
#define STOP_XCT 4 /* nested XCT's */
#define STOP_API 5 /* invalid API int */
#define STOP_NONSTD 6 /* non-std dev num */
#define STOP_MME 7 /* mem mgt error */
/* Peripheral configuration */
@ -136,17 +140,49 @@
#define TC02 0 /* DECtape */
#define TTY1 0 /* second Teletype */
#define BRMASK 0377400 /* bounds mask */
#define BRMASK_XVM 0777400 /* bounds mask, XVM */
#endif
/* Memory */
#define ADDRMASK ((1 << ADDRSIZE) - 1) /* address mask */
#define AMASK ((1 << ADDRSIZE) - 1) /* address mask */
#define IAMASK 077777 /* ind address mask */
#define BLKMASK (ADDRMASK & (~IAMASK)) /* block mask */
#define BLKMASK (AMASK & (~IAMASK)) /* block mask */
#define MAXMEMSIZE (1 << ADDRSIZE) /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
/* Instructions */
#define I_V_OP 14 /* opcode */
#define I_M_OP 017
#define I_V_IND 13 /* indirect */
#define I_V_IDX 12 /* index */
#define I_IND (1 << I_V_IND)
#define I_IDX (1 << I_V_IDX)
#define B_DAMASK 017777 /* bank mode address */
#define B_EPCMASK (AMASK & ~B_DAMASK)
#define P_DAMASK 007777 /* page mode address */
#define P_EPCMASK (AMASK & ~P_DAMASK)
/* Memory cycles */
#define FE 0
#define DF 1
#define RD 2
#define WR 3
/* Memory status codes */
#define MM_OK 0
#define MM_ERR 1
/* Memory management relocation checks (PDP-15 KT15 and XVM only) */
#define REL_C -1 /* console */
#define REL_R 0 /* read */
#define REL_W 1 /* write */
/* Architectural constants */
#define DMASK 0777777 /* data mask */
@ -165,6 +201,39 @@
#define IOT_REASON (1 << IOT_V_REASON)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* PC change 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] = PC
/* XVM memory management registers */
#define MM_RDIS 0400000 /* reloc disabled */
#define MM_V_GM 15 /* G mode */
#define MM_M_GM 03
#define MM_GM (MM_M_GM << MM_V_GM)
#define MM_G_W0 0077777 /* virt addr width */
#define MM_G_W1 0177777
#define MM_G_W2 0777777
#define MM_G_W3 0377777
#define MM_G_B0 0060000 /* SAS base */
#define MM_G_B1 0160000
#define MM_G_B2 0760000
#define MM_G_B3 0360000
#define MM_UIOT 0040000 /* user mode IOT's */
#define MM_WP 0020000 /* share write prot */
#define MM_SH 0010000 /* share enabled */
#define MM_V_SLR 10 /* segment length reg */
#define MM_M_SLR 03
#define MM_SLR_L0 001000 /* SAS length */
#define MM_SLR_L1 002000
#define MM_SLR_L2 010000
#define MM_SLR_L3 020000
#define MM_SBR_MASK 01777 /* share base reg */
#define MM_GETGM(x) (((x) >> MM_V_GM) & MM_M_GM)
#define MM_GETSLR(x) (((x) >> MM_V_SLR) & MM_M_SLR)
/* Device information block */
@ -239,6 +308,15 @@ typedef struct pdp18b_dib DIB;
37 -
*/
#define API_ML0 0200 /* API masks: level 0 */
#define API_ML1 0100
#define API_ML2 0040
#define API_ML3 0020
#define API_ML4 0010
#define API_ML5 0004
#define API_ML6 0002
#define API_ML7 0001 /* level 7 */
#define API_HLVL 4 /* hwre levels */
#define ACH_SWRE 040 /* swre int vec */

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: 18b PDP Simulator Usage
Date: 01-Feb-2003
Date: 25-Jul-2003
COPYRIGHT NOTICE
@ -44,29 +44,33 @@ PDP-7/ PDP7
PDP-9/ PDP9
PDP-15/ PDP15
If no model is specified, the default is the PDP-9.
If no model is specified, the default is the PDP-15.
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tmxr.h
scp.c
scp_tty.c
sim_sock.c
sim_tmxr.c
PDP-4 PDP-7 PDP-9 PDP-15
sim/ sim_defs.h x x x x
sim_rev.h x x x x
sim_sock.h x x x x
sim_tape.h x x
sim_tmxr.h x x x x
scp.c x x x x
scp_tty.c x x x x
sim_sock.c x x x x
sim_tape.c x x
sim_tmxr.c x x x x
sim/pdp18b/ pdp18b_defs.h
pdp18b_cpu.c
pdp18b_drm.c
pdp18b_dt.c
pdp18b_lp.c
pdp18b_mt.c
pdp18b_rb.c
pdp18b_rf.c
pdp18b_rp.c
pdp18b_stddev.c
pdp18b_sys.c
pdp18b_tt1.c
sim/pdp18b/ pdp18b_defs.h x x x x
pdp18b_cpu.c x x x x
pdp18b_drm.c x x
pdp18b_dt.c x x x x
pdp18b_fpp.c x
pdp18b_lp.c x x x x
pdp18b_mt.c x x
pdp18b_rb.c x
pdp18b_rf.c x x
pdp18b_rp.c x
pdp18b_stddev.c x x x x
pdp18b_sys.c x x x x
pdp18b_tt1.c x x
2. 18b PDP Features
@ -77,6 +81,7 @@ system device simulates
name(s)
PDP-4 CPU PDP-4 CPU with 8KW of memory
- Type 18 extended arithmetic element (EAE)
PTR,PTP integral paper tape/Type 75 punch
TTI,TTO KSR28 console terminal (Baudot code)
LPT Type 62 line printer (Hollerith code)
@ -116,6 +121,9 @@ PDP-15 CPU PDP-15 CPU with 32KW of memory
- KA15 automatic priority interrupt (API)
- KF15 power detection
- KM15 memory protection
- KT15 memory relocation and protection
- XVM memory relocation and protection
FPP FP15 floating point processor
PTR,PTP PC15 paper tape reader/punch
TTI,TTO KSR 35 console terminal
TTI1,TTO1 LT15 second console terminal
@ -145,36 +153,58 @@ The 18b PDP simulators implement several unique stop conditions:
- more than XCTMAX nested executes are detected during
instruction execution
The PDP-4 and PDP-7 loaders support only RIM format tapes. The PDP-9
and PDP-15 support both RIM and BIN format tapes. If the file extension
is .RIM, or the -r switch is specified with LOAD, the file is assumed to
be RIM format; if the file extension is not .RIM, or if the -b switch is
specified, the file is assumed to be BIN format. RIM loading requires
that the loading address be specified on the command line.
The PDP-4 and PDP-7 LOAD command supports only "second stage" RIM format
files (alternating DAC address instructions and data):
LOAD file load PDP-4/PDP-7 RIM format file
The PDP-9 and PDP-15 LOAD commands upports hardware RIM format (data only),
PDP-4/PDP-7 RIM loader format (for compatability with Macro7), and BIN
loader format:
LOAD -S file load PDP-4/PDP-7 RIM format file
LOAD -R file address load PDP-9/PDP-15 RIM format
file starting at address
LOAD file.RIM address assume file is PDP-9/PDP-15
RIM format
LOAD -B file load PDP-9/PDP-15 BIN format file
LOAD file.BIN assume file is PDP-9/PDP-15
BIN format
If no address is given for a RIM format load, a starting address of 200
(octal) is assumed. If no switch is specified, and the file extension is
neither RIM nor BIN, the file format is assumed to be BIN.
2.1 CPU
The CPU options are the presence of the EAE, the presense of the API (for
the PDP-9 and PDP-15), and the size of main memory.
The CPU options are the presence of the EAE, the presense of the API and
memory protection (for the PDP-9 and PDP-15), the presense of relocation
or XVM (PDP-15 only), and the size of main memory.
SET CPU EAE enable EAE
SET CPU NOEAE disable EAE
SET CPU API enable API
SET CPU NOAPI disable API
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 12K set memory size = 12K
SET CPU 16K set memory size = 16K
SET CPU 20K set memory size = 20K
SET CPU 24K set memory size = 24K
SET CPU 28K set memory size = 28K
SET CPU 32K set memory size = 32K
SET CPU 48K set memory size = 48K
SET CPU 64K set memory size = 64K
SET CPU 80K set memory size = 80K
SET CPU 96K set memory size = 96K
SET CPU 112K set memory size = 112K
SET CPU 128K set memory size = 128K
system option comment
all SET CPU EAE enable EAE
all SET CPU NOEAE disable EAE
9,15 SET CPU API enable API
9,15 SET CPU NOAPI disable API
9,15 SET CPU PROT enable memory protection
15 SET CPU RELOC enable memory relocation
15 SET CPU XVM enable XVM relocation
9,15 SET CPU NOPROT disable protection, relocation, XVM
4 SET CPU 4K set memory size = 4K
all SET CPU 8K set memory size = 8K
all SET CPU 12K set memory size = 12K
all SET CPU 16K set memory size = 16K
all SET CPU 20K set memory size = 20K
all SET CPU 24K set memory size = 24K
all SET CPU 28K set memory size = 28K
all SET CPU 32K set memory size = 32K
15 SET CPU 48K set memory size = 48K
15 SET CPU 64K set memory size = 64K
15 SET CPU 80K set memory size = 80K
15 SET CPU 96K set memory size = 96K
15 SET CPU 112K set memory size = 112K
15 SET CPU 128K set memory size = 128K
Memory sizes greater than 8K are only available on the PDP-7, PDP-9, and
PDP-15; memory sizes greater than 32KW are only available on the PDP-15.
@ -183,6 +213,12 @@ non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 8K for the PDP-4, 32K
for the PDP-7 and PDP-9, and 128K for the PDP-15.
The PROT option corresponds to the KX09A on the PDP-9 and the KM15 for the
PDP-15. The PROT option is required to run the Foreground/Background
Monitor. The RELOC option corresponds to the KT15 on the PDP-15, and the
XVM option corresponds to the XM15 on the PDP-15. ADSS-15, ADSS-15 Foreground/
Background, and standard DOS-15 will <not> run if these options are enabled.
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
@ -191,10 +227,11 @@ control registers for the interrupt system.
all PC addr program counter
all AC 18 accumulator
all L 1 link
7,9,15 MQ 18 multiplier-quotient
7,9,15 SC 6 shift counter
7,9,15 EAE_AC_SIGN 1 EAE AC sign
all MQ 18 multiplier-quotient
all SC 6 shift counter
all EAE_AC_SIGN 1 EAE AC sign
all SR 18 front panel switches
all ASW addr address switches for RIM load
all INT[0:4] 32 interrupt requests,
0:3 = API levels 0-3
4 = PI level
@ -204,12 +241,15 @@ control registers for the interrupt system.
9,15 APIENB 1 API enable
9,15 APIREQ 8 API requesting levels
9,15 APIACT 8 API active levels
9,15 BR addr memory protection bounds
9,15 BR 18 memory protection bounds
15 XR 18 index register
15 LR 18 limit register
15 BR 17 memory protection bounds
9,15 BR 18 memory protection bounds
15 RR 18 memory protection relocation
15 MMR 18 memory protection control
9,15 USMD 1 user mode
9,15 USMDBUF 1 user mode buffer
9,15 USMDDEF 1 user mode load defer
9,15 NEXM 1 non-existent memory violation
9,15 PRVN 1 privilege violation
7,9 EXTM 1 extend mode
@ -229,18 +269,49 @@ control registers for the interrupt system.
"addr" signifies the address width of the system (13b for the PDP-4, 15b for
the PDP-7 and PDP-9, 17b for the PDP-15).
2.2 Programmed I/O Devices
2.2 Floating Point Processor (FPP)
2.2.1 Paper Tape Reader (PTR)
The PDP-15 features an optional floating point processor, the FP15 (FPP).
The FPP can be enabled and disabled; by default it is disabled.
The FPP implements these registers:
name size comments
FIR 12 floating instruction register
EPA 18 EPA (A exponent)
FMAS 1 FMA sign
FMAH 17 FMA<1:17>
FMAL 18 FMA<18:35>
EPB 18 EPB (B exponent)
FMBS 1 FMB sign
FMBH 17 FMB<1:17>
FMBL 18 FMB<18:35>
FGUARD 1 guard bit
FMQH 17 FMQ<1:17>
FMQL 18 FMQ<18:35>
JEA 18 exception address register
2.3 Programmed I/O Devices
2.3.1 Paper Tape Reader (PTR)
The paper tape reader (PTR) reads data from a disk file. The POS
register specifies the number of the next data item to be read. Thus,
by changing POS, the user can backspace or advance the reader.
On the PDP-4 and PDP-7, the paper tape reader supports the BOOT command.
BOOT PTR copies the RIM loader into memory and starts it running, while
BOOT -F PTR copies the funny format binary loader into memory and starts
it running.
The paper tape reader supports the BOOT command. The specific forms
recognized vary from system to system:
BOOT PTR PDP-4, PDP-7: load RIM loader and start it running
BOOT -F PTR PDP-4, PDP-7: load funny format loader and start
it running
BOOT -H PTR PDP-7: start hardware RIM load at address given
by address switches (ASW)
BOOT {-H} PTR PDP-9, PDP-15: start hardware RIM load at addrss
given by address switches (ASW)
The PDP-4 did not have a hardware read-in mode load capability.
The PTR ATTACH command recognizes one switch, -A for ASCII mode. In
ASCII mode, data returned by the read alphabetic command has even parity.
@ -270,7 +341,7 @@ Error handling is as follows:
OS I/O error x report error and stop
2.2.2 Paper Tape Punch (PTP)
2.3.2 Paper Tape Punch (PTP)
The paper tape punch (PTP) writes data to a disk file. The POS
register specifies the number of the next data item to be written.
@ -302,7 +373,7 @@ Error handling is as follows:
OS I/O error x report error and stop
2.2.3 Terminal Input (TTI)
2.3.3 Terminal Input (TTI)
On the PDP-7, PDP-9, and PDP-15, the terminal interfaces (TTI, TTO)
can be set to one of three modes: KSR, 7B, or 8B. In KSR mode, lower
@ -333,7 +404,7 @@ to simulate typing ^C:
SET TTI CTRL-C
2.2.4 Terminal Output (TTO)
2.3.4 Terminal Output (TTO)
The terminal output (TTO) writes to the simulator console window. It
implements these registers:
@ -346,7 +417,7 @@ implements these registers:
POS 32 number of chararacters output
TIME 24 time from I/O initiation to interrupt
2.2.5 Line Printers (LPT, LP9)
2.3.5 Line Printers (LPT, LP9)
The line printers (LPT, LP9) write data to a disk file. The POS
register specifies the number of the next data item to be written.
@ -423,7 +494,7 @@ For all printers, error handling is as follows:
OS I/O error x report error and stop
2.2.6 Real-Time Clock (CLK)
2.3.6 Real-Time Clock (CLK)
The real-time clock (CLK) frequency can be adjusted as follows:
@ -444,7 +515,7 @@ The clock implements these registers:
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.2.7 Second Terminal (TTI1, TTO1)
2.3.7 Second Terminal (TTI1, TTO1)
The second terminal consists of two independent devices, TTI1 and TTO1.
The second terminal performs input and output through a Telnet session
@ -491,7 +562,7 @@ The second terminal output implements these registers:
DONE 1 device done flag
TIME 24 time from I/O initiation to interrupt
2.3 RP15/RP02 Disk Pack (RP)
2.4 RP15/RP02 Disk Pack (RP)
RP15 options include the ability to make units write enabled or write locked:
@ -526,7 +597,7 @@ Error handling is as follows:
OS I/O error x report error and stop
2.4 Type 24 Serial Drum (DRM)
2.5 Type 24 Serial Drum (DRM)
The serial drum (DRM) implements these registers:
@ -551,7 +622,7 @@ Error handling is as follows:
Drum data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.5 RB09 Fixed Head Disk (RB)
2.6 RB09 Fixed Head Disk (RB)
The RB09 was an early fixed-head disk for the PDP-9. It was superceded
by the RF09/RS09. It is disabled by default.
@ -585,7 +656,7 @@ Error handling is as follows:
RB09 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.5 RF09/RF15/RS09 Fixed Head Disk (RF)
2.7 RF09/RF15/RS09 Fixed Head Disk (RF)
RF09/RF15 options include the ability to set the number of platters
to a fixed value between 1 and 8, or to autosize the number of platters
@ -632,7 +703,7 @@ Error handling is as follows:
RF15/RF09 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.6 Type 550/555, TC02/TU55, and TC15/TU56 DECtape (DT)
2.8 Type 550/555, TC02/TU55, and TC15/TU56 DECtape (DT)
The PDP-4 and PDP-7 use the Type 550 DECtape, a programmed I/O controller.
The PDP-9 uses the TC02, and the PDP-15 uses the TC15. The TC02 and TC15
@ -693,7 +764,7 @@ operate correctly.
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
2.7 TC59/TU10 Magnetic Tape (MT)
2.9 TC59/TU10 Magnetic Tape (MT)
Magnetic tape options include the ability to make units write enabled or
or write locked.
@ -727,7 +798,7 @@ Error handling is as follows:
OS I/O error parity error; if STOP_IOE, stop
2.8 Symbolic Display and Input
2.10 Symbolic Display and Input
The 18b PDP simulators implement symbolic display and input. Display is
controlled by command line switches:
@ -754,15 +825,18 @@ The PDP-15 also recognizes an additional input mode:
# or -p five character packed ASCII string in
two 18b words
Instruction input uses standard 18b PDP assembler syntax. There are six
Instruction input uses standard 18b PDP assembler syntax. There are eight
instruction classes: memory reference, EAE, index (PDP-15 only), IOT,
operate, and LAW.
operate, LAW, FP15 memory reference (PDP-15 only), and FP15 no operand
(PDP-15 only).
Memory reference instructions have the format
memref {I/@} address{,X}
PDP-4, PDP-7: memref {I} address
PDP-9: memref{*} address
PDP-15: memref{*} address{,X}
where I (PDP-4, PDP-7, PDP-9) /@ (PDP-15) signifies indirect reference,
where I (PDP-4, PDP-7) /* (PDP-9, PDP-15) signifies indirect reference,
and X signifies indexing (PDP-15 in page mode only). The address is an
octal number in the range 0 - 017777 (PDP-4, PDP-7, PDP-9, and PDP-15 in
bank mode) or 0 - 07777 (PDP-15 in page mode).
@ -805,13 +879,27 @@ Operate instructions have the format
The simulator does not check the legality of the proposed combination. The
operands for MUY and DVI must be deposited explicitly.
Finally, the LAW instruction has the format
The LAW instruction has the format
LAW immediate
where immediate is in the range of 0 to 017777.
2.9 Character Sets
FP15 memory reference instructions occupy two successive words and have
the format
fpmem{*} address
where * signifies indirect addressing. The address is a number in the range
0 - 0377777.
FP15 no operand instructions occupy two successive words and have the format
fpop
The second word is ignored on output and set to 0 on input.
2.11 Character Sets
The PDP-4's console was an ASR-28 Teletype; its character encoding was
Baudot. The PDP-4's line printer used a modified Hollerith character

View file

@ -221,10 +221,10 @@ static const int32 boot_rom[] = {
t_stat drm_boot (int32 unitno, DEVICE *dptr)
{
int32 i;
extern int32 saved_PC;
extern int32 PC;
if (drm_dib.dev != DEV_DRM) return STOP_NONSTD; /* non-std addr? */
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;
PC = BOOT_START;
return SCPE_OK;
}

View file

@ -327,8 +327,8 @@ static const int32 map_unit[16] = { /* Type 550 unit map */
0, -1, -1, -1, -1, -1, -1, -1 };
DEVICE dt_dev;
int32 dt75 (int32 pulse, int32 AC);
int32 dt76 (int32 pulse, int32 AC);
int32 dt75 (int32 pulse, int32 dat);
int32 dt76 (int32 pulse, int32 dat);
int32 dt_iors (void);
t_stat dt_svc (UNIT *uptr);
t_stat dt_reset (DEVICE *dptr);
@ -423,18 +423,18 @@ DEVICE dt_dev = {
/* IOT routines */
#if defined (TC02) /* TC02/TC15 */
int32 dt75 (int32 pulse, int32 AC)
int32 dt75 (int32 pulse, int32 dat)
{
int32 old_dtsa = dtsa, fnc;
UNIT *uptr;
if (((pulse & 060) == 040) && (pulse & 05)) { /* select */
if (pulse & 01) dtsa = 0; /* DTCA */
if (pulse & 02) AC = dtsa; /* DTRA!... */
if (pulse & 02) dat = dtsa; /* DTRA!... */
if (pulse & 04) { /* DTXA */
if ((AC & DTA_CERF) == 0) dtsb = dtsb & ~DTB_ALLERR;
if ((AC & DTA_CDTF) == 0) dtsb = dtsb & ~DTB_DTF;
dtsa = dtsa ^ (AC & DTA_RW); }
if ((dat & DTA_CERF) == 0) dtsb = dtsb & ~DTB_ALLERR;
if ((dat & DTA_CDTF) == 0) dtsb = dtsb & ~DTB_DTF;
dtsa = dtsa ^ (dat & DTA_RW); }
if ((old_dtsa ^ dtsa) & DTA_UNIT) dt_deselect (old_dtsa);
uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */
fnc = DTA_GETFNC (dtsa); /* get fnc */
@ -445,41 +445,41 @@ if (((pulse & 060) == 040) && (pulse & 05)) { /* select */
dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); /* new func */
DT_UPDINT;
return AC; }
return dat; }
if ((pulse & 067) == 042) return dtsa; /* DTRA */
if ((pulse & 067) == 061) /* DTEF */
return ((dtsb & DTB_ERF)? IOT_SKP + AC: AC);
return ((dtsb & DTB_ERF)? IOT_SKP + dat: dat);
if ((pulse & 067) == 062) return dtsb; /* DTRB */
if ((pulse & 067) == 063) /* DTEF!DTRB */
return ((dtsb & DTB_ERF)? IOT_SKP + dtsb: dtsb);
return AC;
return dat;
}
int32 dt76 (int32 pulse, int32 AC)
int32 dt76 (int32 pulse, int32 dat)
{
if ((pulse & 01) && (dtsb & DTB_DTF)) /* DTDF */
return IOT_SKP + AC;
return AC;
return IOT_SKP + dat;
return dat;
}
#else /* Type 550 */
int32 dt75 (int32 pulse, int32 AC)
int32 dt75 (int32 pulse, int32 dat)
{
if (((pulse & 041) == 001) && (dtsb & DTB_DTF)) /* MMDF */
AC = AC | IOT_SKP;
dat = dat | IOT_SKP;
else if (((pulse & 041) == 041) && (dtsb & DTB_ERF)) /* MMEF */
AC = AC | IOT_SKP;
dat = dat | IOT_SKP;
if (pulse & 002) { /* MMRD */
AC = (AC & ~DMASK) | dtdb;
dat = (dat & ~DMASK) | dtdb;
dtsb = dtsb & ~(DTB_DTF | DTB_BEF); }
if (pulse & 004) { /* MMWR */
dtdb = AC & DMASK;
dtdb = dat & DMASK;
dtsb = dtsb & ~(DTB_DTF | DTB_BEF); }
DT_UPDINT;
return AC;
return dat;
}
int32 dt76 (int32 pulse, int32 AC)
int32 dt76 (int32 pulse, int32 dat)
{
int32 fnc, mot, unum;
UNIT *uptr = NULL;
@ -487,7 +487,7 @@ UNIT *uptr = NULL;
unum = DTA_GETUNIT (dtsa); /* get unit no */
if (unum >= 0) uptr = dt_dev.units + unum; /* get unit */
if ((pulse & 001) && (dtsb & DTB_BEF)) /* MMBF */
AC = AC | IOT_SKP;
dat = dat | IOT_SKP;
if (pulse & 002) { /* MMRS */
dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */
if (uptr) { /* valid unit? */
@ -495,13 +495,13 @@ if (pulse & 002) { /* MMRS */
if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */
if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700))
dtsb = dtsb | DTB_GO; } /* accel? go */
AC = (AC & ~DMASK) | dtsb; }
dat = (dat & ~DMASK) | dtsb; }
if ((pulse & 044) == 044) { /* MMSE */
if ((dtsa ^ AC) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */
dtsa = (dtsa & ~DTA_UNIT) | (AC & DTA_UNIT);
if ((dtsa ^ dat) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */
dtsa = (dtsa & ~DTA_UNIT) | (dat & DTA_UNIT);
dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); }
else if ((pulse & 044) == 004) { /* MMLC */
dtsa = (dtsa & ~DTA_RW) | (AC & DTA_RW); /* load dtsa */
dtsa = (dtsa & ~DTA_RW) | (dat & DTA_RW); /* load dtsa */
dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR);
fnc = DTA_GETFNC (dtsa); /* get fnc */
if ((uptr == NULL) || /* invalid? */
@ -512,7 +512,7 @@ else if ((pulse & 044) == 004) { /* MMLC */
dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); }
DT_UPDINT;
return AC;
return dat;
}
#endif
@ -836,7 +836,7 @@ case FNC_SRCH: /* search */
return SCPE_OK; }
sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* inc WC */
ma = M[DT_CA] & ADDRMASK; /* get mem addr */
ma = M[DT_CA] & AMASK; /* get mem addr */
if (MEM_ADDR_OK (ma)) M[ma] = blk; /* store block # */
if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0))
dtsb = dtsb | DTB_DTF; /* set DTF */
@ -870,7 +870,7 @@ case FNC_READ: /* read */
case 0: /* normal read */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK;
ma = M[DT_CA] & ADDRMASK; /* mem addr */
ma = M[DT_CA] & AMASK; /* mem addr */
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
dtdb = bptr[ba]; /* get tape word */
if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */
@ -920,7 +920,7 @@ case FNC_WRIT: /* write */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK;
case DTO_WCO: /* wc ovflo */
ma = M[DT_CA] & ADDRMASK; /* mem addr */
ma = M[DT_CA] & AMASK; /* mem addr */
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
dtdb = dt_substate? 0: M[ma]; /* get word */
if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */
@ -955,7 +955,7 @@ case FNC_RALL:
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK;
ma = M[DT_CA] & ADDRMASK; /* mem addr */
ma = M[DT_CA] & AMASK; /* mem addr */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
@ -989,7 +989,7 @@ case FNC_WALL:
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK;
ma = M[DT_CA] & ADDRMASK; /* mem addr */
ma = M[DT_CA] & AMASK; /* mem addr */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
dtdb = M[ma]; /* get mem word */
@ -1122,7 +1122,7 @@ return;
int32 dt_comobv (int32 dat)
{
dat = dat ^ 0777777; /* compl obverse */
dat = dat ^ DMASK; /* compl obverse */
dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) |
((dat >> 3) & 0700) | ((dat & 0700) << 3) |
((dat & 070) << 9) | ((dat & 07) << 15);
@ -1140,16 +1140,16 @@ int32 i, csum, wrd;
#if defined (TC02) /* TC02/TC15 */
csum = 077; /* init csum */
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
wrd = bptr[ba + i] ^ 0777777; /* get ~word */
wrd = bptr[ba + i] ^ DMASK; /* get ~word */
csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; }
return (csum & 077);
#else /* Type 550 */
csum = 0777777;
csum = DMASK;
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
wrd = bptr[ba + i]; /* get word */
csum = csum + wrd; /* 1's comp add */
if (csum > 0777777) csum = (csum + 1) & 0777777; }
return (csum ^ 0777777); /* 1's comp res */
if (csum > DMASK) csum = (csum + 1) & DMASK; }
return (csum ^ DMASK); /* 1's comp res */
#endif
}
@ -1164,7 +1164,7 @@ if (wrd == DT_BLKWD) return blk; /* fwd blknum */
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
return (dt_csum (uptr, blk) << 12);
#else
if (wrd == DT_CSMWD) return 0777777; /* rev csum */
if (wrd == DT_CSMWD) return DMASK; /* rev csum */
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
return (dt_csum (uptr, blk));
#endif /* Type 550 */

774
PDP18B/pdp18b_fpp.c Normal file
View file

@ -0,0 +1,774 @@
/* pdp18b_fpp.c: FP15 floating point processor simulator
Copyright (c) 2003, 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.
fpp PDP-15 floating point processor
The FP15 instruction format is:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 1 1 1 0 0 1| subop | microcoded modifiers | floating point
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|in| address |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Indirection is always single level.
The FP15 supports four data formats:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| S| 2's complement integer | A: integer
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| S| 2's complement integer (high) | A: extended integer
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 2's complement integer (low) | A+1
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| fraction (low) |SE|2's complement exponent| A: single floating
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|SF| fraction (high) | A+1
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|SE| 2's complement exponent | A: double floating
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|SF| fraction (high) | A+1
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| fraction (low) | A+2
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
#include "pdp18b_defs.h"
/* Instruction */
#define FI_V_OP 8 /* subopcode */
#define FI_M_OP 017
#define FI_GETOP(x) (((x) >> FI_V_OP) & FI_M_OP)
#define FI_NOLOAD 0200 /* don't load */
#define FI_DP 0100 /* single/double */
#define FI_FP 0040 /* int/flt point */
#define FI_NONORM 0020 /* don't normalize */
#define FI_NORND 0010 /* don't round */
#define FI_V_SGNOP 0 /* A sign change */
#define FI_M_SGNOP 03
#define FI_GETSGNOP(x) (((x) >> FI_V_SGNOP) & FI_M_SGNOP)
/* Exception register */
#define JEA_V_SIGN 17 /* A sign */
#define JEA_V_GUARD 16 /* guard */
#define JEA_EAMASK 077777 /* exc address */
#define JEA_OFF_OVF 0 /* ovf offset */
#define JEA_OFF_UNF 2 /* unf offset */
#define JEA_OFF_DIV 4 /* div offset */
#define JEA_OFF_MM 6 /* mem mgt offset */
/* Status codes - must relate directly to JEA offsets */
#define FP_OK 0 /* no error - mbz */
#define FP_OVF (JEA_OFF_OVF + 1) /* overflow */
#define FP_UNF (JEA_OFF_UNF + 1) /* underflow */
#define FP_DIV (JEA_OFF_DIV + 1) /* divide exception */
#define FP_MM (JEA_OFF_MM + 1) /* mem mgt error */
/* Unpacked floating point fraction */
#define UFP_FH_CARRY 0400000 /* carry out */
#define UFP_FH_NORM 0200000 /* normalized */
#define UFP_FH_MASK 0377777 /* hi mask */
#define UFP_FL_MASK 0777777 /* low mask */
#define UFP_FL_SMASK 0777000 /* low mask, single */
#define UFP_FL_SRND 0000400 /* round bit, single */
#define GET_SIGN(x) (((x) >> 17) & 1)
#define SEXT18(x) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))
#define SEXT9(x) (((x) & 0400)? ((x) | ~0377): ((x) & 0377))
enum fop {
FOP_TST, FOP_SUB, FOP_RSUB, FOP_MUL,
FOP_DIV, FOP_RDIV, FOP_LD, FOP_ST,
FOP_FLT, FOP_FIX, FOP_LFMQ, FOP_JEA,
FOP_ADD, FOP_BR, FOP_DIAG, FOP_UND };
struct ufp {
int32 exp; /* exponent */
int32 sign; /* sign */
int32 hi; /* hi frac, 17b */
int32 lo; }; /* lo frac, 18b */
typedef struct ufp UFP;
static int32 fir; /* instruction */
static int32 jea; /* exc address */
static int32 fguard; /* guard bit */
static UFP fma; /* FMA */
static UFP fmb; /* FMB */
static UFP fmq; /* FMQ - hi,lo only */
extern int32 M[MAXMEMSIZE];
extern int32 pcq[PCQ_SIZE];
extern int32 pcq_p;
extern int32 PC;
extern int32 trap_pending, usmd;
t_stat fp15_reset (DEVICE *dptr);
t_stat fp15_opnd (int32 ir, int32 addr, UFP *a);
t_stat fp15_store (int32 ir, int32 addr, UFP *a);
t_stat fp15_iadd (int32 ir, UFP *a, UFP *b, t_bool sub);
t_stat fp15_imul (int32 ir, UFP *a, UFP *b);
t_stat fp15_idiv (int32 ir, UFP *a, UFP *b);
t_stat fp15_fadd (int32 ir, UFP *a, UFP *b, t_bool sub);
t_stat fp15_fmul (int32 ir, UFP *a, UFP *b);
t_stat fp15_fdiv (int32 ir, UFP *a, UFP *b);
t_stat fp15_fix (int32 ir, UFP *a);
t_stat fp15_norm (int32 ir, UFP *a, UFP *b, t_bool rnd);
t_stat fp15_exc (int32 sta);
void fp15_asign (int32 ir, UFP *a);
void dp_add (UFP *a, UFP *b);
void dp_sub (UFP *a, UFP *b);
void dp_inc (UFP *a);
int32 dp_cmp (UFP *a, UFP *b);
void dp_mul (UFP *a, UFP *b);
void dp_lsh_1 (UFP *a, UFP *b);
void dp_rsh_1 (UFP *a, UFP *b);
void dp_dnrm_r (int32 ir, UFP *a, int32 sc);
void dp_swap (UFP *a, UFP *b);
extern t_stat Read (int32 ma, int32 *dat, int32 cyc);
extern t_stat Write (int32 ma, int32 dat, int32 cyc);
extern t_stat Ia (int32 ma, int32 *ea, t_bool jmp);
extern int32 Incr_addr (int32 addr);
extern int32 Jms_word (int32 t);
/* FPP data structures
fpp_dev FPP device descriptor
fpp_unit FPP unit
fpp_reg FPP register list
fpp_mod FPP modifier list
*/
UNIT fpp_unit = { UDATA (NULL, 0, 0) };
REG fpp_reg[] = {
{ ORDATA (FIR, fir, 12) },
{ ORDATA (EPA, fma.exp, 18) },
{ FLDATA (FMAS, fma.sign, 0) },
{ ORDATA (FMAH, fma.hi, 17) },
{ ORDATA (FMAL, fma.lo, 18) },
{ ORDATA (EPB, fmb.exp, 18) },
{ FLDATA (FMBS, fmb.sign, 0) },
{ ORDATA (FMBH, fmb.hi, 17) },
{ ORDATA (FMBL, fmb.lo, 18) },
{ FLDATA (FGUARD, fguard, 0) },
{ ORDATA (FMQH, fmq.hi, 17) },
{ ORDATA (FMQL, fmq.lo, 18) },
{ ORDATA (JEA, jea, 18) },
{ NULL } };
DEVICE fpp_dev = {
"FPP", &fpp_unit, fpp_reg, NULL,
1, 8, 1, 1, 8, 18,
NULL, NULL, &fp15_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE | DEV_DIS };
/* Instruction decode for FP15
The CPU actually fetches the instruction and the word after. If the
instruction is 71XXXX, the CPU executes it as a NOP, and the FP15 fools
the CPU into thinking that the second word is also a NOP.
Indirect addresses are resolved during fetch, unless the NOLOAD modifier
is set and the instruction is not a store. */
t_stat fp15 (int32 ir)
{
int32 ar, ma, fop, dat;
t_stat sta = FP_OK;
if (fpp_dev.flags & DEV_DIS) return MM_OK; /* disabled? */
fir = ir & 07777; /* save subop + mods */
ma = PC; /* fetch next word */
PC = Incr_addr (PC);
if (Read (ma, &ar, RD)) return fp15_exc (FP_MM); /* error? MM exc */
fop = FI_GETOP (fir); /* get subopcode */
if ((ar & SIGN) && /* indirect? */
((fop == FOP_ST) || !(ir & FI_NOLOAD))) { /* store or load? */
ma = ar & AMASK; /* fetch indirect */
if (Read (ma, &ar, RD)) return fp15_exc (FP_MM); }
fma.exp = SEXT18 (fma.exp); /* sext exponents */
fmb.exp = SEXT18 (fmb.exp);
switch (fop) { /* case on subop */
case FOP_TST: /* NOP */
break;
case FOP_SUB: /* subtract */
if (sta = fp15_opnd (fir, ar, &fmb)) break; /* fetch op to FMB */
if (fir & FI_FP) sta = fp15_fadd (fir, &fma, &fmb, 1); /* fp? */
else sta = fp15_iadd (fir, &fma, &fmb, 1); /* no, int sub */
break;
case FOP_RSUB: /* reverse sub */
fmb = fma; /* FMB <- FMA */
if (sta = fp15_opnd (fir, ar, &fma)) break; /* fetch op to FMA */
if (fir & FI_FP) sta = fp15_fadd (fir, &fma, &fmb, 1); /* fp? */
else sta = fp15_iadd (fir, &fma, &fmb, 1); /* no, int sub */
break;
case FOP_MUL: /* multiply */
if (sta = fp15_opnd (fir, ar, &fmb)) break; /* fetch op to FMB */
if (fir & FI_FP) sta = fp15_fmul (fir, &fma, &fmb); /* fp? */
else sta = fp15_imul (fir, &fma, &fmb); /* no, int mul */
break;
case FOP_DIV: /* divide */
if (sta = fp15_opnd (fir, ar, &fmb)) break; /* fetch op to FMB */
if (fir & FI_FP) sta = fp15_fdiv (fir, &fma, &fmb); /* fp? */
else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */
break;
case FOP_RDIV: /* reverse divide */
fmb = fma; /* FMB <- FMA */
if (sta = fp15_opnd (fir, ar, &fma)) break; /* fetch op to FMA */
if (fir & FI_FP) sta = fp15_fdiv (fir, &fma, &fmb); /* fp? */
else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */
break;
case FOP_LD: /* load */
if (sta = fp15_opnd (fir, ar, &fma)) break; /* fetch op to FMA */
fp15_asign (fir, &fma); /* modify A sign */
if (fir & FI_FP) /* fp? */
sta = fp15_norm (ir, &fma, NULL, 0); /* normalize */
break;
case FOP_ST: /* store */
fp15_asign (fir, &fma); /* modify A sign */
sta = fp15_store (fir, ar, &fma); /* store result */
break;
case FOP_FLT: /* float */
if (sta = fp15_opnd (fir, ar, &fma)) break; /* fetch op to FMA */
fma.exp = 35;
fp15_asign (fir, &fma); /* adjust A sign */
sta = fp15_norm (ir, &fma, NULL, 0); /* normalize */
break;
case FOP_FIX: /* fix */
if (sta = fp15_opnd (fir, ar, &fma)) break; /* fetch op to FMA */
sta = fp15_fix (fir, &fma); /* fix */
break;
case FOP_LFMQ: /* load FMQ */
if (sta = fp15_opnd (fir, ar, &fma)) break; /* fetch op to FMA */
dp_swap (&fma, &fmq); /* swap FMA, FMQ */
fp15_asign (fir, &fma); /* adjust A sign */
if (fir & FI_FP) /* fp? norm, no rnd */
sta = fp15_norm (ir | FI_NORND, &fma, &fmq, 0);
break;
case FOP_JEA: /* JEA */
if (ir & 0200) { /* store? */
dat = jea | (fma.sign << JEA_V_SIGN) | (fguard << JEA_V_GUARD);
sta = Write (ar, dat, WR); }
else { /* no, load */
if (sta = Read (ar, &dat, RD)) break;
fguard = (dat >> JEA_V_GUARD) & 1;
jea = dat; }
break;
case FOP_ADD: /* add */
if (sta = fp15_opnd (fir, ar, &fmb)) break; /* fetch op to FMB */
if (fir & FI_FP) sta = fp15_fadd (fir, &fma, &fmb, 0); /* fp? */
else sta = fp15_iadd (fir, &fma, &fmb, 0); /* no, int add */
break;
case FOP_BR: /* branch */
if (((fir & 001) && ((fma.hi | fma.lo) == 0)) ||
((fir & 002) && fma.sign) ||
((fir & 004) && !fma.sign) ||
((fir & 010) && ((fma.hi | fma.lo) != 0)) ||
((fir & 020) && fguard)) { /* cond met? */
PCQ_ENTRY; /* save current PC */
PC = (PC & BLKMASK) | (ar & IAMASK); } /* branch within 32K */
break;
default:
break; }
fma.exp = fma.exp & DMASK; /* mask exp to 18b */
fmb.exp = fmb.exp & DMASK;
if (sta != FP_OK) return fp15_exc (sta); /* error? */
return MM_OK;
}
/* Operand load and store */
t_stat fp15_opnd (int32 ir, int32 addr, UFP *fpn)
{
int32 i, numwd, wd[3];
fguard = 0; /* clear guard */
if (ir & FI_NOLOAD) return FP_OK; /* no load? */
if (ir & FI_FP) numwd = 2; /* fp? at least 2 */
else numwd = 1; /* else at least 1 */
if (ir & FI_DP) numwd = numwd + 1; /* dp? 1 more */
for (i = 0; i < numwd; i++) { /* fetch words */
if (Read (addr, &wd[i], RD)) return FP_MM;
addr = (addr + 1) & AMASK; }
if (ir & FI_FP) { /* fp? */
fpn->sign = GET_SIGN (wd[1]); /* frac sign */
fpn->hi = wd[1] & UFP_FH_MASK; /* frac high */
if (ir & FI_DP) { /* dp? */
fpn->exp = SEXT18 (wd[0]); /* exponent */
fpn->lo = wd[2]; } /* frac low */
else { /* sp */
fpn->exp = SEXT9 (wd[0]); /* exponent */
fpn->lo = wd[0] & UFP_FL_SMASK; } /* frac low */
}
else { fpn->sign = GET_SIGN (wd[0]); /* int, get sign */
if (ir & FI_DP) { /* dp? */
fpn->lo = wd[1]; /* 2 words */
fpn->hi = wd[0]; }
else { /* single */
fpn->lo = wd[0]; /* 1 word */
fpn->hi = fpn->sign? DMASK: 0; } /* sign extended */
if (fpn->sign) { /* negative? */
fpn->lo = (-fpn->lo) & UFP_FL_MASK; /* take abs val */
fpn->hi = (~fpn->hi + (fpn->lo == 0)) & UFP_FH_MASK; }
}
return FP_OK;
}
t_stat fp15_store (int32 ir, int32 addr, UFP *a)
{
int32 i, numwd, wd[3];
t_stat sta;
fguard = 0; /* clear guard */
if (ir & FI_FP) { /* fp? */
if (sta = fp15_norm (ir, a, NULL, 0)) return sta; /* normalize */
wd[1] = (a->sign << 17) | a->hi; /* hi frac */
if (ir & FI_DP) { /* dp? */
numwd = 3; /* 3 words */
wd[0] = a->exp & DMASK; /* exponent */
wd[2] = a->lo; } /* low frac */
else { /* single */
if (!(ir & FI_NORND) && (a->lo & UFP_FL_SRND)) { /* round? */
a->lo = (a->lo + UFP_FL_SRND) & UFP_FL_SMASK;
a->hi = (a->hi + (a->lo == 0)) & UFP_FH_MASK;
if ((a->hi | a->lo) == 0) { /* carry out? */
a->hi = UFP_FH_NORM; /* shift back */
a->exp = a->exp + 1; } }
if (a->exp > 0377) return FP_OVF; /* sp ovf? */
if (a->exp < -0400) return FP_UNF; /* sp unf? */
numwd = 2; /* 2 words */
wd[0] = (a->exp & 0777) | a->lo; } /* low frac'exp */
}
else { fmb.lo = (-a->lo) & UFP_FL_MASK; /* 2's complement */
fmb.hi = (~a->hi + (fmb.lo == 0)) & UFP_FH_MASK;/* to FMB */
if (ir & FI_DP) { /* dp? */
numwd = 2; /* 2 words */
if (a->sign) { /* negative? */
wd[0] = fmb.hi | SIGN; /* store FMB */
wd[1] = fmb.lo; }
else { /* pos, store FMA */
wd[0] = a->hi;
wd[1] = a->lo; } }
else { /* single */
if (a->hi || (a->lo & SIGN)) return FP_OVF; /* check int ovf */
numwd = 1; /* 1 word */
if (a->sign) wd[0] = fmb.lo; /* neg? store FMB */
else wd[0] = a->lo; } /* pos, store FMA */
}
for (i = 0; i < numwd; i++) { /* store words */
if (Write (addr, wd[i], WR)) return FP_MM;
addr = (addr + 1) & AMASK; }
return FP_OK;
}
/* Integer arithmetic routines */
/* Integer add - overflow only on add, if carry out of high fraction */
t_stat fp15_iadd (int32 ir, UFP *a, UFP *b, t_bool sub)
{
fmq.hi = fmq.lo = 0; /* clear FMQ */
if (a->sign ^ b->sign ^ sub) dp_sub (a, b); /* eff subtract? */
else { dp_add (a, b); /* no, add */
if (a->hi & UFP_FH_CARRY) { /* carry out? */
a->hi = a->hi & UFP_FH_MASK; /* mask to 35b */
return FP_OVF; } } /* overflow */
fp15_asign (ir, a); /* adjust A sign */
return FP_OK;
}
/* Integer multiply - overflow if high result (FMQ after swap) non-zero */
t_stat fp15_imul (int32 ir, UFP *a, UFP *b)
{
a->sign = a->sign ^ b->sign; /* sign of result */
dp_mul (a, b); /* a'FMQ <- a * b */
dp_swap (a, &fmq); /* swap a, FMQ */
if (fmq.hi | fmq.lo) return FP_OVF; /* FMQ != 0? ovf */
fp15_asign (ir, a); /* adjust A sign */
return FP_OK;
}
/* Integer divide - actually done as fraction divide
- If divisor zero, error
- If dividend zero, done
- Normalize dividend and divisor together
- If divisor normalized but dividend not, result is zero
- If divisor not normalized, normalize and count shifts
- Do fraction divide for number of shifts, +1, steps
Note that dp_lsh_1 returns a 72b result; the last right shift
guarantees a 71b remainder. The quotient cannot exceed 71b */
t_stat fp15_idiv (int32 ir, UFP *a, UFP *b)
{
int32 i, sc;
a->sign = a->sign ^ b->sign; /* sign of result */
fmq.hi = fmq.lo = 0; /* clear quotient */
a->exp = 0; /* clear a exp */
if ((b->hi | b->lo) == 0) return FP_DIV; /* div by 0? */
if ((a->hi | a->lo) == 0) return FP_OK; /* div into 0? */
while (((a->hi & UFP_FH_NORM) == 0) && /* normalize divd */
((b->hi & UFP_FH_NORM) == 0)) { /* and divr */
dp_lsh_1 (a, NULL); /* lsh divd, divr */
dp_lsh_1 (b, NULL); } /* can't carry out */
if (!(a->hi & UFP_FH_NORM) && (b->hi & UFP_FH_NORM)) { /* divr norm, divd not? */
a->hi = a->lo = 0; /* result is 0 */
return FP_OK; }
while ((b->hi & UFP_FH_NORM) == 0) { /* normalize divr */
dp_lsh_1 (b, NULL); /* can't carry out */
a->exp = a->exp + 1; } /* count steps */
sc = a->exp;
for (i = 0; i <= sc; i++) { /* n+1 steps */
dp_lsh_1 (&fmq, NULL); /* left shift quo */
if (dp_cmp (a, b) >= 0) { /* sub work? */
dp_sub (a, b); /* a -= b */
if (i == 0) a->exp = a->exp + 1; /* first step? */
fmq.lo = fmq.lo | 1; } /* set quo bit */
dp_lsh_1 (a, NULL); } /* left shift divd */
dp_rsh_1 (a, NULL); /* shift back */
dp_swap (a, &fmq); /* swap a, FMQ */
fp15_asign (ir, a); /* adjust A sign */
return FP_OK;
}
/* Floating point arithmetic routines */
/* Floating add
- Special add case, overflow if carry out increments exp out of range
- All cases, overflow/underflow detected in normalize */
t_stat fp15_fadd (int32 ir, UFP *a, UFP *b, t_bool sub)
{
int32 ediff;
fmq.hi = fmq.lo = 0; /* clear FMQ */
ediff = a->exp - b->exp; /* exp diff */
if (((a->hi | a->lo) == 0) || (ediff < -35)) { /* a = 0 or "small"? */
*a = *b; /* rslt is b */
a->sign = a->sign ^ sub; } /* or -b if sub */
else if (((b->hi | b->lo) != 0) && (ediff <= 35)) { /* b!=0 && ~"small"? */
if (ediff > 0) dp_dnrm_r (ir, b, ediff); /* |a| > |b|? dnorm b */
else if (ediff < 0) { /* |a| < |b|? */
a->exp = b->exp; /* b exp is rslt */
dp_dnrm_r (ir, a, -ediff); } /* denorm A */
if (a->sign ^ b->sign ^ sub) dp_sub (a, b); /* eff sub? */
else { /* eff add */
dp_add (a, b); /* add */
if (a->hi & UFP_FH_CARRY) { /* carry out? */
fguard = a->lo & 1; /* set guard */
dp_rsh_1 (a, NULL); /* right shift */
a->exp = a->exp + 1; /* incr exponent */
if (!(ir & FI_NORND) && fguard) /* rounding? */
dp_inc (a);
if (a->exp > 0377777) return FP_OVF; } }
} /* end if b != 0 */
fp15_asign (ir, a); /* adjust A sign */
return fp15_norm (ir, a, NULL, 0); /* normalize */
}
/* Floating multiply - overflow/underflow detected in normalize */
t_stat fp15_fmul (int32 ir, UFP *a, UFP *b)
{
a->sign = a->sign ^ b->sign; /* sign of result */
a->exp = a->exp + b->exp; /* exp of result */
dp_mul (a, b); /* mul fractions */
fp15_asign (ir, a); /* adjust A sign */
return fp15_norm (ir, a, &fmq, 1); /* norm and round */
}
/* Floating divide - overflow/underflow detected in normalize */
t_stat fp15_fdiv (int32 ir, UFP *a, UFP *b)
{
int32 i;
a->sign = a->sign ^ b->sign; /* sign of result */
a->exp = a->exp - b->exp; /* exp of result */
fmq.hi = fmq.lo = 0; /* clear quotient */
if (!(b->hi & UFP_FH_NORM)) return FP_DIV; /* divr not norm? */
if (a->hi | a->lo) { /* divd non-zero? */
fp15_norm (0, a, NULL, 0); /* normalize divd */
for (i = 0; (fmq.hi & UFP_FH_NORM) == 0; i++) { /* until quo */
dp_lsh_1 (&fmq, NULL); /* left shift quo */
if (dp_cmp (a, b) >= 0) { /* sub work? */
dp_sub (a, b); /* a -= b */
if (i == 0) a->exp = a->exp + 1;
fmq.lo = fmq.lo | 1; } /* set quo bit */
dp_lsh_1 (a, NULL); } /* left shift divd */
dp_rsh_1 (a, NULL); /* shift back */
dp_swap (a, &fmq); } /* swap a, FMQ */
fp15_asign (ir, a); /* adjust A sign */
return fp15_norm (ir, a, &fmq, 1); /* norm and round */
}
/* Floating to integer - overflow only if exponent out of range */
t_stat fp15_fix (int32 ir, UFP *a)
{
int32 i;
fmq.hi = fmq.lo = 0; /* clear FMQ */
if (a->exp > 35) return FP_OVF; /* exp > 35? ovf */
if (a->exp < 0) a->hi = a->lo = 0; /* exp <0 ? rslt 0 */
else { for (i = a->exp; i < 35; i++) /* denorm frac */
dp_rsh_1 (a, &fmq);
if (fmq.hi & UFP_FH_NORM) { /* last out = 1? */
fguard = 1; /* set guard */
if (!(ir & FI_NORND)) dp_inc (a); } } /* round */
fp15_asign (ir, a); /* adjust A sign */
return FP_OK;
}
/* Double precision routines */
/* Double precision add - returns 72b result (including carry) */
void dp_add (UFP *a, UFP *b)
{
int32 a_hi_orig = a->hi;
a->lo = (a->lo + b->lo) & UFP_FL_MASK; /* add low */
a->hi = a->hi + b->hi + (a->lo < b->lo); /* add hi + carry */
return;
}
/* Double precision increment - returns 72b result (including carry) */
void dp_inc (UFP *a)
{
a->lo = (a->lo + 1) & UFP_FL_MASK; /* inc low */
a->hi = a->hi + (a->lo == 0); /* propagate carry */
return;
}
/* Double precision subtract - result always fits in 71b */
void dp_sub (UFP *a, UFP *b)
{
if (dp_cmp (a,b) >= 0) { /* |a| >= |b|? */
a->hi = (a->hi - b->hi - (a->lo < b->lo)) & UFP_FH_MASK;
a->lo = (a->lo - b->lo) & UFP_FL_MASK; } /* a - b */
else { a->hi = (b->hi - a->hi - (b->lo < a->lo)) & UFP_FH_MASK;
a->lo = (b->lo - a->lo) & UFP_FL_MASK; /* b - a */
a->sign = a->sign ^ 1; } /* change a sign */
return;
}
/* Double precision compare - returns +1 (>), 0 (=), -1 (<) */
int32 dp_cmp (UFP *a, UFP *b)
{
if (a->hi < b->hi) return -1;
if (a->hi > b->hi) return +1;
if (a->lo < b->lo) return -1;
if (a->lo > b->lo) return +1;
return 0;
}
/* Double precision multiply - returns 70b result */
void dp_mul (UFP *a, UFP *b)
{
int32 i;
fmq.hi = a->hi; /* FMQ <- a */
fmq.lo = a->lo;
a->hi = a->lo = 0; /* a <- 0 */
if (((fmq.hi | fmq.lo) == 0) || ((b->hi | b->lo) == 0)) return;
for (i = 0; i < 35; i++) { /* 35 iterations */
if (fmq.lo & 1) dp_add (a, b); /* FMQ<35>? a += b */
dp_rsh_1 (a, &fmq); } /* rsh a'FMQ */
return;
}
/* Double (quad) precision left shift - returns 72b (143b) result */
void dp_lsh_1 (UFP *a, UFP *b)
{
int32 t = b? b->lo: 0;
a->hi = (a->hi << 1) | (a->lo >> 17);
a->lo = ((a->lo << 1) | (t >> 16)) & UFP_FL_MASK;
if (b) {
b->hi = ((b->hi << 1) | (b->lo >> 17)) & UFP_FH_MASK;
b->lo = (b->lo << 1) & UFP_FL_MASK; }
return;
}
/* Double (quad) precision right shift - returns 71b (142b) result */
void dp_rsh_1 (UFP *a, UFP *b)
{
if (b) {
b->lo = (b->lo >> 1) | ((b->hi & 1) << 17);
b->hi = (b->hi >> 1) | ((a->lo & 1) << 16); }
a->lo = (a->lo >> 1) | ((a->hi & 1) << 17);
a->hi = a->hi >> 1;
return;
}
/* Double precision denormalize and round - returns 71b result */
void dp_dnrm_r (int32 ir, UFP *a, int32 sc)
{
int32 i;
if (sc <= 0) return; /* legit? */
for (i = 0; i < sc; i++) dp_rsh_1 (a, &fmq); /* dnorm to fmq */
if (!(ir & FI_NORND) && (fmq.hi & UFP_FH_NORM)) /* round & fmq<1>? */
dp_inc (a); /* incr a */
return;
}
/* Double precision swap */
void dp_swap (UFP *a, UFP *b)
{
int32 t;
t = a->hi; /* swap fractions */
a->hi = b->hi;
b->hi = t;
t = a->lo;
a->lo = b->lo;
b->lo = t;
return;
}
/* Support routines */
void fp15_asign (int32 fir, UFP *a)
{
int32 sgnop = FI_GETSGNOP (fir);
switch (sgnop) { /* modify FMA sign */
case 1:
a->sign = 0;
break;
case 2:
a->sign = 1;
break;
case 3:
a->sign = a->sign ^ 1;
break;
default:
break; }
return;
}
/* FP15 normalization and rounding
- Do normalization if enabled (NOR phase, part 1)
Normalization also does zero detect
- Do rounding if enabled (NOR phase, part 2) */
t_stat fp15_norm (int32 ir, UFP *a, UFP *b, t_bool rnd)
{
if (!(ir & FI_NONORM)) { /* norm enabled? */
if ((a->hi | a->lo) || (b && (b->hi | b->lo))) { /* frac != 0? */
while ((a->hi & UFP_FH_NORM) == 0) { /* until norm */
dp_lsh_1 (a, b); /* lsh a'b, no cry */
a->exp = a->exp - 1; } } /* decr exp */
else a->sign = a->exp = 0; } /* true zero */
if (rnd && b && (b->hi & UFP_FH_NORM)) { /* rounding? */
fguard = 1; /* set guard */
if (!(ir & FI_NORND)) { /* round enabled? */
dp_inc (a); /* add 1 */
if (a->hi & UFP_FH_CARRY) { /* carry out? */
a->hi = UFP_FH_NORM; /* set hi bit */
a->exp = a->exp + 1; } } } /* incr exp */
if (a->exp > 0377777) return FP_OVF; /* overflow? */
if (a->exp < -0400000) return FP_UNF; /* underflow? */
return FP_OK;
}
/* Exception */
t_stat fp15_exc (t_stat sta)
{
int32 ma, mb;
if (sta == FP_MM) trap_pending = 0; /* if mm, kill trap */
ma = (jea & JEA_EAMASK) + sta - 1; /* JEA address */
PCQ_ENTRY; /* record branch */
PC = Incr_addr (PC); /* PC+1 for "JMS" */
mb = Jms_word (usmd); /* form JMS word */
if (Write (ma, mb, WR)) return MM_ERR; /* store */
PC = (jea + 1) & IAMASK; /* new PC */
return MM_OK;
}
/* Reset routine */
t_stat fp15_reset (DEVICE *dptr)
{
jea = 0;
fir = 0;
fguard = 0;
fma.exp = fma.hi = fma.lo = fma.sign = 0;
fmb.exp = fmb.hi = fmb.lo = fmb.sign = 0;
fmq.exp = fmq.hi = fmq.lo = fmq.sign = 0;
return SCPE_OK;
}

View file

@ -28,6 +28,7 @@
lp09 (PDP-9,15) LP09 line printer
lp15 (PDP-15) LP15 line printer
23-Jul-03 RMS Fixed overprint bug in Type 62
25-Apr-03 RMS Revised for extended file support
05-Feb-03 RMS Added LP09, fixed conditionalization
05-Oct-02 RMS Added DIB, device number support
@ -53,7 +54,8 @@ extern int32 int_hwre[API_HLVL+1];
#define BPTR_MAX 40 /* pointer max */
#define BPTR_MASK 077 /* buf ptr max */
int32 lp62_iot = 0; /* saved state */
int32 lp62_spc = 0; /* print vs spc */
int32 lp62_ovrpr = 0; /* overprint */
int32 lp62_stopioe = 0;
int32 lp62_bp = 0; /* buffer ptr */
char lp62_buf[LP62_BSIZE + 1] = { 0 };
@ -73,8 +75,8 @@ static const char *lp62_cc[] = {
"\f" };
DEVICE lp62_dev;
int32 lp62_65 (int32 pulse, int32 AC);
int32 lp62_66 (int32 pulse, int32 AC);
int32 lp62_65 (int32 pulse, int32 dat);
int32 lp62_66 (int32 pulse, int32 dat);
int32 lp62_iors (void);
t_stat lp62_svc (UNIT *uptr);
t_stat lp62_reset (DEVICE *dptr);
@ -97,7 +99,8 @@ REG lp62_reg[] = {
{ FLDATA (DONE, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) },
{ DRDATA (BPTR, lp62_bp, 6) },
{ ORDATA (STATE, lp62_iot, 6), REG_HRO },
{ ORDATA (STATE, lp62_spc, 6), REG_HRO },
{ FLDATA (OVRPR, lp62_ovrpr, 0), REG_HRO },
{ DRDATA (POS, lp62_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, lp62_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lp62_stopioe, 0) },
@ -118,62 +121,62 @@ DEVICE lp62_dev = {
/* IOT routines */
int32 lp62_65 (int32 pulse, int32 AC)
int32 lp62_65 (int32 pulse, int32 dat)
{
int32 i;
if ((pulse & 01) && TST_INT (LPT)) AC = IOT_SKP | AC; /* LPSF */
if ((pulse & 01) && TST_INT (LPT)) dat = IOT_SKP | dat; /* LPSF */
if (pulse & 02) {
int32 sb = pulse & 060; /* subopcode */
if (sb == 000) CLR_INT (LPT); /* LPCF */
if ((sb == 040) && (lp62_bp < BPTR_MAX)) { /* LPLD */
i = lp62_bp * 3; /* cvt to chr ptr */
lp62_buf[i] = lp62_trans[(AC >> 12) & 077];
lp62_buf[i + 1] = lp62_trans[(AC >> 6) & 077];
lp62_buf[i + 2] = lp62_trans[AC & 077];
lp62_buf[i] = lp62_trans[(dat >> 12) & 077];
lp62_buf[i + 1] = lp62_trans[(dat >> 6) & 077];
lp62_buf[i + 2] = lp62_trans[dat & 077];
lp62_bp = (lp62_bp + 1) & BPTR_MASK; }
}
if (pulse & 04) /* LPSE */
sim_activate (&lp62_unit, lp62_unit.wait); /* activate */
return AC;
if (pulse & 04) { /* LPSE */
lp62_spc = 0; /* print */
sim_activate (&lp62_unit, lp62_unit.wait); } /* activate */
return dat;
}
int32 lp62_66 (int32 pulse, int32 AC)
int32 lp62_66 (int32 pulse, int32 dat)
{
if ((pulse & 01) && TST_INT (LPTSPC)) /* LSSF */
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
if (pulse & 02) CLR_INT (LPTSPC); /* LSCF */
if (pulse & 04) { /* LSPR */
lp62_iot = 020 | (AC & 07); /* space, no print */
lp62_spc = 020 | (dat & 07); /* space */
sim_activate (&lp62_unit, lp62_unit.wait); } /* activate */
return AC;
return dat;
}
/* Unit service, printer is in one of three states
/* Unit service, action based on lp62_spc
lp62_iot = 0 write buffer to file, set state to
lp62_iot = 10 write cr, then write buffer to file
lp62_iot = 2x space command x, then set state to 0
lp62_spc = 0 write buffer to file, set overprint
lp62_spc = 2x space command x, clear overprint
*/
t_stat lp62_svc (UNIT *uptr)
{
int32 i;
if (lp62_iot & 020) { /* space? */
if (lp62_spc) { /* space? */
SET_INT (LPTSPC); /* set flag */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lp62_stopioe, SCPE_UNATT);
fputs (lp62_cc[lp62_iot & 07], uptr->fileref); /* print cctl */
fputs (lp62_cc[lp62_spc & 07], uptr->fileref); /* print cctl */
if (ferror (uptr->fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
lp62_iot = 0; } /* clear state */
lp62_ovrpr = 0; } /* clear overprint */
else { SET_INT (LPT); /* print */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lp62_stopioe, SCPE_UNATT);
if (lp62_iot & 010) fputc ('\r', uptr->fileref);
if (lp62_ovrpr) fputc ('\r', uptr->fileref); /* overprint? */
fputs (lp62_buf, uptr->fileref); /* print buffer */
if (ferror (uptr->fileref)) { /* test error */
perror ("LPT I/O error");
@ -181,7 +184,7 @@ else { SET_INT (LPT); /* print */
return SCPE_IOERR; }
lp62_bp = 0;
for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */
lp62_iot = 010; } /* set state */
lp62_ovrpr = 1; } /* set overprint */
uptr->pos = ftell (uptr->fileref); /* update position */
return SCPE_OK;
}
@ -197,7 +200,8 @@ CLR_INT (LPTSPC);
sim_cancel (&lp62_unit); /* deactivate unit */
lp62_bp = 0; /* clear buffer ptr */
for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */
lp62_iot = 0; /* clear state */
lp62_spc = 0; /* clear state */
lp62_ovrpr = 0; /* clear overprint */
return SCPE_OK;
}
@ -235,8 +239,8 @@ static const char *lp647_cc[] = {
"\f" };
DEVICE lp647_dev;
int32 lp647_65 (int32 pulse, int32 AC);
int32 lp647_66 (int32 pulse, int32 AC);
int32 lp647_65 (int32 pulse, int32 dat);
int32 lp647_66 (int32 pulse, int32 dat);
int32 lp647_iors (void);
t_stat lp647_svc (UNIT *uptr);
t_stat lp647_reset (DEVICE *dptr);
@ -285,12 +289,12 @@ DEVICE lp647_dev = {
/* IOT routines */
int32 lp647_65 (int32 pulse, int32 AC)
int32 lp647_65 (int32 pulse, int32 dat)
{
int32 i, sb;
sb = pulse & 060; /* subcode */
if ((pulse & 01) && lp647_don) AC = IOT_SKP | AC; /* LPSF */
if ((pulse & 01) && lp647_don) dat = IOT_SKP | dat; /* LPSF */
if (pulse & 02) { /* pulse 02 */
lp647_don = 0; /* clear done */
CLR_INT (LPT); /* clear int req */
@ -310,32 +314,32 @@ if (pulse & 004) { /* LPDI */
break;
case 040: /* LPB3 */
if (lp647_bp < LP647_BSIZE) {
lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | ((AC >> 12) & 077);
lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | ((dat >> 12) & 077);
lp647_bp = lp647_bp + 1; }
case 020: /* LPB2 */
if (lp647_bp < LP647_BSIZE) {
lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | ((AC >> 6) & 077);
lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | ((dat >> 6) & 077);
lp647_bp = lp647_bp + 1; }
case 060: /* LPB1 */
if (lp647_bp < LP647_BSIZE) {
lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | (AC & 077);
lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | (dat & 077);
lp647_bp = lp647_bp + 1; }
lp647_don = 1; /* set done */
if (lp647_ie) SET_INT (LPT); /* set int */
break; } /* end case */
}
return AC;
return dat;
}
int32 lp647_66 (int32 pulse, int32 AC)
int32 lp647_66 (int32 pulse, int32 dat)
{
if ((pulse & 01) && lp647_err) AC = IOT_SKP | AC; /* LPSE */
if ((pulse & 01) && lp647_err) dat = IOT_SKP | dat; /* LPSE */
if (pulse & 02) { /* LPCF */
lp647_don = 0; /* clear done, int */
CLR_INT (LPT); }
if (pulse & 04) {
if ((pulse & 060) < 060) { /* LPLS, LPPB, LPPS */
lp647_iot = (pulse & 060) | (AC & 07); /* save parameters */
lp647_iot = (pulse & 060) | (dat & 07); /* save parameters */
sim_activate (&lp647_unit, lp647_unit.wait); } /* activate */
#if defined (PDP9)
else { /* LPEI */
@ -343,7 +347,7 @@ if (pulse & 04) {
if (lp647_don) SET_INT (LPT); }
#endif
}
return AC;
return dat;
}
/* Unit service. lp647_iot specifies the action to be taken
@ -442,7 +446,7 @@ int32 lp09_ie = 1; /* int enable */
int32 lp09_stopioe = 0;
DEVICE lp09_dev;
int32 lp09_66 (int32 pulse, int32 AC);
int32 lp09_66 (int32 pulse, int32 dat);
int32 lp09_iors (void);
t_stat lp09_svc (UNIT *uptr);
t_stat lp09_reset (DEVICE *dptr);
@ -486,13 +490,13 @@ DEVICE lp09_dev = {
/* IOT routines */
int32 lp09_66 (int32 pulse, int32 AC)
int32 lp09_66 (int32 pulse, int32 dat)
{
int32 sb = pulse & 060; /* subopcode */
if (pulse & 001) {
if ((sb == 000) && lp09_don) AC = IOT_SKP | AC; /* LSDF */
if ((sb == 020) && lp09_err) AC = IOT_SKP | AC; /* LSEF */
if ((sb == 000) && lp09_don) dat = IOT_SKP | dat; /* LSDF */
if ((sb == 020) && lp09_err) dat = IOT_SKP | dat; /* LSEF */
}
if (pulse & 002) {
if (sb == 000) { /* LSCF */
@ -501,11 +505,11 @@ if (pulse & 002) {
else if (sb == 020) { /* LPLD */
lp09_don = 0; /* clear done, int */
CLR_INT (LPT);
lp09_unit.buf = AC & 0177; /* load char */
lp09_unit.buf = dat & 0177; /* load char */
if ((lp09_unit.buf == 015) || (lp09_unit.buf == 014) ||
(lp09_unit.buf == 012))
sim_activate (&lp09_unit, lp09_unit.wait);
else AC = AC | (lp09_svc (&lp09_unit) << IOT_V_REASON); }
else dat = dat | (lp09_svc (&lp09_unit) << IOT_V_REASON); }
}
if (pulse & 004) {
if (sb == 000) { /* LIOF */
@ -515,7 +519,7 @@ if (pulse & 004) {
lp09_ie = 1; /* set int enab */
if (lp09_don) SET_INT (LPT); } /* if done, set int */
}
return AC;
return dat;
}
/* Unit service */
@ -608,8 +612,8 @@ int32 lp15_bp = 0;
char lp15_buf[LP15_BSIZE] = { 0 };
DEVICE lp15_dev;
int32 lp15_65 (int32 pulse, int32 AC);
int32 lp15_66 (int32 pulse, int32 AC);
int32 lp15_65 (int32 pulse, int32 dat);
int32 lp15_66 (int32 pulse, int32 dat);
int32 lp15_iors (void);
t_stat lp15_svc (UNIT *uptr);
t_stat lp15_reset (DEVICE *dptr);
@ -656,18 +660,18 @@ DEVICE lp15_dev = {
/* IOT routines */
int32 lp15_65 (int32 pulse, int32 AC)
int32 lp15_65 (int32 pulse, int32 dat)
{
int32 header, sb;
sb = pulse & 060; /* subopcode */
if (pulse & 01) {
if ((sb == 000) && (lp15_sta & (STA_ERR | STA_DON))) /* LPSF */
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
else if ((sb == 020) || (sb == 040)) { /* LPP1, LPPM */
sim_activate (&lp15_unit, lp15_unit.wait); /* activate */
header = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777;
header = M[(M[LPT_CA] + 1) & AMASK]; /* get first word */
M[LPT_CA] = (M[LPT_CA] + 2) & DMASK;
lp15_mode = header & 1; /* mode */
if (sb == 040) lp15_lc = 1; /* line count */
else lp15_lc = (header >> 9) & 0377;
@ -675,18 +679,18 @@ if (pulse & 01) {
lp15_bp = 0; } /* reset buf ptr */
else if (sb == 060) lp15_ie = 0; /* LPDI */
}
if ((pulse & 02) && (sb == 040)) AC = AC | lp15_updsta (0); /* LPOS, LPRS */
if ((pulse & 02) && (sb == 040)) dat = dat | lp15_updsta (0); /* LPOS, LPRS */
if ((pulse & 04) && (sb == 040)) lp15_ie = 1; /* LPEI */
lp15_updsta (0); /* update status */
return AC;
return dat;
}
int32 lp15_66 (int32 pulse, int32 AC)
int32 lp15_66 (int32 pulse, int32 dat)
{
if (pulse == 021) lp15_sta = lp15_sta & ~STA_DON; /* LPCD */
if (pulse == 041) lp15_sta = 0; /* LPCF */
lp15_updsta (0); /* update status */
return AC;
return dat;
}
/* Unit service */
@ -709,9 +713,9 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
return IORETURN (lp15_stopioe, SCPE_UNATT); }
for (more = 1; more != 0; ) { /* loop until ctrl */
w0 = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */
w1 = M[(M[LPT_CA] + 2) & ADDRMASK]; /* get second word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777; /* advance mem addr */
w0 = M[(M[LPT_CA] + 1) & AMASK]; /* get first word */
w1 = M[(M[LPT_CA] + 2) & AMASK]; /* get second word */
M[LPT_CA] = (M[LPT_CA] + 2) & DMASK; /* advance mem addr */
if (lp15_mode) { /* unpacked? */
c[0] = w0 & 0177;
c[1] = w1 & 0177;

View file

@ -131,7 +131,7 @@ int32 mt_log = 0;
uint8 *mtxb = NULL; /* transfer buffer */
DEVICE mt_dev;
int32 mt (int32 pulse, int32 AC);
int32 mt (int32 pulse, int32 dat);
int32 mt_iors (void);
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
@ -194,7 +194,7 @@ DEVICE mt_dev = {
/* IOT routine */
int32 mt (int32 pulse, int32 AC)
int32 mt (int32 pulse, int32 dat)
{
int32 f, sb;
UNIT *uptr;
@ -205,21 +205,21 @@ sb = pulse & 060; /* subop */
if (pulse & 01) {
if ((sb == 000) && (uptr->flags & UNIT_ATT) && /* MTTR */
!sim_is_active (uptr))
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
else if ((sb == 020) && !mt_busy ()) /* MTCR */
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
else if ((sb == 040) && (mt_sta & (STA_ERR | STA_DON))) /* MTSF */
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
}
if ((pulse & 06) && mt_log)
printf ("[MT%d: IOT=%o, AC=%o, sta=%o]\n",
GET_UNIT (mt_cu), 0707300 + pulse, AC, mt_sta);
GET_UNIT (mt_cu), 0707300 + pulse, dat, mt_sta);
if (pulse & 02) {
if (sb == 000) AC = AC | (mt_cu & 0777700); /* MTRC */
if (sb == 000) dat = dat | (mt_cu & 0777700); /* MTRC */
else if (sb == 020) { /* MTAF, MTLC */
if (!mt_busy ()) mt_cu = mt_sta = 0; /* if not busy, clr */
mt_sta = mt_sta & ~(STA_ERR | STA_DON); } /* clear flags */
else if (sb == 040) AC = AC | mt_sta; /* MTRS */
else if (sb == 040) dat = dat | mt_sta; /* MTRS */
}
if (pulse & 04) {
if (sb == 000) { /* MTGO */
@ -236,10 +236,10 @@ if (pulse & 04) {
else mt_sta = uptr->USTAT = 0; /* no, clear status */
sim_activate (uptr, mt_time); } } /* start io */
if (sb == 020) /* MTCM, MTLC */
mt_cu = (mt_cu & 0770700) | (AC & 0777700); /* load status */
mt_cu = (mt_cu & 0770700) | (dat & 0777700); /* load status */
}
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
return AC;
return dat;
}
/* Unit service
@ -289,9 +289,9 @@ case FN_CMPARE: /* read/compare */
cbc = tbc; /* use smaller */
wc = PACKED (mt_cu)? ((tbc + 2) / 3): ((tbc + 1) / 2); }
for (i = p = 0; i < wc; i++) { /* copy buffer */
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & 0777777;
xma = M[MT_CA] & ADDRMASK;
M[MT_WC] = (M[MT_WC] + 1) & DMASK; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & DMASK;
xma = M[MT_CA] & AMASK;
if (PACKED (mt_cu)) { /* packed? */
c1 = mtxb[p++] & 077;
c2 = mtxb[p++] & 077;
@ -303,16 +303,16 @@ case FN_CMPARE: /* read/compare */
c = (c1 << 8) | c2; }
if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
else if ((f == FN_CMPARE) && (c != (M[xma] &
(PACKED (mt_cu)? 0777777: 0177777)))) {
(PACKED (mt_cu)? DMASK: 0177777)))) {
mt_updcsta (uptr, STA_CPE);
break; } }
break;
case FN_WRITE: /* write */
tbc = PACKED (mt_cu)? wc * 3: wc * 2;
xma = M[MT_CA] & ADDRMASK; /* get mem addr */
xma = M[MT_CA] & AMASK; /* get mem addr */
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
xma = (xma + 1) & ADDRMASK; /* incr mem addr */
xma = (xma + 1) & AMASK; /* incr mem addr */
if (PACKED (mt_cu)) { /* packed? */
mtxb[p++] = (M[xma] >> 12) & 077;
mtxb[p++] = (M[xma] >> 6) & 077;
@ -323,7 +323,7 @@ case FN_WRITE: /* write */
if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) /* write rec, err? */
r = mt_map_err (uptr, st); /* map error */
else {
M[MT_CA] = (M[MT_CA] + wc) & 0777777; /* advance mem addr */
M[MT_CA] = (M[MT_CA] + wc) & DMASK; /* advance mem addr */
M[MT_WC] = 0; } /* clear word cnt */
mt_cu = mt_cu & ~CU_ERASE; /* clear erase flag */
break;
@ -339,7 +339,7 @@ case FN_WREOF:
case FN_SPACEF: /* space forward */
do {
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC */
M[MT_WC] = (M[MT_WC] + 1) & DMASK; /* inc WC */
if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
r = mt_map_err (uptr, st); /* map error */
break; }
@ -349,7 +349,7 @@ case FN_SPACEF: /* space forward */
case FN_SPACER: /* space reverse */
do {
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC */
M[MT_WC] = (M[MT_WC] + 1) & DMASK; /* inc WC */
if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
r = mt_map_err (uptr, st); /* map error */
break; }

View file

@ -149,7 +149,7 @@ if (pulse & 001) {
if (pulse & 002) {
if (sb == 000) AC = AC | rb_make_da (rb_da); /* DBRD */
if (sb == 020) AC = AC | rb_sta; /* DBRS */
if (sb == 040) rb_ma = AC & ADDRMASK; /* DBLM */
if (sb == 040) rb_ma = AC & AMASK; /* DBLM */
}
if (pulse & 004) {
if (sb == 000) rb_da = rb_set_da (AC, rb_da); /* DBLD */
@ -236,7 +236,7 @@ do { if (rb_sta & RBS_WR) { /* write? */
else if (MEM_ADDR_OK (rb_ma)) /* read, valid addr? */
M[rb_ma] = *(((int32 *) uptr->filebuf) + rb_da);
rb_wc = (rb_wc + 1) & 0177777; /* incr word count */
rb_ma = (rb_ma + 1) & ADDRMASK; /* incr mem addr */
rb_ma = (rb_ma + 1) & AMASK; /* incr mem addr */
rb_da = rb_da + 1; /* incr disk addr */
if (rb_da > RB_SIZE) rb_da = 0; /* disk wraparound? */
}

View file

@ -26,6 +26,7 @@
rf (PDP-9) RF09/RF09
(PDP-15) RF15/RS09
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing
12-Feb-03 RMS Removed 8 platter sizing hack
@ -113,8 +114,8 @@ int32 rf_burst = 1; /* burst mode flag */
int32 rf_stopioe = 1; /* stop on error */
DEVICE rf_dev;
int32 rf70 (int32 pulse, int32 AC);
int32 rf72 (int32 pulse, int32 AC);
int32 rf70 (int32 pulse, int32 dat);
int32 rf72 (int32 pulse, int32 dat);
int32 rf_iors (void);
t_stat rf_svc (UNIT *uptr);
t_stat rf_reset (DEVICE *dptr);
@ -151,14 +152,14 @@ REG rf_reg[] = {
{ NULL } };
MTAB rf_mod[] = {
{ UNIT_PLAT, 0, NULL, "1P", &rf_set_size },
{ UNIT_PLAT, 1, NULL, "2P", &rf_set_size },
{ UNIT_PLAT, 2, NULL, "3P", &rf_set_size },
{ UNIT_PLAT, 3, NULL, "4P", &rf_set_size },
{ UNIT_PLAT, 4, NULL, "5P", &rf_set_size },
{ UNIT_PLAT, 5, NULL, "6P", &rf_set_size },
{ UNIT_PLAT, 6, NULL, "7P", &rf_set_size },
{ UNIT_PLAT, 7, NULL, "8P", &rf_set_size },
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
{ UNIT_PLAT, (4 << UNIT_V_PLAT), NULL, "5P", &rf_set_size },
{ UNIT_PLAT, (5 << UNIT_V_PLAT), NULL, "6P", &rf_set_size },
{ UNIT_PLAT, (6 << UNIT_V_PLAT), NULL, "7P", &rf_set_size },
{ UNIT_PLAT, (7 << UNIT_V_PLAT), NULL, "8P", &rf_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
@ -172,14 +173,14 @@ DEVICE rf_dev = {
/* IOT routines */
int32 rf70 (int32 pulse, int32 AC)
int32 rf70 (int32 pulse, int32 dat)
{
int32 t, sb;
sb = pulse & 060; /* subopcode */
if (pulse & 01) {
if ((sb == 000) && (rf_sta & (RFS_ERR | RFS_DON)))
AC = IOT_SKP | AC; /* DSSF */
dat = IOT_SKP | dat; /* DSSF */
else if (sb == 020) rf_reset (&rf_dev); /* DSCC */
else if (sb == 040) { /* DSCF */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
@ -187,19 +188,19 @@ if (pulse & 01) {
}
if (pulse & 02) {
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
else if (sb == 000) AC = AC | rf_dbuf; /* DRBR */
else if (sb == 000) dat = dat | rf_dbuf; /* DRBR */
else if (sb == 020) /* DRAL */
AC = AC | (rf_da & 0777777);
dat = dat | (rf_da & DMASK);
else if (sb == 040) /* DSFX */
rf_sta = rf_sta ^ (AC & (RFS_FNC | RFS_IE)); /* xor func */
rf_sta = rf_sta ^ (dat & (RFS_FNC | RFS_IE)); /* xor func */
else if (sb == 060) /* DRAH */
AC = AC | (rf_da >> 18) | ((rf_sta & RFS_NED)? 010: 0);
dat = dat | (rf_da >> 18) | ((rf_sta & RFS_NED)? 010: 0);
}
if (pulse & 04) {
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
else if (sb == 000) rf_dbuf = AC & 0777777; /* DLBR */
else if (sb == 000) rf_dbuf = dat & DMASK; /* DLBR */
else if (sb == 020) /* DLAL */
rf_da = (rf_da & ~0777777) | (AC & 0777777);
rf_da = (rf_da & ~DMASK) | (dat & DMASK);
else if (sb == 040) { /* DSCN */
rf_sta = rf_sta & ~RFS_DON; /* clear done */
if (GET_FNC (rf_sta) != FN_NOP) {
@ -207,20 +208,20 @@ if (pulse & 04) {
if (t < 0) t = t + RF_NUMWD; /* wrap around? */
sim_activate (&rf_unit, t * rf_time); } } /* schedule op */
else if (sb == 060) { /* DLAH */
rf_da = (rf_da & 0777777) | ((AC & 07) << 18);
rf_da = (rf_da & DMASK) | ((dat & 07) << 18);
if ((uint32) rf_da >= rf_unit.capac) /* for sizing */
rf_updsta (RFS_NED); }
}
rf_updsta (0); /* update status */
return AC;
return dat;
}
int32 rf72 (int32 pulse, int32 AC)
int32 rf72 (int32 pulse, int32 dat)
{
int32 sb = pulse & 060;
if (pulse & 02) {
if (sb == 000) AC = AC | GET_POS (rf_time) | /* DLOK */
if (sb == 000) dat = dat | GET_POS (rf_time) | /* DLOK */
(sim_is_active (&rf_unit)? 0400000: 0);
else if (sb == 040) { /* DSCD */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
@ -228,9 +229,9 @@ if (pulse & 02) {
rf_updsta (0); }
else if (sb == 060) { /* DSRS */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
AC = AC | rf_updsta (0); }
dat = dat | rf_updsta (0); }
}
return AC;
return dat;
}
/* Unit service - assumes the entire disk is buffered */
@ -247,8 +248,8 @@ f = GET_FNC (rf_sta); /* get function */
do { if ((uint32) rf_da >= uptr->capac) { /* disk overflow? */
rf_updsta (RFS_NED); /* nx disk error */
break; }
M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */
pa = M[RF_CA] = (M[RF_CA] + 1) & ADDRMASK; /* incr mem addr */
M[RF_WC] = (M[RF_WC] + 1) & DMASK; /* incr word count */
pa = M[RF_CA] = (M[RF_CA] + 1) & AMASK; /* incr mem addr */
if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */
M[pa] = *(((int32 *) uptr->filebuf) + rf_da);
if ((f == FN_WCHK) && /* write check? */
@ -323,9 +324,9 @@ return attach_unit (uptr, cptr);
t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if ((val < 0) || (val > RF_NUMDK)) return SCPE_IERR;
if (val < 0) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = (val + 1) * RF_DKSIZE;
uptr->capac = UNIT_GETP (val) * RF_DKSIZE;
uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK;
}

View file

@ -144,8 +144,8 @@ int32 rp_swait = 10; /* seek time */
int32 rp_rwait = 10; /* rotate time */
DEVICE rp_dev;
int32 rp63 (int32 pulse, int32 AC);
int32 rp64 (int32 pulse, int32 AC);
int32 rp63 (int32 pulse, int32 dat);
int32 rp64 (int32 pulse, int32 dat);
int32 rp_iors (void);
t_stat rp_svc (UNIT *uptr);
void rp_updsta (int32 newa, int32 newb);
@ -202,7 +202,7 @@ DEVICE rp_dev = {
/* IOT routines */
int32 rp63 (int32 pulse, int32 AC)
int32 rp63 (int32 pulse, int32 dat)
{
int32 sb = pulse & 060; /* subopcode */
@ -210,24 +210,24 @@ rp_updsta (0, 0);
if (pulse & 01) {
if ((sb == 000) && /* DPSF */
((rp_sta & (STA_DON | STA_ERR)) || (rp_stb & STB_ATTN)))
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
else if ((sb == 020) && (rp_stb & STB_ATTN)) /* DPSA */
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
else if ((sb == 040) && (rp_sta & STA_DON)) /* DPSJ */
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
else if ((sb == 060) && (rp_sta & STA_ERR)) /* DPSE */
AC = IOT_SKP | AC;
dat = IOT_SKP | dat;
}
if (pulse & 02) {
if (sb == 000) AC = AC | rp_sta; /* DPOSA */
else if (sb == 020) AC = AC | rp_stb; /* DPOSB */
if (sb == 000) dat = dat | rp_sta; /* DPOSA */
else if (sb == 020) dat = dat | rp_stb; /* DPOSB */
}
if (pulse & 04) {
if (rp_busy) { /* busy? */
rp_updsta (0, STB_PGE);
return AC; }
return dat; }
else if (sb == 000) { /* DPLA */
rp_da = AC & 0777777;
rp_da = dat & DMASK;
if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0);
if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0);
if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0); }
@ -236,38 +236,38 @@ if (pulse & 04) {
rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE |
STB_TME | STB_PGE | STB_EOP);
rp_updsta (0, 0); }
else if (sb == 040) rp_ma = AC & 0777777; /* DPCA */
else if (sb == 060) rp_wc = AC & 0777777; /* DPWC */
else if (sb == 040) rp_ma = dat & DMASK; /* DPCA */
else if (sb == 060) rp_wc = dat & DMASK; /* DPWC */
}
return AC;
return dat;
}
/* IOT 64 */
int32 rp64 (int32 pulse, int32 AC)
int32 rp64 (int32 pulse, int32 dat)
{
int32 u, f, c, sb;
UNIT *uptr;
sb = pulse & 060;
if (pulse & 01) {
if (sb == 020) AC = IOT_SKP | AC; /* DPSN */
if (sb == 020) dat = IOT_SKP | dat; /* DPSN */
}
if (pulse & 02) {
if (sb == 000) AC = AC | rp_unit[GET_UNIT (rp_sta)].CYL; /* DPOU */
else if (sb == 020) AC = AC | rp_da; /* DPOA */
else if (sb == 040) AC = AC | rp_ma; /* DPOC */
else if (sb == 060) AC = AC | rp_wc; /* DPOW */
if (sb == 000) dat = dat | rp_unit[GET_UNIT (rp_sta)].CYL; /* DPOU */
else if (sb == 020) dat = dat | rp_da; /* DPOA */
else if (sb == 040) dat = dat | rp_ma; /* DPOC */
else if (sb == 060) dat = dat | rp_wc; /* DPOW */
}
if (pulse & 04) {
if (rp_busy) { /* busy? */
rp_updsta (0, STB_PGE);
return AC; }
return dat; }
if (sb == 000) rp_sta = rp_sta & ~STA_RW; /* DPCF */
else if (sb == 020) rp_sta = rp_sta & (AC | ~STA_RW); /* DPLZ */
else if (sb == 040) rp_sta = rp_sta | (AC & STA_RW); /* DPLO */
else if (sb == 020) rp_sta = rp_sta & (dat | ~STA_RW); /* DPLZ */
else if (sb == 040) rp_sta = rp_sta | (dat & STA_RW); /* DPLO */
else if (sb == 060) /* DPLF */
rp_sta = (rp_sta & ~STA_RW) | (AC & STA_RW);
rp_sta = (rp_sta & ~STA_RW) | (dat & STA_RW);
rp_sta = rp_sta & ~STA_DON; /* clear done */
u = GET_UNIT (rp_sta); /* get unit num */
uptr = rp_dev.units + u; /* select unit */
@ -286,7 +286,7 @@ if (pulse & 04) {
sim_activate (uptr, MAX (RP_MIN, c + rp_rwait)); } }
}
rp_updsta (0, 0);
return AC;
return dat;
}
/* Unit service
@ -342,7 +342,7 @@ if (rp_sta & (STA_NXS | STA_NXF | STA_NXC)) { /* or bad disk addr? */
rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */
return SCPE_OK; }
pa = rp_ma & ADDRMASK; /* get mem addr */
pa = rp_ma & AMASK; /* get mem addr */
da = GET_DA (rp_da) * RP_NUMWD; /* get disk addr */
wc = 01000000 - rp_wc; /* get true wc */
if (((uint32) (pa + wc)) > MEMSIZE) { /* memory overrun? */
@ -373,8 +373,8 @@ if ((f == FN_WRCHK) && (err == 0)) { /* write check? */
if (comp != M[pa + i]) rp_updsta (0, STB_WCE); }
err = ferror (uptr->fileref); }
rp_wc = (rp_wc + wc) & 0777777; /* final word count */
rp_ma = (rp_ma + wc) & 0777777; /* final mem addr */
rp_wc = (rp_wc + wc) & DMASK; /* final word count */
rp_ma = (rp_ma + wc) & DMASK; /* final mem addr */
da = (da + wc + (RP_NUMWD - 1)) / RP_NUMWD; /* final sector num */
cyl = da / (RP_NUMSC * RP_NUMSF); /* get cyl */
if (cyl >= RP_NUMCY) cyl = RP_NUMCY - 1;

View file

@ -29,6 +29,8 @@
tto teleprinter
clk clock
26-Jul-03 RMS Increased PTP, TTO timeouts for PDP-15 operating systems
Added hardware read-in mode support for PDP-7/9/15
25-Apr-03 RMS Revised for extended file support
14-Mar-03 RMS Clean up flags on detach
01-Mar-03 RMS Added SET/SHOW CLK FREQ support, SET TTI CTRL-C support
@ -62,7 +64,7 @@
#define UNIT_PASCII (1 << UNIT_V_PASCII)
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], saved_PC;
extern int32 int_hwre[API_HLVL+1], PC, ASW;
extern int32 sim_switches;
extern UNIT cpu_unit;
@ -74,10 +76,10 @@ int32 tto_state = 0;
int32 clk_tps = 60; /* ticks/second */
int32 tmxr_poll = 16000; /* term mux poll */
int32 ptr (int32 pulse, int32 AC);
int32 ptp (int32 pulse, int32 AC);
int32 tti (int32 pulse, int32 AC);
int32 tto (int32 pulse, int32 AC);
int32 ptr (int32 pulse, int32 dat);
int32 ptp (int32 pulse, int32 dat);
int32 tti (int32 pulse, int32 dat);
int32 tto (int32 pulse, int32 dat);
int32 clk_iors (void);
int32 ptr_iors (void);
int32 ptp_iors (void);
@ -188,7 +190,7 @@ DEVICE ptr_dev = {
DIB ptp_dib = { DEV_PTP, 1, &ptp_iors, { &ptp } };
UNIT ptp_unit = {
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 1000 };
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
@ -327,7 +329,7 @@ static const char tto_trans[64] = {
DIB tto_dib = { DEV_TTO, 1, &tto_iors, { &tto } };
UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT };
UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), 1000 };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, TTO_WIDTH) },
@ -358,10 +360,10 @@ DEVICE tto_dev = {
/* Clock: IOT routine */
int32 clk (int32 pulse, int32 AC)
int32 clk (int32 pulse, int32 dat)
{
if (pulse & 001) { /* CLSF */
if (TST_INT (CLK)) AC = AC | IOT_SKP; }
if (TST_INT (CLK)) dat = dat | IOT_SKP; }
if (pulse & 004) { /* CLON/CLOF */
if (pulse & 040) { /* CLON */
CLR_INT (CLK); /* clear flag */
@ -370,7 +372,7 @@ if (pulse & 004) { /* CLON/CLOF */
sim_activate (&clk_unit, /* start, calibr */
sim_rtc_init (clk_unit.wait)); }
else clk_reset (&clk_dev); } /* CLOF */
return AC;
return dat;
}
/* Unit service */
@ -380,7 +382,7 @@ t_stat clk_svc (UNIT *uptr)
int32 t;
if (clk_state) { /* clock on? */
M[7] = (M[7] + 1) & 0777777; /* incr counter */
M[7] = (M[7] + 1) & DMASK; /* incr counter */
if (M[7] == 0) SET_INT (CLK); /* ovrflo? set flag */
t = sim_rtc_calb (clk_tps); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */
@ -426,19 +428,19 @@ return SCPE_OK;
/* Paper tape reader: IOT routine */
int32 ptr (int32 pulse, int32 AC)
int32 ptr (int32 pulse, int32 dat)
{
if (pulse & 001) { /* RSF */
if (TST_INT (PTR)) AC = AC | IOT_SKP; }
if (TST_INT (PTR)) dat = dat | IOT_SKP; }
if (pulse & 002) { /* RRB, RCF */
CLR_INT (PTR); /* clear done */
AC = AC | ptr_unit.buf; } /* return buffer */
dat = dat | ptr_unit.buf; } /* return buffer */
if (pulse & 004) { /* RSA, RSB */
ptr_state = (pulse & 040)? 18: 0; /* set mode */
CLR_INT (PTR); /* clear done */
ptr_unit.buf = 0; /* clear buffer */
sim_activate (&ptr_unit, ptr_unit.wait); }
return AC;
return dat;
}
/* Unit service */
@ -526,6 +528,39 @@ ptr_unit.flags = ptr_unit.flags & ~UNIT_RASCII;
return detach_unit (uptr);
}
/* Hardware RIM loader routines, PDP-7/9/15 */
int32 ptr_getw (FILE *fileref, int32 *hi)
{
int32 word, bits, st, ch;
word = st = bits = 0;
do { if ((ch = getc (fileref)) == EOF) return -1;
if (ch & 0200) {
word = (word << 6) | (ch & 077);
bits = (bits << 1) | ((ch >> 6) & 1);
st++; } }
while (st < 3);
if (hi != NULL) *hi = bits;
return word;
}
t_stat ptr_rim_load (FILE *fileref, int32 origin)
{
int32 bits, val;
for (;;) { /* word loop */
if ((val = ptr_getw (fileref, &bits)) < 0) return SCPE_FMT;
if (bits & 1) { /* end of tape? */
if ((val & 0760000) == OP_JMP) {
PC = ((origin - 1) & 060000) | (val & 017777);
return SCPE_OK; }
else if (val == OP_HLT) return STOP_HALT;
break; }
else if (MEM_ADDR_OK (origin)) M[origin++] = val; }
return SCPE_FMT;
}
#if defined (PDP4) || defined (PDP7)
/* Bootstrap routine, PDP-4 and PDP-7
@ -533,12 +568,11 @@ return detach_unit (uptr);
In a 4K system, the boostrap resides at 7762-7776.
In an 8K or greater system, the bootstrap resides at 17762-17776.
Because the program is so small, simple masking can be
used to remove addr<5> for a 4K system.
*/
used to remove addr<5> for a 4K system. */
#define BOOT_START 017577
#define BOOT_FPC 017577
#define BOOT_RPC 017770
#define BOOT_FPC 017577 /* funny format loader */
#define BOOT_RPC 017770 /* RIM loader */
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = {
@ -677,6 +711,10 @@ t_stat ptr_boot (int32 unitno, DEVICE *dptr)
int32 i, mask, wd;
extern int32 sim_switches;
#if defined (PDP7)
if (sim_switches & SWMASK ('H')) /* hardware RIM load? */
return ptr_rim_load (ptr_unit.fileref, ASW);
#endif
if (ptr_dib.dev != DEV_PTR) return STOP_NONSTD; /* non-std addr? */
if (MEMSIZE < 8192) mask = 0767777; /* 4k? */
else mask = 0777777;
@ -684,7 +722,7 @@ for (i = 0; i < BOOT_LEN; i++) {
wd = boot_rom[i];
if ((wd >= 0040000) && (wd < 0640000)) wd = wd & mask;
M[(BOOT_START & mask) + i] = wd; }
saved_PC = ((sim_switches & SWMASK ('F'))? BOOT_FPC: BOOT_RPC) & mask;
PC = ((sim_switches & SWMASK ('F'))? BOOT_FPC: BOOT_RPC) & mask;
return SCPE_OK;
}
@ -694,24 +732,24 @@ return SCPE_OK;
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
return SCPE_ARG;
return ptr_rim_load (ptr_unit.fileref, ASW);
}
#endif
/* Paper tape punch: IOT routine */
int32 ptp (int32 pulse, int32 AC)
int32 ptp (int32 pulse, int32 dat)
{
if (pulse & 001) { /* PSF */
if (TST_INT (PTP)) AC = AC | IOT_SKP; }
if (TST_INT (PTP)) dat = dat | IOT_SKP; }
if (pulse & 002) CLR_INT (PTP); /* PCF */
if (pulse & 004) { /* PSA, PSB, PLS */
CLR_INT (PTP); /* clear flag */
ptp_unit.buf = (pulse & 040)? /* load punch buf */
(AC & 077) | 0200: AC & 0377; /* bin or alpha */
(dat & 077) | 0200: dat & 0377; /* bin or alpha */
sim_activate (&ptp_unit, ptp_unit.wait); } /* activate unit */
return AC;
return dat;
}
/* Unit service */
@ -782,16 +820,16 @@ return detach_unit (uptr);
/* Terminal input: IOT routine */
int32 tti (int32 pulse, int32 AC)
int32 tti (int32 pulse, int32 dat)
{
if (pulse & 001) { /* KSF */
if (TST_INT (TTI)) AC = AC | IOT_SKP; }
if (TST_INT (TTI)) dat = dat | IOT_SKP; }
if (pulse & 002) { /* KRB */
CLR_INT (TTI); /* clear flag */
AC = AC | tti_unit.buf & TTI_MASK; } /* return buffer */
dat = dat | tti_unit.buf & TTI_MASK; } /* return buffer */
if (pulse & 004) { /* IORS */
AC = AC | upd_iors (); }
return AC;
dat = dat | upd_iors (); }
return dat;
}
/* Unit service */
@ -870,15 +908,15 @@ return SCPE_OK;
/* Terminal output: IOT routine */
int32 tto (int32 pulse, int32 AC)
int32 tto (int32 pulse, int32 dat)
{
if (pulse & 001) { /* TSF */
if (TST_INT (TTO)) AC = AC | IOT_SKP; }
if (TST_INT (TTO)) dat = dat | IOT_SKP; }
if (pulse & 002) CLR_INT (TTO); /* clear flag */
if (pulse & 004) { /* load buffer */
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
tto_unit.buf = AC & TTO_MASK; } /* load buffer */
return AC;
tto_unit.buf = dat & TTO_MASK; } /* load buffer */
return dat;
}
/* Unit service */

View file

@ -23,6 +23,8 @@
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.
30-Jul-03 RMS Fixed FPM class mask
18-Jul-03 RMS Added FP15 support
02-Mar-03 RMS Split loaders apart for greater flexibility
09-Feb-03 RMS Fixed bug in FMTASC (found by Hans Pufal)
31-Jan-03 RMS Added support for RB09
@ -47,6 +49,9 @@
#include <ctype.h>
extern DEVICE cpu_dev;
#if defined (PDP15)
extern DEVICE fpp_dev;
#endif
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev;
extern UNIT tti_unit, tto_unit;
@ -87,7 +92,7 @@ extern UNIT cpu_unit;
extern REG cpu_reg[];
extern int32 M[];
extern int32 memm;
extern int32 saved_PC;
extern int32 PC;
/* SCP data structures and interface routines
@ -111,9 +116,13 @@ char sim_name[] = "PDP-15";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 3;
int32 sim_emax = 2;
DEVICE *sim_devices[] = { &cpu_dev,
DEVICE *sim_devices[] = {
&cpu_dev,
#if defined (PDP15)
&fpp_dev,
#endif
&ptr_dev,
&ptp_dev,
&tti_dev,
@ -159,7 +168,8 @@ const char *sim_stop_messages[] = {
"Breakpoint",
"Nested XCT's",
"Invalid API interrupt",
"Non-standard device number" };
"Non-standard device number",
"Memory management error" };
/* Binary loaders */
@ -202,7 +212,7 @@ for (;;) {
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */
saved_PC = ((origin - 1) & 060000) | (val & 017777);
PC = ((origin - 1) & 060000) | (val & 017777);
return SCPE_OK; }
else if (val == OP_HLT) return SCPE_OK; /* HLT? */
else return SCPE_FMT; } /* error */
@ -226,7 +236,7 @@ t_stat r;
if (*cptr != 0) { /* more input? */
cptr = get_glyph (cptr, gbuf, 0); /* get origin */
origin = get_uint (gbuf, 8, ADDRMASK, &r);
origin = get_uint (gbuf, 8, AMASK, &r);
if (r != SCPE_OK) return r;
if (*cptr != 0) return SCPE_ARG; } /* no more */
else origin = 0200; /* default 200 */
@ -234,7 +244,7 @@ else origin = 0200; /* default 200 */
for (;;) { /* word loop */
if ((val = getword (fileref, &bits)) < 0) return SCPE_FMT;
if (bits & 1) { /* end of tape? */
if ((val & 0760000) == OP_JMP) saved_PC =
if ((val & 0760000) == OP_JMP) PC =
((origin - 1) & 060000) | (val & 017777);
else if (val != OP_HLT) return SCPE_FMT;
break; }
@ -258,16 +268,16 @@ return SCPE_OK;
t_stat bin_load_915 (FILE *fileref, char *cptr)
{
int32 i, val, origin, count, cksum;
int32 i, val, bits, origin, count, cksum;
if (*cptr != 0) return SCPE_2MARG; /* no arguments */
do { val = getc (fileref); } /* find end RIM */
while (((val & 0100) == 0) && (val != EOF));
if (val == EOF) rewind (fileref); /* no RIM? rewind */
do { val = getword (fileref, & bits); } /* find end RIM */
while ((val >= 0) && ((bits & 1) == 0));
if (val < 0) rewind (fileref); /* no RIM? rewind */
for (;;) { /* block loop */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (val & SIGN) {
if (val != DMASK) saved_PC = val & 077777;
if (val != DMASK) PC = val & 077777;
break; }
cksum = origin = val; /* save origin */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
@ -328,23 +338,30 @@ return bin_load_915 (fileref, cptr); /* must be BIN */
#define I_V_EST 8 /* EAE setup */
#define I_V_ESH 9 /* EAE shift */
#define I_V_EMD 10 /* EAE mul-div */
#define I_NPN (I_V_NPN << I_V_FL) /* no operand */
#define I_NPI (I_V_NPI << I_V_FL) /* no operand IOT */
#define I_IOT (I_V_IOT << I_V_FL) /* IOT */
#define I_MRF (I_V_MRF << I_V_FL) /* memory reference */
#define I_OPR (I_V_OPR << I_V_FL) /* OPR */
#define I_LAW (I_V_LAW << I_V_FL) /* LAW */
#define I_XR (I_V_XR << I_V_FL) /* index */
#define I_XR9 (I_V_XR9 << I_V_FL) /* index literal */
#define I_EST (I_V_EST << I_V_FL) /* EAE setup */
#define I_ESH (I_V_ESH << I_V_FL) /* EAE shift */
#define I_EMD (I_V_EMD << I_V_FL) /* EAE mul-div */
#define I_V_FPM 11 /* FP15 mem ref */
#define I_V_FPI 12 /* FP15 indirect */
#define I_V_FPN 13 /* FP15 no operand */
#define I_NPN (I_V_NPN << I_V_FL)
#define I_NPI (I_V_NPI << I_V_FL)
#define I_IOT (I_V_IOT << I_V_FL)
#define I_MRF (I_V_MRF << I_V_FL)
#define I_OPR (I_V_OPR << I_V_FL)
#define I_LAW (I_V_LAW << I_V_FL)
#define I_XR (I_V_XR << I_V_FL)
#define I_XR9 (I_V_XR9 << I_V_FL)
#define I_EST (I_V_EST << I_V_FL)
#define I_ESH (I_V_ESH << I_V_FL)
#define I_EMD (I_V_EMD << I_V_FL)
#define I_FPM (I_V_FPM << I_V_FL)
#define I_FPI (I_V_FPI << I_V_FL)
#define I_FPN (I_V_FPN << I_V_FL)
#define MD(x) ((I_EMD) + ((x) << I_V_DC))
static const int32 masks[] = {
0777777, 0777767, 0740000, 0760000,
0777777, 0777767, 0770000, 0760000,
0763730, 0760000, 0777000, 0777000,
0740700, 0760700, 0777700 };
0740700, 0760700, 0777700, 0777777,
0777777, 0777777 };
static const char *opcode[] = {
"CAL", "DAC", "JMS", "DZM", /* mem refs */
@ -452,9 +469,75 @@ static const char *opcode[] = {
#if defined (PDP15)
"SPCO", "SKP15", "RES",
"SBA", "DBA", "EBA",
"ORMM", "RDMM", "LDMM", "MPLR",
"ENB", "INH", "MPRC", "IPFH",
"AAS", "PAX", "PAL", "AAC",
"PXA", "AXS", "PXL", "PLA",
"PLX", "CLAC","CLX", "CLLR", "AXR",
"FPT", /* FP15 */
"ISB", "ESB", /* mem ref */
"FSB", "URFSB", "UNFSB", "UUFSB",
"DSB", "URDSB", "UNDSB", "UUDSB",
"IRS", "ERS",
"FRS", "URFRS", "UNFRS", "UUFRS",
"DRS", "URDRS", "UNDRS", "UUDRS",
"IMP", "EMP",
"FMP", "URFMP", "UNFMP", "UUFMP",
"DMP", "URDMP", "UNDMP", "UUDMP",
"IDV", "EDV",
"FDV", "URFDV", "UNFDV", "UUFDV",
"DDV", "URDDV", "UNDDV", "UUDDV",
"IRD", "ERD",
"FRD", "URFRD", "UNFRD", "UUFRD",
"DRD", "URDRD", "UNDRD", "UUDRD",
"ILD", "ELD",
"FLD", "UNFLD", "DLD", "UNDLD",
"IST", "EST",
"FST", "URFST", "UNFST", "UUFST",
"DST", "UNDST",
"ILF", "UNILF", "ELF", "UNELF",
"FLX", "URFLX", "DLX", "URDLX",
"ILQ", "ELQ",
"FLQ", "UNFLQ", "DLQ", "UNDLQ",
"LJE", "SJE",
"IAD", "EAD",
"FAD", "URFAD", "UNFAD", "UUFAD",
"DAD", "URDAD", "UNDAD", "UUDAD",
"BZA", "BMA", "BLE", "BPA",
"BRU", "BNA", "BAC",
"ISB*", "ESB*", /* indirect */
"FSB*", "URFSB*", "UNFSB*", "UUFSB*",
"DSB*", "URDSB*", "UNDSB*", "UUDSB*",
"IRS*", "ERS*",
"FRS*", "URFRS*", "UNFRS*", "UUFRS*",
"DRS*", "URDRS*", "UNDRS*", "UUDRS*",
"IMP*", "EMP*",
"FMP*", "URFMP*", "UNFMP*", "UUFMP*",
"DMP*", "URDMP*", "UNDMP*", "UUDMP*",
"IDV*", "EDV*",
"FDV*", "URFDV*", "UNFDV*", "UUFDV*",
"DDV*", "URDDV*", "UNDDV*", "UUDDV*",
"IRD*", "ERD",
"FRD*", "URFRD*", "UNFRD*", "UUFRD*",
"DRD*", "URDRD*", "UNDRD*", "UUDRD*",
"ILD*", "ELD",
"FLD*", "UNFLD*", "DLD*", "UNDLD*",
"IST*", "EST",
"FST*", "URFST*", "UNFST*", "UUFST*",
"DST*", "UNDST*",
"ILF*", "UNILF*", "ELF*", "UNELF*",
"FLX*", "URFLX*", "DLX*", "URDLX*",
"ILQ*", "ELQ*",
"FLQ*", "UNFLQ*", "DLQ*", "UNDLQ*",
"LJE*", "SJE*",
"IAD*", "EAD*",
"FAD*", "URFAD*", "UNFAD*", "UUFAD*",
"DAD*", "URDAD*", "UNDAD*", "UUDAD*",
"FLA", "UNFLA", "FXA", "URFXA", /* no operand */
"SWQ", "UNSWQ", "FZR",
"FAB", "FNG", "FCM", "FNM",
#endif
#if defined (PDP9) || defined (PDP15)
"MPSK", "MPSNE", "MPCV", "MPEU",
@ -617,9 +700,74 @@ static const int32 opc_val[] = {
#if defined (PDP15)
0703341+I_NPI, 0707741+I_NPI, 0707742+I_NPI,
0707761+I_NPI, 0707762+I_NPI, 0707764+I_NPI,
0700022+I_NPI, 0700032+I_NPN, 0700024+I_NPI, 0701724+I_NPI,
0705521+I_NPI, 0705522+I_NPI, 0701722+I_NPI, 0701764+I_NPI,
0720000+I_XR9, 0721000+I_XR, 0722000+I_XR, 0723000+I_XR9,
0724000+I_XR, 0725000+I_XR9, 0726000+I_XR, 0730000+I_XR,
0731000+I_XR, 0734000+I_XR, 0735000+I_XR, 0736000+I_XR, 0737000+I_XR9,
0710314+I_FPN,
0710400+I_FPM, 0710500+I_FPM,
0710440+I_FPM, 0710450+I_FPM, 0710460+I_FPM, 0710470+I_FPM,
0710540+I_FPM, 0710550+I_FPM, 0710560+I_FPM, 0710570+I_FPM,
0711000+I_FPM, 0711100+I_FPM,
0711040+I_FPM, 0711050+I_FPM, 0711060+I_FPM, 0711070+I_FPM,
0711140+I_FPM, 0711150+I_FPM, 0711160+I_FPM, 0711170+I_FPM,
0711400+I_FPM, 0711500+I_FPM,
0711440+I_FPM, 0711450+I_FPM, 0711460+I_FPM, 0711470+I_FPM,
0711540+I_FPM, 0711550+I_FPM, 0711560+I_FPM, 0711570+I_FPM,
0712000+I_FPM, 0712100+I_FPM,
0712040+I_FPM, 0712050+I_FPM, 0712060+I_FPM, 0712070+I_FPM,
0712140+I_FPM, 0712150+I_FPM, 0712160+I_FPM, 0712170+I_FPM,
0712400+I_FPM, 0712500+I_FPM,
0712440+I_FPM, 0712450+I_FPM, 0712460+I_FPM, 0712470+I_FPM,
0712540+I_FPM, 0712550+I_FPM, 0712560+I_FPM, 0712570+I_FPM,
0713000+I_FPM, 0713100+I_FPM,
0713050+I_FPM, 0713070+I_FPM, 0713150+I_FPM, 0713170+I_FPM,
0713600+I_FPM, 0713700+I_FPM,
0713640+I_FPM, 0713650+I_FPM, 0713660+I_FPM, 0713670+I_FPM,
0713750+I_FPM, 0713770+I_FPM,
0714010+I_FPM, 0714030+I_FPM, 0714110+I_FPM, 0714130+I_FPM,
0714460+I_FPM, 0714470+I_FPM, 0714560+I_FPM, 0714570+I_FPM,
0715000+I_FPM, 0715100+I_FPM,
0715050+I_FPM, 0715070+I_FPM, 0715150+I_FPM, 0715170+I_FPM,
0715400+I_FPM, 0715600+I_FPM,
0716000+I_FPM, 0716100+I_FPM,
0716040+I_FPM, 0716050+I_FPM, 0716060+I_FPM, 0716070+I_FPM,
0716140+I_FPM, 0716150+I_FPM, 0716160+I_FPM, 0716170+I_FPM,
0716601+I_FPM, 0716602+I_FPM, 0716603+I_FPM,
0716604+I_FPM, 0716606+I_FPM, 0716610+I_FPM, 0716620+I_FPM,
0710400+I_FPI, 0710500+I_FPI, /* indirect */
0710440+I_FPI, 0710450+I_FPI, 0710460+I_FPI, 0710470+I_FPI,
0710540+I_FPI, 0710550+I_FPI, 0710560+I_FPI, 0710570+I_FPI,
0711000+I_FPI, 0711100+I_FPI,
0711040+I_FPI, 0711050+I_FPI, 0711060+I_FPI, 0711070+I_FPI,
0711140+I_FPI, 0711150+I_FPI, 0711160+I_FPI, 0711170+I_FPI,
0711400+I_FPI, 0711500+I_FPI,
0711440+I_FPI, 0711450+I_FPI, 0711460+I_FPI, 0711470+I_FPI,
0711540+I_FPI, 0711550+I_FPI, 0711560+I_FPI, 0711570+I_FPI,
0712000+I_FPI, 0712100+I_FPI,
0712040+I_FPI, 0712050+I_FPI, 0712060+I_FPI, 0712070+I_FPI,
0712140+I_FPI, 0712150+I_FPI, 0712160+I_FPI, 0712170+I_FPI,
0712400+I_FPI, 0712500+I_FPI,
0712440+I_FPI, 0712450+I_FPI, 0712460+I_FPI, 0712470+I_FPI,
0712540+I_FPI, 0712550+I_FPI, 0712560+I_FPI, 0712570+I_FPI,
0713000+I_FPI, 0713100+I_FPI,
0713050+I_FPI, 0713070+I_FPI, 0713150+I_FPI, 0713170+I_FPI,
0713600+I_FPI, 0713700+I_FPI,
0713640+I_FPI, 0713650+I_FPI, 0713660+I_FPI, 0713670+I_FPI,
0713750+I_FPI, 0713770+I_FPI,
0714010+I_FPI, 0714030+I_FPI, 0714110+I_FPI, 0714130+I_FPI,
0714460+I_FPI, 0714470+I_FPI, 0714560+I_FPI, 0714570+I_FPI,
0715000+I_FPI, 0715100+I_FPI,
0715050+I_FPI, 0715070+I_FPI, 0715150+I_FPI, 0715170+I_FPI,
0715400+I_FPI, 0715600+I_FPI,
0716000+I_FPI, 0716100+I_FPI,
0716040+I_FPI, 0716050+I_FPI, 0716060+I_FPI, 0716070+I_FPI,
0716140+I_FPI, 0716150+I_FPI, 0716160+I_FPI, 0716170+I_FPI,
0714210+I_FPN, 0714230+I_FPN, 0714660+I_FPN, 0714670+I_FPN,
0715250+I_FPN, 0715270+I_FPN, 0711200+I_FPN,
0713271+I_FPN, 0713272+I_FPN, 0713273+I_FPN, 0713250+I_FPN,
#endif
#if defined (PDP9) || defined (PDP15)
0701701+I_NPI, 0701741+I_NPI, 0701702+I_NPI, 0701742+I_NPI,
@ -741,7 +889,7 @@ if (!(sw & SWMASK ('M'))) return SCPE_ARG;
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 */
case I_V_NPN: /* no operands */
@ -758,17 +906,17 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
case I_V_MRF: /* mem ref */
#if defined (PDP15)
if (memm) {
disp = inst & 017777;
ma = (addr & 0760000) | disp; }
disp = inst & B_DAMASK;
ma = (addr & (AMASK & ~B_DAMASK)) | disp; }
else {
disp = inst & 007777;
ma = (addr & 0770000) | disp; }
fprintf (of, "%s %-o", opcode[i], (cflag? ma & ADDRMASK: disp));
if (!memm && (inst & 0010000)) fprintf (of, ",X");
disp = inst & P_DAMASK;
ma = (addr & (AMASK & ~P_DAMASK)) | disp; }
fprintf (of, "%s %-o", opcode[i], (cflag? ma & AMASK: disp));
if (!memm && (inst & I_IDX)) fprintf (of, ",X");
#else
disp = inst & 017777;
ma = (addr & 0760000) | disp;
fprintf (of, "%s %-o", opcode[i], (cflag? ma & ADDRMASK: disp));
disp = inst & B_DAMASK;
ma = (addr & (AMASK & ~B_DAMASK)) | disp;
fprintf (of, "%s %-o", opcode[i], (cflag? ma & AMASK: disp));
#endif
break;
case I_V_OPR: /* operate */
@ -796,7 +944,15 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
if (disp == k) fprintf (of, "%s", opcode[i]);
else if (disp < k) fprintf (of, "%s -%-o", opcode[i], k - disp);
else fprintf (of, "%s +%-o", opcode[i], disp - k);
break; } /* end case */
break;
case I_V_FPM: case I_V_FPI: /* FP15 mem ref */
fprintf (of, "%s", opcode[i]);
if (val[1] & SIGN) fputc ('*', of);
fprintf (of, " %-o", val[1] & ~SIGN);
return -1;
case I_V_FPN: /* FP15 no operand */
fprintf (of, "%s", opcode[i]);
return -1; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
@ -838,8 +994,8 @@ return get_uint (cptr, 8, 0777777, status);
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 cflag, d, i, j, k, sign, dmask, epcmask;
t_stat r;
int32 cflag, d, i, j, k, sign, damask, epcmask;
t_stat r, sta = SCPE_OK;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
@ -895,31 +1051,31 @@ case I_V_LAW: /* law */
break;
case I_V_MRF: /* mem ref */
#if defined (PDP15)
if (memm) dmask = 017777;
else dmask = 07777;
if (memm) damask = B_DAMASK;
else damask = P_DAMASK;
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
#else
dmask = 017777;
damask = B_DAMASK;
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
#endif
#if defined (PDP4) || defined (PDP7)
if (strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | 020000;
val[0] = val[0] | I_IND;
cptr = get_glyph (cptr, gbuf, 0); }
#endif
epcmask = ADDRMASK & ~dmask; /* get ePC */
d = get_uint (gbuf, 8, ADDRMASK, &r); /* get addr */
epcmask = AMASK & ~damask; /* get ePC */
d = get_uint (gbuf, 8, AMASK, &r); /* get addr */
if (r != SCPE_OK) return SCPE_ARG;
if (d <= dmask) val[0] = val[0] | d; /* fit in 12/13b? */
if (d <= damask) val[0] = val[0] | d; /* fit in 12/13b? */
else if (cflag && (((addr ^ d) & epcmask) == 0))
val[0] = val[0] | (d & dmask); /* hi bits = ePC? */
val[0] = val[0] | (d & damask); /* hi bits = ePC? */
else return SCPE_ARG;
#if defined (PDP15)
if (!memm) {
cptr = get_glyph (cptr, gbuf, 0);
if (gbuf[0] != 0) {
if (strcmp (gbuf, "X") != 0) return SCPE_ARG;
val[0] = val[0] | 010000; } }
val[0] = val[0] | I_IDX; } }
#endif
break;
case I_V_EMD: /* or'able */
@ -940,7 +1096,23 @@ case I_V_NPN: case I_V_NPI: case I_V_IOT: case I_V_OPR:
if (sign > 0) val[0] = val[0] + d;
else if (sign < 0) val[0] = val[0] - d;
else val[0] = val[0] | d; } }
break;
case I_V_FPM: /* FP15 mem ref */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
val[1] = get_uint (gbuf, 8, AMASK, &r); /* get addr */
if (r != SCPE_OK) return SCPE_ARG;
sta = -1;
break;
case I_V_FPI: /* FP15 ind mem ref */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
val[1] = get_uint (gbuf, 8, AMASK, &r) | SIGN; /* get @addr */
if (r != SCPE_OK) return SCPE_ARG;
sta = -1;
break;
case I_V_FPN: /* FP15 no operand */
val[1] = 0;
sta = -1;
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
return SCPE_OK;
return sta;
}

View file

@ -58,8 +58,8 @@ TMLN tt1_ldsc = { 0 }; /* line descriptors */
TMXR tt_desc = { 1, 0, 0, &tt1_ldsc }; /* mux descriptor */
DEVICE tti1_dev, tto1_dev;
int32 tti1 (int32 pulse, int32 AC);
int32 tto1 (int32 pulse, int32 AC);
int32 tti1 (int32 pulse, int32 dat);
int32 tto1 (int32 pulse, int32 dat);
t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr);
t_stat tti1_reset (DEVICE *dptr);
@ -150,14 +150,14 @@ DEVICE tto1_dev = {
/* Terminal input: IOT routine */
int32 tti1 (int32 pulse, int32 AC)
int32 tti1 (int32 pulse, int32 dat)
{
if (pulse & 001) { /* KSF1 */
if (TST_INT (TTI1)) AC = AC | IOT_SKP; }
if (TST_INT (TTI1)) dat = dat | IOT_SKP; }
if (pulse & 002) { /* KRB1 */
CLR_INT (TTI1); /* clear flag */
AC= AC | tti1_unit.buf; } /* return buffer */
return AC;
dat= dat | tti1_unit.buf; } /* return buffer */
return dat;
}
/* Unit service */
@ -204,15 +204,15 @@ return SCPE_OK;
/* Terminal output: IOT routine */
int32 tto1 (int32 pulse, int32 AC)
int32 tto1 (int32 pulse, int32 dat)
{
if (pulse & 001) { /* TSF */
if (TST_INT (TTO1)) AC = AC | IOT_SKP; }
if (TST_INT (TTO1)) dat = dat | IOT_SKP; }
if (pulse & 002) CLR_INT (TTO1); /* clear flag */
if (pulse & 004) { /* load buffer */
sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */
tto1_unit.buf = AC & 0377; } /* load buffer */
return AC;
tto1_unit.buf = dat & 0377; } /* load buffer */
return dat;
}
/* Unit service */

View file

@ -25,6 +25,7 @@
df DF32 fixed head disk
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing
02-Feb-03 RMS Added variable platter and autosizing support
@ -142,10 +143,10 @@ REG df_reg[] = {
{ NULL } };
MTAB df_mod[] = {
{ UNIT_PLAT, 0, NULL, "1P", &df_set_size },
{ UNIT_PLAT, 1, NULL, "2P", &df_set_size },
{ UNIT_PLAT, 2, NULL, "3P", &df_set_size },
{ UNIT_PLAT, 3, NULL, "4P", &df_set_size },
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &df_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &df_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &df_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &df_set_size },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
@ -338,9 +339,9 @@ return attach_unit (uptr, cptr);
t_stat df_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if ((val < 0) || (val >= DF_NUMDK)) return SCPE_IERR;
if (val < 0) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = (val + 1) * DF_DKSIZE;
uptr->capac = UNIT_GETP (val) * DF_DKSIZE;
uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK;
}

View file

@ -25,6 +25,7 @@
rf RF08 fixed head disk
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing
02-Feb-03 RMS Added variable platter and autosizing support
@ -154,10 +155,10 @@ REG rf_reg[] = {
{ NULL } };
MTAB rf_mod[] = {
{ UNIT_PLAT, 0, NULL, "1P", &rf_set_size },
{ UNIT_PLAT, 1, NULL, "2P", &rf_set_size },
{ UNIT_PLAT, 2, NULL, "3P", &rf_set_size },
{ UNIT_PLAT, 3, NULL, "4P", &rf_set_size },
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
@ -391,9 +392,9 @@ return attach_unit (uptr, cptr);
t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if ((val < 0) || (val >= RF_NUMDK)) return SCPE_IERR;
if (val < 0) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = (val + 1) * RF_DKSIZE;
uptr->capac = UNIT_GETP (val) * RF_DKSIZE;
uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK;
}

View file

@ -170,8 +170,9 @@ for channel W, entry [1] for channel Y, etc.
MODE[0:7] 12 channel mode (from EOM instruction)
FLAG[0:7] 9 channel flags
The user can display all the registers in a channel with the command SHOW
CHAN <chan>.
The user can display all the registers in a channel with the command:
SHOW CHAN channel-letter
2.3 Console Input (TTI)
@ -364,7 +365,7 @@ The lines (MUXL) implements these registers:
TIME[0:31] 24 transmit time, lines 0 to 31
The additional terminals do not support save and restore. All open
The terminal multiplexor does not support save and restore. All open
connections are lost when the simulator shuts down or MUX is detached.
2.10 Project Genie Drum (DRM)
@ -419,11 +420,8 @@ Error handling is as follows:
not attached 1 report error and stop
0 disk not ready
end of file x assume rest of disk is zero
OS I/O error x report error and stop
By default, the rapid access disk is assigned to channel E.
The rapid access disk is buffered in memory; end of file and OS I/O errors
cannot occur. By default, the rapid access disk is assigned to channel E.
2.12 Moving Head Disk (DSK)
@ -456,9 +454,12 @@ Error handling is as follows:
not attached 1 report error and stop
0 disk not ready
Rapid access disk data files are buffered in memory; therefore, end of file
and OS I/O errors cannot occur. By default, the rapid access disk is
assigned to channel F.
end of file x assume rest of disk is zero
OS I/O error x report error and stop
By default, the moving head disk is assigned to channel F.
2.13 Magnetic Tape (MT)

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: VAX Simulator Usage
Date: 15-Jun-2003
Date: 15-Jul-2003
COPYRIGHT NOTICE
@ -37,17 +37,20 @@ This memorandum documents the VAX simulator.
1. Simulator Files
To compile the VAX, you must define VM_VAX and USE_INT64 as part of the compilation
command line.
command line. To enable extended file support (files greater than 2GB), you must
define USE_ADDR64 as part of the command line as well.
sim/ sim_defs.h
sim_ether.h
sim_rev.h
sim_sock.h
sim_tape.h
sim_tmxr.h
scp.c
scp_tty.c
sim_ether.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/vax/ vax_defs.h
@ -59,6 +62,7 @@ sim/vax/ vax_defs.h
vax_mmu.c
vax_stddev.c
vax_sys.c
vax_sysdev.c
sim/pdp11/ pdp11_mscp.h
pdp11_uqssp.h
@ -90,7 +94,7 @@ PTR,PTP PCV11 paper tape reader/punch
TTI,TTO console terminal
LPT LPV11 line printer
CLK real-time clock
DZ DZV11 8-line terminal multiplexor (up to 4)
DZ DZV11 4-line terminal multiplexor (up to 4)
RL RLV12/RL01(2) cartridge disk controller with four drives
RQ RQDX3 MSCP controller with four drives
RQB second RQDX3 MSCP controller with four drives
@ -130,6 +134,9 @@ HALT instruction.
SET CPU 64M set memory size = 64MB
SET CPU SIMHALT kernel HALT returns to simulator
SET CPU CONHALT kernel HALT returns to boot ROM console
The CPU implements a show command to display the I/O address map:
SHOW CPU IOSPACE show I/O space address map
If memory size is being reduced, and the memory being truncated contains
@ -201,10 +208,10 @@ control registers for the interrupt system.
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY -- clear history buffer
SET CPU HISTORY=0 -- disable history
SET CPU HISTORY=n -- enable history, display length = n
SHOW CPU HISTORY -- print CPU history
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, display length = n
SHOW CPU HISTORY print CPU history
The maximum length for the history is 4096 entries.
@ -225,15 +232,15 @@ The boot ROM consists of a single unit, representing the 128KB boot ROM.
It has no registers. The boot ROM is loaded with a binary byte stream
using the LOAD -r command:
LOAD -r KA655.BIN -- load boot ROM image KA655.BIN
LOAD -r KA655.BIN load boot ROM image KA655.BIN
ROM accesses a use a calibrated delay that slows ROM-based execution to
about 500K instructions per second. This delay is required to make the
power-up self-test routines run correctly on very fast hosts. The delay
is controlled with the commands:
SET ROM NODELAY -- ROM runs like RAM
SET ROM DELAY -- ROM runs slowly
SET ROM NODELAY ROM runs like RAM
SET ROM DELAY ROM runs slowly
2.1.4 Non-volatile Memory (NVR)
@ -491,16 +498,16 @@ The clock (CLK) implements these registers:
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.3.7 DZ11 Terminal Multiplexor (DZ)
2.3.7 DZV11 Terminal Multiplexor (DZ)
The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines)
The DZV11 is an 4-line terminal multiplexor. Up to 4 DZ11's (16 lines)
are supported. The number of lines can be changed with the command
SET DZ LINES=n set line count to n
SET DZ LINES=n set line count to n
The line count must be a multiple of 4, with a maximum of 16.
The DZ11 supports 8-bit input and output of characters. 8-bit output
The DZV11 supports 8-bit input and output of characters. 8-bit output
may be incompatible with certain operating systems. The command
SET DZ 7B
@ -511,12 +518,15 @@ The terminal lines perform input and output through Telnet sessions
connected to a user-specified port. The ATTACH command specifies
the port to be used:
ATTACH {-am} DZ <port> set up listening port
ATTACH {-am} DZ <port> set up listening port
where port is a decimal number between 1 and 65535 that is not being used
for other TCP/IP activities. The optional switch -m turns on the DZ11's
for other TCP/IP activities. The optional switch -m turns on the DZV11's
modem controls; the optional switch -a turns on active disconnects
(disconnect session if computer clears Data Terminal Ready).
(disconnect session if computer clears Data Terminal Ready). Without
modem control, the DZ behaves as though terminals were directly connected;
disconnecting the Telnet session does not cause any operating system-
visible change in line status.
Once the DZ is attached and the simulator is running, the DZ will listen
for connections on the specified port. It assumes that the incoming
@ -528,7 +538,7 @@ The SHOW DZ CONNECTIONS command displays the current connections to the DZ.
The SHOW DZ STATISTICS command displays statistics for active connections.
The SET DZ DISCONNECT=linenumber disconnects the specified line.
The DZ11 implements these registers:
The DZV11 implements these registers:
name size comments
@ -544,7 +554,7 @@ The DZ11 implements these registers:
MDMTCL 1 modem control enabled
AUTODS 1 autodisconnect enabled
The DZ11 does not support save and restore. All open connections are
The DZV11 does not support save and restore. All open connections are
lost when the simulator shuts down or the DZ is detached.
2.4 RLV12/RL01,RL02 Cartridge Disk (RL)
@ -613,9 +623,14 @@ of many disk types:
SET RQn RA72 set type to RA72
SET RQn RA90 set type to RA90
SET RQn RA92 set type to RA92
SET RQn RA81 set type to RA81 with n LBN's.
SET RQn RAUSER{=n} set type to RA81 with n LBN's
The type options can be used only when a unit is not attached to a file.
RAUSER is a "user specified" disk; the user can specify the size of the
disk in logical block numbers (LBN's, 512 bytes each). The minimum size
is 50MB. The maximum size is 2GB if the simulator is compiled without
64b addressing, 1000GB with 64b addressing.
Units can also be set ONLINE or OFFLINE.
Each RQ controller implements the following special SHOW commands:
@ -662,13 +677,13 @@ Each RQ controller implements these registers:
Error handling is as follows:
error processed as
error processed as
not attached disk not ready
not attached disk not ready
end of file assume rest of disk is zero
end of file assume rest of disk is zero
OS I/O error report error and stop
OS I/O error report error and stop
2.6 TSV11/TSV05 Magnetic Tape (TS)
@ -780,13 +795,13 @@ The TQ controller implements these registers:
Error handling is as follows:
error processed as
error processed as
not attached tape not ready
not attached tape not ready
end of file end of medium
end of file end of medium
OS I/O error report error and stop
OS I/O error report error and stop
2.8 DELQA/DEQNA Qbus Ethernet Controllers (XQ, XQB)
@ -840,18 +855,18 @@ controller will behave as though the ethernet cable were unplugged.
XQ has the following registers:
name size comments
name size comments
SA0 16 station address word 0
SA1 16 station address word 1
SA2 16 station address word 2
SA3 16 station address word 3
SA4 16 station address word 4
SA5 16 station address word 5
CSR 16 control status register
VAR 16 vector address register
RBDL 32 receive buffer descriptor list
XBDL 32 trans(X)mit buffer descriptorlList
SA0 16 station address word 0
SA1 16 station address word 1
SA2 16 station address word 2
SA3 16 station address word 3
SA4 16 station address word 4
SA5 16 station address word 5
CSR 16 control status register
VAR 16 vector address register
RBDL 32 receive buffer descriptor list
XBDL 32 trans(X)mit buffer descriptorlList
One final note: because of it's asynchronous nature, the XQ controller is
not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers,

File diff suppressed because it is too large Load diff

View file

@ -61,7 +61,7 @@ PDP18BD = PDP18B/
PDP18B = ${PDP18BD}pdp18b_dt.c ${PDP18BD}pdp18b_drm.c ${PDP18BD}pdp18b_cpu.c \
${PDP18BD}pdp18b_lp.c ${PDP18BD}pdp18b_mt.c ${PDP18BD}pdp18b_rf.c \
${PDP18BD}pdp18b_rp.c ${PDP18BD}pdp18b_stddev.c ${PDP18BD}pdp18b_sys.c \
${PDP18BD}pdp18b_rb.c ${PDP18BD}pdp18b_tt1.c
${PDP18BD}pdp18b_rb.c ${PDP18BD}pdp18b_tt1.c ${PDP18BD}pdp18b_fpp.c
PDP4_OPT = -DPDP4 -I ${PDP18BD}
PDP7_OPT = -DPDP7 -I ${PDP18BD}
PDP9_OPT = -DPDP9 -I ${PDP18BD}
@ -150,7 +150,8 @@ IBM1130D = Ibm1130/
IBM1130 = ${IBM1130D}ibm1130_cpu.c ${IBM1130D}ibm1130_cr.c \
${IBM1130D}ibm1130_disk.c ${IBM1130D}ibm1130_stddev.c \
${IBM1130D}ibm1130_sys.c ${IBM1130D}ibm1130_gdu.c \
${IBM1130D}ibm1130_gui.c ${IBM1130D}ibm1130_prt.c
${IBM1130D}ibm1130_gui.c ${IBM1130D}ibm1130_prt.c \
${IBM1130D}ibm1130_fmt.c
IBM1130_OPT = -I ${IBM1130D}

4
scp.c
View file

@ -23,6 +23,7 @@
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.
15-Jul-03 RMS Removed unnecessary test in reset_all
15-Jun-03 RMS Added register flag REG_VMIO
25-Apr-03 RMS Added extended address support (V3.0)
Fixed bug in SAVE (found by Peter Schorn)
@ -1324,7 +1325,6 @@ DEVICE *dptr;
uint32 i;
t_stat reason;
if (start < 0) return SCPE_IERR;
for (i = 0; i < start; i++) {
if (sim_devices[i] == NULL) return SCPE_IERR; }
for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
@ -3729,7 +3729,7 @@ for (i = 0; i < sec; i++) { /* loop */
c = sim_os_poll_kbd (); /* check for stop char */
if ((c == SCPE_STOP) || stop_cpu) return SCPE_STOP;
if ((i % 10) == 0) { /* Status every 10 sec */
printf ("Waiting for console Telnet connnection\n");
printf ("Waiting for console Telnet connection\n");
fflush (stdout); }
sim_os_sleep (1); /* wait 1 second */
}

View file

@ -185,9 +185,9 @@ int32 i;
sys$gettim (tod); /* time 0.1usec */
/* To convert to msec, must divide 64b quantity by 10000. This is actually done
/* To convert to msec, must divide a 64b quantity by 10000. This is actually done
by dividing the 96b quantity 0'time by 10000, producing 64b of quotient, the
high 32b of which are discared. This can probably be done by a clever multiply...
high 32b of which are discarded. This can probably be done by a clever multiply...
*/
quo = htod = 0;

View file

@ -29,12 +29,64 @@
#define SIM_MAJOR 3
#define SIM_MINOR 0
#define SIM_PATCH 0
#define SIM_PATCH 1
/* V3.0 revision history
patch date module(s) and fix(es)
1 27-Jul-03 pdp1_cpu.c: updated to detect indefinite I/O wait
pdp1_drm.c: fixed incorrect logical, missing activate, break
pdp1_lp.c:
-- fixed bugs in instruction decoding, overprinting
-- updated to detect indefinite I/O wait
pdp1_stddev.c:
-- changed RIM loader to be "hardware"
-- updated to detect indefinite I/O wait
pdp1_sys.c: added block loader format support to LOAD
pdp10_rp.c: fixed bug in read header
pdp11_rq: fixed bug in user disk size (found by Chaskiel M Grundman)
pdp18b_cpu.c:
-- added FP15 support
-- added XVM support
-- added EAE support to the PDP-4
-- added PDP-15 "re-entrancy ECO"
-- fixed memory protect/skip interaction
-- fixed CAF to only reset peripherals
pdp18b_fpp.c: added FP15
pdp18b_lp.c: fixed bug in Type 62 overprinting
pdp18b_rf.c: fixed bug in set size routine
pdp18b_stddev.c:
-- increased PTP TIME for PDP-15 operating systems
-- added hardware RIM loader for PDP-7, PDP-9, PDP-15
pdp18b_sys.c: added FP15, KT15, XVM instructions
pdp8b_df.c, pdp8_rf.c: fixed bug in set size routine
hp2100_dr.c:
-- fixed drum sizes
-- fixed variable capacity interaction with SAVE/RESTORE
i1401_cpu.c: revised fetch to model hardware more closely
ibm1130: fixed bugs found by APL 1130
nova_dsk.c: fixed bug in set size routine
altairz80: fixed bug in real-time clock on Windows host
0 15-Jun-03 scp.c:
-- added ASSIGN/DEASSIGN
-- changed RESTORE to detach files

View file

@ -528,7 +528,7 @@ if (map) map[objc] = tpos;
return objc;
}
/* Find the preceding record length in a TPC file */
/* Find the preceding record in a TPC file */
t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map)
{

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: Simulator Usage, V3.0
Date: 15-May-2004
Subj: Simulator Usage, V3.1
Date: 15-Jul-2003
COPYRIGHT NOTICE
@ -155,8 +155,7 @@ Examples:
The Windows-specific Ethernet code uses the WinPCAP 3.0 package.
This package for windows simulates the libpcap package that is freely
available for Unix systems. Note that WinPCAP DOES NOT SUPPORT dual
CPU environments.
available for Unix systems.
WinPCAP must be installed prior to building the PDP-11 and VAX
simulators with Ethernet support.

View file

@ -199,25 +199,13 @@ the source kit.
2.2 How do I install SIMH with Ethernet support on Windows?
First, you must download download and install the WinPCAP AutoInstaller and
developer's kit from
The pre-compiled binaries contain Ethernet support. Before running these
binaries, you must download download and install the WinPCAP AutoInstaller from
http://winpcap.polito.it
This creates a network packet driver in Windows for SIMH to attach to.
Second, you must download the Gnu C compiler. You can get a Windows compatible
GNU C compiler from:
http://www.mingw.org
Third, place the include (.h) files from the developer's kit in the C
compiler's include folder, and the libraries from the developer's kit in C
compiler's library folder.
Then, the batch file build_mingw_ether.bat can be used to build all the
simulators, with Ethernet suport where appropriate.
To use network support, you must either be an administrator on the Windows
machine (implied in Windows 9X), or you must set the windows packet driver to
autostart when the system boots; see the WinPCAP FAQ page for detailed