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 RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially
clean directory. 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. - Added ASSIGN/DEASSIGN (logical name) commands.
- Changed RESTORE to unconditionally detach files. - Changed RESTORE to unconditionally detach files.
@ -13,7 +77,7 @@ clean directory.
- Fixed bug in SHOW CONNECTIONS. - Fixed bug in SHOW CONNECTIONS.
- Added USE_ADDR64 support - Added USE_ADDR64 support
1.2 All magtapes 3.2 All magtapes
- Magtapes support SIMH format, E11 format, and TPC format (read only). - Magtapes support SIMH format, E11 format, and TPC format (read only).
- SET <tape_unit> FORMAT=format sets the specified tape unit's format. - 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 - Tape format can also be set as part of the ATTACH command, using
the -F switch. the -F switch.
1.3 VAX 3.3 VAX
- VAX can be compiled without USE_INT64. - VAX can be compiled without USE_INT64.
- If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support
files > 2GB. files > 2GB.
- VAX ROM has speed control (SET ROM DELAY/NODELAY). - 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 CVTfi bug: integer overflow not set if exponent out of range
- Fixed EMODx bugs: - Fixed EMODx bugs:
@ -41,7 +105,7 @@ clean directory.
- Fixed interval timer and ROM access to pass power-up self-test even on very - Fixed interval timer and ROM access to pass power-up self-test even on very
fast host processors (fixes from Mark Pizzolato). 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 mnemonic, instruction lengths, and reverse scan length check bug for MCS.
- Fixed MCE bug, BS off by 1 if zero suppress. - Fixed MCE bug, BS off by 1 if zero suppress.
@ -50,15 +114,15 @@ clean directory.
- Added check for invalid 8 character MCW, LCA. - Added check for invalid 8 character MCW, LCA.
- Fixed magtape load-mode end of record response. - Fixed magtape load-mode end of record response.
2.3 Nova 4.3 Nova
- Fixed DSK variable size interaction with restore. - Fixed DSK variable size interaction with restore.
2.4 PDP-1 4.4 PDP-1
- Fixed DT variable size interaction with restore. - Fixed DT variable size interaction with restore.
2.5 PDP-11 4.5 PDP-11
- Fixed DT variable size interaction with restore. - Fixed DT variable size interaction with restore.
- Fixed bug in MMR1 update (found by Tim Stark). - 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 ability to split received packet into multiple buffers.
o Added explicit runt and giant packet processing. 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 DT, RF variable size interaction with restore.
- Fixed MT bug in MTTR. - Fixed MT bug in MTTR.
2.7 PDP-8 4.7 PDP-8
- Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed DT, DF, RF, RX variable size interaction with restore.
- Fixed MT bug in SKTR. - 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 (13210A controller only), DQ read status.
- Fixed bug in DP, DQ seek complete. - Fixed bug in DP, DQ seek complete.
2.9 GRI 4.9 GRI
- Fixed bug in SC queue pointer management. - 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 /* 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), 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 */ /* SIMH pseudo device status registers */
/* ZSDOS clock definitions */ /* 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 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 setClockZSDOSAdr = 0; /* address in M of 6 byte parameter block for setting time */
static int32 getClockZSDOSPos = 0; /* determines state for sending clock information */ static int32 getClockZSDOSPos = 0; /* determines state for sending clock information */
/* CPM3 clock definitions */ /* 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 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 setClockCPM3Adr = 0; /* address in M of 5 byte parameter block for setting time */
static int32 getClockCPM3Pos = 0; /* determines state for sending clock information */ 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 cpmCommandLineLength 128
#define splimit 10 /* stack depth of timer stack */ #define splimit 10 /* stack depth of timer stack */
static uint32 markTime[splimit]; /* 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 char version[] = "SIMH002";
static t_stat simh_dev_reset(DEVICE *dptr) { static t_stat simh_dev_reset(DEVICE *dptr) {
currentTime = NULL; currentTimeValid = FALSE;
ClockZSDOSDelta = 0; ClockZSDOSDelta = 0;
setClockZSDOSPos = 0; setClockZSDOSPos = 0;
getClockZSDOSPos = 0; getClockZSDOSPos = 0;
@ -783,7 +784,7 @@ static void setClockCPM3(void) {
} }
static int32 simh_in(const int32 port) { static int32 simh_in(const int32 port) {
int32 result; int32 result = 0;
switch(lastCommand) { switch(lastCommand) {
case attachPTRCmd: case attachPTRCmd:
case attachPTPCmd: case attachPTPCmd:
@ -791,31 +792,31 @@ static int32 simh_in(const int32 port) {
lastCommand = 0; lastCommand = 0;
break; break;
case getClockZSDOSCmd: case getClockZSDOSCmd:
if (currentTime) { if (currentTimeValid) {
switch(getClockZSDOSPos) { switch(getClockZSDOSPos) {
case 0: case 0:
result = toBCD(currentTime -> tm_year > 99 ? result = toBCD(currentTime.tm_year > 99 ?
currentTime -> tm_year - 100 : currentTime -> tm_year); currentTime.tm_year - 100 : currentTime.tm_year);
getClockZSDOSPos = 1; getClockZSDOSPos = 1;
break; break;
case 1: case 1:
result = toBCD(currentTime -> tm_mon + 1); result = toBCD(currentTime.tm_mon + 1);
getClockZSDOSPos = 2; getClockZSDOSPos = 2;
break; break;
case 2: case 2:
result = toBCD(currentTime -> tm_mday); result = toBCD(currentTime.tm_mday);
getClockZSDOSPos = 3; getClockZSDOSPos = 3;
break; break;
case 3: case 3:
result = toBCD(currentTime -> tm_hour); result = toBCD(currentTime.tm_hour);
getClockZSDOSPos = 4; getClockZSDOSPos = 4;
break; break;
case 4: case 4:
result = toBCD(currentTime -> tm_min); result = toBCD(currentTime.tm_min);
getClockZSDOSPos = 5; getClockZSDOSPos = 5;
break; break;
case 5: case 5:
result = toBCD(currentTime -> tm_sec); result = toBCD(currentTime.tm_sec);
getClockZSDOSPos = lastCommand = 0; getClockZSDOSPos = lastCommand = 0;
break; break;
} }
@ -825,7 +826,7 @@ static int32 simh_in(const int32 port) {
} }
break; break;
case getClockCPM3Cmd: case getClockCPM3Cmd:
if (currentTime) { if (currentTimeValid) {
switch(getClockCPM3Pos) { switch(getClockCPM3Pos) {
case 0: case 0:
result = daysCPM3SinceOrg & 0xff; result = daysCPM3SinceOrg & 0xff;
@ -836,15 +837,15 @@ static int32 simh_in(const int32 port) {
getClockCPM3Pos = 2; getClockCPM3Pos = 2;
break; break;
case 2: case 2:
result = toBCD(currentTime -> tm_hour); result = toBCD(currentTime.tm_hour);
getClockCPM3Pos = 3; getClockCPM3Pos = 3;
break; break;
case 3: case 3:
result = toBCD(currentTime -> tm_min); result = toBCD(currentTime.tm_min);
getClockCPM3Pos = 4; getClockCPM3Pos = 4;
break; break;
case 4: case 4:
result = toBCD(currentTime -> tm_sec); result = toBCD(currentTime.tm_sec);
getClockCPM3Pos = lastCommand = 0; getClockCPM3Pos = lastCommand = 0;
break; break;
} }
@ -1012,7 +1013,8 @@ static int32 simh_out(const int32 port, const int32 data) {
case getClockZSDOSCmd: case getClockZSDOSCmd:
time(&now); time(&now);
now += ClockZSDOSDelta; now += ClockZSDOSDelta;
currentTime = localtime(&now); currentTime = *localtime(&now);
currentTimeValid = TRUE;
getClockZSDOSPos = 0; getClockZSDOSPos = 0;
break; break;
case setClockZSDOSCmd: case setClockZSDOSCmd:
@ -1021,7 +1023,8 @@ static int32 simh_out(const int32 port, const int32 data) {
case getClockCPM3Cmd: case getClockCPM3Cmd:
time(&now); time(&now);
now += ClockCPM3Delta; now += ClockCPM3Delta;
currentTime = localtime(&now); currentTime = *localtime(&now);
currentTimeValid = TRUE;
daysCPM3SinceOrg = (now - mkCPM3Origin()) / secondsPerDay; daysCPM3SinceOrg = (now - mkCPM3Origin()) / secondsPerDay;
getClockCPM3Pos = 0; getClockCPM3Pos = 0;
break; break;

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: H316 Simulator Usage Subj: H316 Simulator Usage
Date: 20-Apr-2003 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -51,7 +51,7 @@ sim/h316/ h316_defs.h
h316_cpu.c h316_cpu.c
h316_lp.c h316_lp.c
h316_stddev.c h316_stddev.c
h316_cpu.c h316_sys.c
2. H316/H516 Features 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 The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time. 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 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, 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 - 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 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 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 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 there is no valid PC, and C must be used to specify current sector addressing.
sector addressing.
I/O instructions have the format I/O instructions have the format

View file

@ -1,14 +1,14 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: HP2100 Simulator Usage Subj: HP2100 Simulator Usage
Date: 15-Nov-2002 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary: The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), 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/ sim_defs.h
sim_rev.h sim_rev.h
sim_sock.h sim_sock.h
sim_tape.h
sim_tmxr.h sim_tmxr.h
scp.c scp.c
scp_tty.c scp_tty.c
sim_sock.c sim_sock.c
sim_tape.c
sim_tmxr.c sim_tmxr.c
sim/hp2100/ hp2100_defs.h sim/hp2100/ hp2100_defs.h
@ -563,7 +565,6 @@ Both IPLI and IPLO implement these registers:
TIME 24 polling interval for input TIME 24 polling interval for input
STOP_IOE 1 stop on I/O error STOP_IOE 1 stop on I/O error
2.5 12557A Disk Controller (DPC, DPD) with 2781 Drives 2.5 12557A Disk Controller (DPC, DPD) with 2781 Drives
13210A Disk Controller (DPC, DPD) with 7900 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. 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 10-Nov-02 RMS Added BOOT command
*/ */
@ -48,8 +50,21 @@
#define DR_DNUMSC 32 /* drum sec/track */ #define DR_DNUMSC 32 /* drum sec/track */
#define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC) #define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)
#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */ #define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */
#define UNIT_V_DR (UNIT_V_UF) /* disk vs drum */ #define UNIT_V_SZ (UNIT_V_UF) /* disk vs drum */
#define UNIT_DR (1 << UNIT_V_DR) #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 */ /* Command word */
@ -105,11 +120,16 @@ int32 drd_ptr = 0; /* sector pointer */
int32 dr_stopioe = 1; /* stop on error */ int32 dr_stopioe = 1; /* stop on error */
int32 dr_time = 10; /* time per word */ 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; DEVICE drd_dev, drc_dev;
int32 drdio (int32 inst, int32 IR, int32 dat); int32 drdio (int32 inst, int32 IR, int32 dat);
int32 drcio (int32 inst, int32 IR, int32 dat); int32 drcio (int32 inst, int32 IR, int32 dat);
t_stat drc_svc (UNIT *uptr); t_stat drc_svc (UNIT *uptr);
t_stat drc_reset (DEVICE *dptr); t_stat drc_reset (DEVICE *dptr);
t_stat drc_attach (UNIT *uptr, char *cptr);
t_stat drc_boot (int32 unitno, DEVICE *dptr); t_stat drc_boot (int32 unitno, DEVICE *dptr);
int32 dr_incda (int32 trk, int32 sec, int32 ptr); int32 dr_incda (int32 trk, int32 sec, int32 ptr);
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); 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 }, { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, dr_stopioe, 0) }, { FLDATA (STOP_IOE, dr_stopioe, 0) },
{ ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO }, { ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO },
{ DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO },
{ NULL } }; { NULL } };
MTAB drc_mod[] = { MTAB drc_mod[] = {
{ UNIT_DR, 0, "disk", NULL, NULL }, { UNIT_DR, 0, "disk", NULL, NULL },
{ UNIT_DR, UNIT_DR, "drum", NULL, NULL }, { UNIT_DR, UNIT_DR, "drum", NULL, NULL },
{ UNIT_DR, 184320, NULL, "180K", &dr_set_size }, { UNIT_SZ, (SZ_180K << UNIT_V_SZ), NULL, "180K", &dr_set_size },
{ UNIT_DR, 368640, NULL, "360K", &dr_set_size }, { UNIT_SZ, (SZ_360K << UNIT_V_SZ), NULL, "360K", &dr_set_size },
{ UNIT_DR, 737280, NULL, "720K", &dr_set_size }, { UNIT_SZ, (SZ_720K << UNIT_V_SZ), NULL, "720K", &dr_set_size },
{ UNIT_DR, 368640+1, NULL, "384K", &dr_set_size }, { UNIT_SZ, (SZ_384K << UNIT_V_SZ), NULL, "384K", &dr_set_size },
{ UNIT_DR, 524280+1, NULL, "512K", &dr_set_size }, { UNIT_SZ, (SZ_512K << UNIT_V_SZ), NULL, "512K", &dr_set_size },
{ UNIT_DR, 655360+1, NULL, "640K", &dr_set_size }, { UNIT_SZ, (SZ_640K << UNIT_V_SZ), NULL, "640K", &dr_set_size },
{ UNIT_DR, 786432+1, NULL, "768K", &dr_set_size }, { UNIT_SZ, (SZ_768K << UNIT_V_SZ), NULL, "768K", &dr_set_size },
{ UNIT_DR, 917504+1, NULL, "896K", &dr_set_size }, { UNIT_SZ, (SZ_896K << UNIT_V_SZ), NULL, "896K", &dr_set_size },
{ UNIT_DR, 1048576+1, NULL, "1024K", &dr_set_size }, { UNIT_SZ, (SZ_1024K << UNIT_V_SZ), NULL, "1024K", &dr_set_size },
{ UNIT_DR, 1572864+1, NULL, "1536K", &dr_set_size }, { UNIT_SZ, (SZ_1536K << UNIT_V_SZ), NULL, "1536K", &dr_set_size },
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &drd_dev }, &hp_setdev, &hp_showdev, &drd_dev },
{ 0 } }; { 0 } };
@ -198,7 +219,7 @@ DEVICE drc_dev = {
"DRC", &drc_unit, drc_reg, drc_mod, "DRC", &drc_unit, drc_reg, drc_mod,
1, 8, 21, 1, 8, 16, 1, 8, 21, 1, 8, 16,
NULL, NULL, &drc_reset, NULL, NULL, &drc_reset,
&drc_boot, NULL, NULL, &drc_boot, &drc_attach, NULL,
&drc_dib, DEV_DISABLE }; &drc_dib, DEV_DISABLE };
/* IOT routines */ /* IOT routines */
@ -336,14 +357,26 @@ sim_cancel (&drc_unit);
return SCPE_OK; 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 */ /* Set size routine */
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) 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 (uptr->flags & UNIT_ATT) return SCPE_ALATT;
if (val & 1) uptr->flags = uptr->flags | UNIT_DR; uptr->capac = sz;
else uptr->flags = uptr->flags & ~UNIT_DR;
uptr->capac = val & ~1;
return SCPE_OK; return SCPE_OK;
} }

View file

@ -1,6 +1,6 @@
/* hp2100_fp.c: HP 2100 floating point instructions /* 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), 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 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. 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 21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms
The HP2100 uses a unique binary floating point format: The HP2100 uses a unique binary floating point format:
@ -153,7 +154,7 @@ UnpackFP (&fop1, FPAB); /* unpack A-B */
UnpackFP (&fop2, opnd); /* get op */ UnpackFP (&fop2, opnd); /* get op */
if (sub) { /* subtract? */ if (sub) { /* subtract? */
fop2.fr = FR_NEG (fop2.fr); /* negate frac */ 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.fr = fop2.fr >> 1; /* special case */
fop2.exp = fop2.exp + 1; } } fop2.exp = fop2.exp + 1; } }
if (fop1.fr == 0) fop1 = fop2; /* op1 = 0? res = op2 */ 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 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. 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 16-Mar-03 RMS Fixed mnemonic, instruction lengths, and reverse
scan length check bug for MCS scan length check bug for MCS
Fixed MCE bug, BS off by 1 if zero suppress Fixed MCE bug, BS off by 1 if zero suppress
@ -114,6 +117,7 @@
*/ */
#include "i1401_defs.h" #include "i1401_defs.h"
#include "i1401_dat.h"
#define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_MASK (PCQ_SIZE - 1)
@ -268,7 +272,7 @@ const int32 op_table[64] = {
L1, /* punch feed */ L1, /* punch feed */
0, /* illegal */ 0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ | MA, /* modify address */ 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 */ 0, /* illegal */
0, /* illegal */ 0, /* illegal */
@ -284,7 +288,7 @@ const int32 op_table[64] = {
L1 | L4 | L7 | AREQ | BREQ, /* move supress zero */ L1 | L4 | L7 | AREQ | BREQ, /* move supress zero */
0, /* illegal */ 0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ | NOWM, /* set word mark */ 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 */ 0, /* illegal */
0, /* illegal */ 0, /* illegal */
@ -293,7 +297,7 @@ const int32 op_table[64] = {
L2 | L5, /* select stacker */ L2 | L5, /* select stacker */
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* load */ L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* load */
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* move */ L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* move */
HNOP | L1 | L4 | L7, /* nop */ HNOP | L1 | L2 | L4 | L5 | L7 | L8, /* nop */
0, /* illegal */ 0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ | MR, /* move to record */ L1 | L4 | L7 | AREQ | BREQ | MR, /* move to record */
L1 | L4 | AREQ | MLS, /* 50: store A addr */ 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 */ L1 | L4 | L7 | AREQ | MLS, /* 70: store B addr */
0, /* illegal */ 0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ, /* zero and add */ 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 */ L1 | L4 | L7 | AREQ | BREQ, /* clear word mark */
0, /* illegal */ 0, /* illegal */
0, /* illegal */ 0, /* illegal */
@ -362,38 +366,6 @@ const int32 bin_to_bcd[16] = {
const int32 bcd_to_bin[16] = { const int32 bcd_to_bin[16] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7 }; 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 */ /* Indicator resets - a 1 marks an indicator that resets when tested */
static const int32 ind_table[64] = { 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; 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 */ reason = STOP_NOWM; /* no, error */
break; } break; }
op = M[IS] & CHAR; /* get opcode */ 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 */ if (op == OP_SAR) BS = AS; /* SAR? save ASTAR */
PP (IS); 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, % */ D = ioind = t; /* could be D char, % */
AS = hun_table[t]; /* could be A addr */ AS = hun_table[t]; /* could be A addr */
PP (IS); /* if %xy, BA is set */ 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 */ AS = AS | BA; /* ASTAR bad */
if (!(flags & MLS)) BS = AS; if (!(flags & MLS)) BS = AS;
goto CHECK_LENGTH; } goto CHECK_LENGTH; }
D = dev = t; /* could be D char, dev */
AS = AS + ten_table[t]; /* build A addr */ AS = AS + ten_table[t]; /* build A addr */
dev = t; /* save char as dev */
PP (IS); 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 */ AS = AS | BA; /* ASTAR bad */
if (!(flags & MLS)) BS = AS; if (!(flags & MLS)) BS = AS;
goto CHECK_LENGTH; } 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 */ 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 */ xa = (AS >> V_INDEX) & M_INDEX; /* get index reg */
if (xa && (ioind != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */ if (xa && (ioind != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */
AS = AS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] + 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 */ if (!(flags & MLS)) BS = AS; /* not MLS? B = A */
PP (IS); 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? */ if ((op == OP_B) && (t == BCD_BLANK)) goto CHECK_LENGTH; /* BR + space? */
D = t; /* could be D char */ D = t; /* could be D char */
BS = hun_table[t]; /* could be B addr */ BS = hun_table[t]; /* could be B addr */
PP (IS); 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 */ BS = BS | BA; /* BSTAR bad */
goto CHECK_LENGTH; } goto CHECK_LENGTH; }
D = t; /* could be D char */
BS = BS + ten_table[t]; /* build B addr */ BS = BS + ten_table[t]; /* build B addr */
PP (IS); 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 */ BS = BS | BA; /* BSTAR bad */
goto CHECK_LENGTH; } goto CHECK_LENGTH; }
D = t; /* could be D char */
BS = BS + one_table[t]; /* finish B addr */ BS = BS + one_table[t]; /* finish B addr */
xa = (BS >> V_INDEX) & M_INDEX; /* get index reg */ xa = (BS >> V_INDEX) & M_INDEX; /* get index reg */
if (xa && (cpu_unit.flags & XSA)) { /* indexed? */ if (xa && (cpu_unit.flags & XSA)) { /* indexed? */
@ -564,39 +560,43 @@ if (xa && (cpu_unit.flags & XSA)) { /* indexed? */
BS = (BS & INDEXMASK) % MAXMEMSIZE; } BS = (BS & INDEXMASK) % MAXMEMSIZE; }
PP (IS); PP (IS);
if ((M[IS] & WM) || (flags & NOWM)) goto CHECK_LENGTH; /* WM? 7 chr */ if (flags & NOWM) goto CHECK_LENGTH; /* I-7: SWM? done */
D = M[IS]; /* last char is D */ if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* WM? 7 char inst */
do { PP (IS); } while ((M[IS] & WM) == 0); /* find word mark */ 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: CHECK_LENGTH:
ilnt = IS - saved_IS; /* get lnt */ ilnt = IS - saved_IS; /* get lnt */
if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) && /* valid lnt? */ //if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) && /* valid lnt? */
((flags & HNOP) == 0)) reason = STOP_INVL; // ((flags & HNOP) == 0)) reason = STOP_INVL;
if ((flags & BREQ) && ADDR_ERR (BS)) reason = STOP_INVB; /* valid A? */ if ((flags & BREQ) && ADDR_ERR (BS)) reason = STOP_INVB; /* valid A? */
if ((flags & AREQ) && ADDR_ERR (AS)) reason = STOP_INVA; /* valid B? */ if ((flags & AREQ) && ADDR_ERR (AS)) reason = STOP_INVA; /* valid B? */
if (reason) break; /* error in fetch? */ if (reason) break; /* error in fetch? */
switch (op) { /* case on opcode */ 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 MCW copy A to B, preserving B WM, here fetch
until either A or B WM until either A or B WM
LCA: copy A to B, overwriting B WM, here fetch LCA copy A to B, overwriting B WM, here fetch
until A WM until A WM
MCM: copy A to B, preserving B WM, fetch fetch
until record or group mark Instruction lengths:
MCS: copy A to B, clearing B WM, until A WM; fetch fetch
reverse scan and suppress leading zeroes 1 chained A and B
MN: copy A char digit to B char digit, fetch fetch 2,3 invalid A-address
preserving B zone and WM 4 chained B address
MZ: copy A char zone to B char zone, fetch fetch 5,6 invalid B-address
preserving B digit and WM 7 normal
8+ normal + modifier
*/ */
case OP_MCW: /* move char */ case OP_MCW: /* move char */
if (ilnt >= 8) { /* I/O form? */ if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */
if (ioind != BCD_PERCNT) reason = STOP_INVL; reason = iodisp (dev, unit, MD_NORM, D); /* dispatch I/O */
else reason = iodisp (dev, unit, MD_NORM, D);
break; } break; }
if (ADDR_ERR (AS)) { /* check A addr */ if (ADDR_ERR (AS)) { /* check A addr */
reason = STOP_INVA; reason = STOP_INVA;
@ -609,9 +609,8 @@ case OP_MCW: /* move char */
break; break;
case OP_LCA: /* load char */ case OP_LCA: /* load char */
if (ilnt >= 8) { /* I/O form? */ if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */
if (ioind != BCD_PERCNT) reason = STOP_INVL; reason = iodisp (dev, unit, MD_WM, D);
else reason = iodisp (dev, unit, MD_WM, D);
break; } break; }
if (ADDR_ERR (AS)) { /* check A addr */ if (ADDR_ERR (AS)) { /* check A addr */
reason = STOP_INVA; reason = STOP_INVA;
@ -621,6 +620,27 @@ case OP_LCA: /* load char */
MM (AS); MM (BS); } /* decr pointers */ MM (AS); MM (BS); } /* decr pointers */
while ((wm & WM) == 0); /* stop on A WM */ while ((wm & WM) == 0); /* stop on A WM */
break; 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 */ case OP_MCM: /* move to rec/group */
do { do {
@ -662,38 +682,18 @@ case OP_MZ: /* move zone */
MM (AS); MM (BS); /* decr pointers */ MM (AS); MM (BS); /* decr pointers */
break; break;
/* Compare - A and B are checked in fetch */ /* Branch instruction A check B check
case OP_C: /* compare */ Instruction lengths:
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
B 1/8 char: branch if B char equals d if branch here 1 branch if B char equals d, chained if branch here
B 4 char: unconditional branch if branch 2,3 invalid B-address if branch here
B 5 char: branch if indicator[d] is set if branch 4 unconditional branch if branch
BWZ: branch if (d<0>: B char WM) if branch here 5 branch if indicator[d] is set if branch
(d<1>: B char zone = d zone) 6 invalid B-address if branch here
BBE: branch if B char & d non-zero 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 */ case OP_B: /* branch */
@ -701,14 +701,29 @@ case OP_B: /* branch */
else if (ilnt == 5) { /* branch on ind? */ else if (ilnt == 5) { /* branch on ind? */
if (ind[D]) { BRANCH; } /* test indicator */ if (ind[D]) { BRANCH; } /* test indicator */
if (ind_table[D]) ind[D] = 0; } /* reset if needed */ if (ind_table[D]) ind[D] = 0; } /* reset if needed */
else { else { /* branch char eq */
if (ADDR_ERR (BS)) { /* branch char eq */ if (ADDR_ERR (BS)) { /* validate B addr */
reason = STOP_INVB; /* validate B addr */ reason = STOP_INVB;
break; } break; }
if ((M[BS] & CHAR) == D) { BRANCH; } /* char equal? */ if ((M[BS] & CHAR) == D) { BRANCH; } /* char equal? */
else { MM (BS); } } else { MM (BS); } }
break; 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 */ case OP_BWZ: /* branch wm or zone */
if (((D & 1) && (M[BS] & WM)) || /* d1? test wm */ if (((D & 1) && (M[BS] & WM)) || /* d1? test wm */
((D & 2) && ((M[BS] & ZONE) == (D & ZONE)))) /* d2? test zone */ ((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 */ else { MM (BS); } /* decr pointer */
break; break;
/* Arithmetic instructions A check B check /* Arithmetic instructions A check B check
ZA: move A to B, normalizing A sign, fetch fetch ZA move A to B, normalizing A sign, fetch fetch
preserving B WM, until B WM preserving B WM, until B WM
ZS: move A to B, complementing A sign, fetch fetch ZS move A to B, complementing A sign, fetch fetch
preserving B WM, until B WM preserving B WM, until B WM
A: add A to B fetch fetch A add A to B fetch fetch
S: subtract A from 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 */ 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); carry = (t >= 10);
M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t]; } } M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t]; } }
break; break;
/* I/O instructions A check B check
R: read a card if branch case OP_C: /* compare */
W: write to line printer if branch if (ilnt != 1) { /* if not chained */
WR: write and read if branch ind[IN_EQU] = 1; /* clear indicators */
P: punch a card if branch ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0; }
RP: read and punch if branch do {
WP: write and punch if branch a = M[AS]; /* get characters */
WRP: write read and punch if branch b = M[BS];
RF: read feed (nop) wm = a | b; /* get word marks */
PF: punch feed (nop) if ((a & CHAR) != (b & CHAR)) { /* unequal? */
SS: select stacker if branch ind[IN_EQU] = 0; /* set indicators */
CC: carriage control if branch ind[IN_UNQ] = 1;
MTF: magtape functions 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 */ case OP_R: /* read */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */ if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
reason = read_card (ilnt, D); /* read card */ reason = read_card (ilnt, D); /* read card */
BS = CDR_BUF + CDR_WIDTH; BS = CDR_BUF + CDR_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */ if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break; break;
case OP_W: /* write */ case OP_W: /* write */
if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */ if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */
reason = write_line (ilnt, D); /* print line */ reason = write_line (ilnt, D); /* print line */
BS = LPT_BUF + LPT_WIDTH; BS = LPT_BUF + LPT_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */ if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break; break;
case OP_P: /* punch */ case OP_P: /* punch */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */ if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
reason = punch_card (ilnt, D); /* punch card */ reason = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH; BS = CDP_BUF + CDP_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */ if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
break; break;
case OP_WR: /* write and read */ case OP_WR: /* write and read */
@ -830,7 +884,7 @@ case OP_WR: /* write and read */
reason = write_line (ilnt, D); /* print line */ reason = write_line (ilnt, D); /* print line */
r1 = read_card (ilnt, D); /* read card */ r1 = read_card (ilnt, D); /* read card */
BS = CDR_BUF + CDR_WIDTH; 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 */ if (reason == SCPE_OK) reason = r1; /* merge errors */
break; break;
@ -839,7 +893,7 @@ case OP_WP: /* write and punch */
reason = write_line (ilnt, D); /* print line */ reason = write_line (ilnt, D); /* print line */
r1 = punch_card (ilnt, D); /* punch card */ r1 = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH; 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 */ if (reason == SCPE_OK) reason = r1; /* merge errors */
break; break;
@ -848,7 +902,7 @@ case OP_RP: /* read and punch */
reason = read_card (ilnt, D); /* read card */ reason = read_card (ilnt, D); /* read card */
r1 = punch_card (ilnt, D); /* punch card */ r1 = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH; 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 */ if (reason == SCPE_OK) reason = r1; /* merge errors */
break; break;
@ -858,24 +912,36 @@ case OP_WRP: /* write, read, punch */
r1 = read_card (ilnt, D); /* read card */ r1 = read_card (ilnt, D); /* read card */
r2 = punch_card (ilnt, D); /* punch card */ r2 = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH; 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; if (reason == SCPE_OK) reason = (r1 == SCPE_OK)? r2: r1;
break; break;
case OP_SS: /* select stacker */ case OP_SS: /* select stacker */
if (reason = iomod (ilnt, D, ss_mod)) break; /* valid modifier? */ if (reason = iomod (ilnt, D, ss_mod)) break; /* valid modifier? */
if (reason = select_stack (D)) break; /* sel stack, error? */ 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; break;
case OP_CC: /* carriage control */ case OP_CC: /* carriage control */
if (reason = carriage_control (D)) break; /* car ctrl, error? */ 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; 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 */ case OP_MTF: /* magtape function */
if (reason = iomod (ilnt, D, mtf_mod)) break; /* valid modifier? */ if (ilnt < 4) reason = STOP_INVL; /* too short? */
if (reason = mt_func (unit, D)) break; /* mt func, error? */ 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 */ break; /* can't branch */
case OP_RF: case OP_PF: /* read, punch feed */ 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 The first A field character is masked to its digit part, all others
are copied intact 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 */ case OP_MCE: /* edit */
@ -1040,6 +1115,15 @@ case OP_MCE: /* edit */
LD + 1 + length of multiplier. Locate the low order multiplier digit, 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 and at the same time zero out the product field. Then compute the sign
of the result. 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: case OP_MUL:
@ -1085,7 +1169,7 @@ case OP_MUL:
/* Divide. Comments from the PDP-10 based simulator by Len Fehskens. /* 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 pencil and paper; successive subtraction of the divisor from a substring
of the dividend while counting up the corresponding quotient digit. 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 Start by locating the high order non-zero digit of the divisor. This
also tests for a divide by zero. 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: case OP_DIV:
@ -1170,16 +1263,19 @@ case OP_DIV:
BS = qs - 2; /* BS = quo 10's pos */ BS = qs - 2; /* BS = quo 10's pos */
break; 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 SWM set WM on A char and B char fetch fetch
CWM: clear 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 Instruction lengths:
SAR: store A* at A addr fetch
SBR: store B* at A addr fetch 1 chained
NOP: no operation 2,3 invalid A-address
H: halt 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 */ case OP_SWM: /* set word mark */
@ -1194,13 +1290,41 @@ case OP_CWM: /* clear word mark */
MM (AS); MM (BS); /* decr pointers */ MM (AS); MM (BS); /* decr pointers */
break; 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 */ case OP_CS: /* clear storage */
t = (BS / 100) * 100; /* lower bound */ t = (BS / 100) * 100; /* lower bound */
while (BS >= t) M[BS--] = 0; /* clear region */ while (BS >= t) M[BS--] = 0; /* clear region */
if (BS < 0) BS = BS + MEMSIZE; /* wrap if needed */ if (BS < 0) BS = BS + MEMSIZE; /* wrap if needed */
if (ilnt >= 7) { BRANCH; } /* branch variant? */ if (ilnt == 7) { BRANCH; } /* branch variant? */
break; 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 */ case OP_MA: /* modify address */
a = one_table[M[AS] & CHAR]; MM (AS); /* get A address */ a = one_table[M[AS] & CHAR]; MM (AS); /* get A address */
a = a + ten_table[M[AS] & CHAR]; MM (AS); 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? */ if (((a % 4000) + (b % 4000)) >= 4000) BS = BS + 2; /* carry? */
break; 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 */ 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_u (BS); MM (AS);
M[AS] = (M[AS] & WM) | store_addr_t (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); M[AS] = (M[AS] & WM) | store_addr_h (BS); MM (AS);
break; break;
/* NOP - no validity checking, all instructions length ok */
case OP_NOP: /* nop */ case OP_NOP: /* nop */
break; break;
/* HALT - unless length = 4 (branch), no validity checking; all lengths ok */
case OP_H: /* halt */ case OP_H: /* halt */
if (ilnt == 4) hb_pend = 1; /* set pending branch */ if (ilnt == 4) hb_pend = 1; /* set pending branch */
reason = STOP_HALT; /* stop simulator */ reason = STOP_HALT; /* stop simulator */

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: IBM 1401 Simulator Usage Subj: IBM 1401 Simulator Usage
Date: 20-Apr-2003 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -39,13 +39,16 @@ This memorandum documents the IBM 1401 simulator.
sim/ sim_defs.h sim/ sim_defs.h
sim_rev.h sim_rev.h
sim_sock.h sim_sock.h
sim_tape.h
sim_tmxr.h sim_tmxr.h
scp.c scp.c
scp_tty.c scp_tty.c
sim_sock.c sim_sock.c
sim_tape.c
sim_tmxr.c sim_tmxr.c
sim/i1401/ i1401_defs.h sim/i1401/ i1401_defs.h
i1401_dat.h
i1401_cpu.c i1401_cpu.c
i1401_cd.c i1401_cd.c
i1401_iq.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 If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated 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. 20K, and indirect addressing, editing instructions, and divide are enabled.
Memory is implemented as 5 bit BCD digits, as follows: 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 -s display as flag terminated numeric string
(CPU and DP only) (CPU and DP only)
-m display instruction mnemonics -m display instruction mnemonics
(CPU and only) (CPU and DP only)
-d display 50 characters per line, with word -d display 50 characters per line, with word
marks denoted by "_" on the line above marks denoted by "_" on the line above

View file

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

View file

@ -9,26 +9,27 @@
* Mail to sim@ibm1130.org * Mail to sim@ibm1130.org
*/ */
// ctrl-M (Enter) => EOF // 03 ctrl-C => Program stop (not handled here)
// ctrl-U => Erase field // 05 ctrl-E => Simulator stop (not handled here)
// ctrl-Q => Interrupt request (not here) // 08 ctrl-H => Backspace
// ctrl-C => Program stop (not here) // 0D ctrl-M (Enter) => EOF
// \ => "not" // 11 ctrl-Q => Interrupt request (not handled here)
// Del => backspace // 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard)
// Ctrl-H => backspace // 15 ctrl-U => Erase Field
// 7E ~ => "not"
// FF Del => Backspace again
static uint16 ascii_to_conin[] = /* ASCII to ((hollerith << 4) | special key flags) */ 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 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, /* 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, /* 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, /* 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, /* 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, /* 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, /* 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, /* 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, /* 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, /* 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, /* 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 _0_ '\0'
#define CENT '\xA2' #define CENT_ '\xA2' /* cent and not: standard DOS mapping */
#define REST IGNR #define NOT_ '\xAC'
#define RDRSTP '?' #define IGNR_ '\xFF'
#define NOT '\xAC' #define CRLF_ '\r'
#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 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_, /* 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_, /* 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_, /* 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_, /* 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_, /* 40 */ '$', '\t', '!', _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_, /* 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_, /* 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_, /* 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_, /* 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_, /* 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_, /* 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_, /* 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_, /* 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_, /* 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_, /* 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. * or modifications.
* *
* This is not a supported product, but I welcome bug reports and fixes. * 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 25-Jun-01 BLK Written
10-May-02 BLK Fixed bug in MDX instruction 10-May-02 BLK Fixed bug in MDX instruction
27-Mar-02 BLK Made BOSC work even in short form 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 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 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: The register state for the IBM 1130 CPU is:
@ -470,23 +471,17 @@ t_stat sim_instr (void)
if (wait_state) { /* waiting? */ if (wait_state) { /* waiting? */
sim_interval = 0; /* run the clock out */ sim_interval = 0; /* run the clock out */
if (sim_qcount() <= 1) { /* waiting for keyboard only */ if (sim_qcount() <= (cgi ? 0 : 1)) { /* one routine queued? we're waiting for keyboard only */
if (keyboard_is_locked()) { /* CPU is not expecting a keystroke */ 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) if (wait_state == WAIT_OP)
reason = STOP_WAIT; /* end the simulation */ reason = STOP_WAIT; /* end the simulation */
else else
reason = STOP_INVALID_INSTR; 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 */ 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 * 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; 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 xio_error (char *msg);
void bail (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); t_stat cr_boot (int unitno, DEVICE *dptr);
void calc_ints (void); /* recalculate interrupt bitmask */ void calc_ints (void); /* recalculate interrupt bitmask */
void trace_io (char *fmt, ...); /* debugging printout */ void trace_io (char *fmt, ...); /* debugging printout */
void scp_panic (char *msg); /* bail out of simulator */ void scp_panic (char *msg); /* bail out of simulator */
char *upcase(char *str); char *upcase(char *str);
void break_simulation (t_stat reason); /* let a device halt the simulation */ 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); t_bool gdu_active (void);
void remark_cmd (char *remark); void remark_cmd (char *remark);
void stuff_cmd (char *cmd); void stuff_cmd (char *cmd);
void update_gui (t_bool force); void update_gui (t_bool force);
void sim_init (void); 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 */ /* 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 forms_check (int set); /* device notification to console lamp display */
void print_check (int set); void print_check (int set);
void keyboard_selected (int select); 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 * usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications. * or modifications.
* *
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
*
* Revision History * 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 * 01-sep-02 corrected treatment of -m and -r flags in dsk_attach
* in cgi mode, so that file is opened readonly but emulated * in cgi mode, so that file is opened readonly but emulated
* disk is writable. * 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" #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 */ 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_swait = 50; /* seek time -- see how short a delay we can get away with */
int32 dsk_rwait = 50; /* rotate time */ int32 dsk_rwait = 50; /* rotate time */
static t_bool raw_disk_debug = FALSE;
static t_stat dsk_svc (UNIT *uptr); static t_stat dsk_svc (UNIT *uptr);
static t_stat dsk_reset (DEVICE *dptr); static t_stat dsk_reset (DEVICE *dptr);
@ -141,6 +145,15 @@ static int32 dsk_ilswlevel[DSK_NUMDR] =
2, 2, 2, 2 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 */ /* xio_disk - XIO command interpreter for the disk drives */
/* /*
* device status word: * 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) void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
{ {
int i, rev, nsteps, newcyl, sec, nwords; 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]; char msg[80];
UNIT *uptr = dsk_unit+drv; UNIT *uptr = dsk_unit+drv;
int16 buf[DSK_NUMWD]; 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 */ 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; break;
if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */ 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 */ 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; newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD;
if (MEM_MAPPED(uptr)) { dsk_action[drv].io_address = iocc_addr;
memcpy(buf, (char *) uptr->filebuf + newpos, 2*DSK_NUMWD); dsk_action[drv].io_nwords = nwords;
} dsk_action[drv].io_sector = sec;
else { dsk_action[drv].io_filepos = newpos;
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;
}
void_backtrace(iocc_addr, iocc_addr + nwords - 1); // mark prev instruction as altered uptr->FUNC = DSK_FUNC_READ;
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
} }
else else {
trace_io("* DSK%d verify %d.%d (%x)", drv, uptr->CYL, sec, uptr->CYL*8 + sec); trace_io("* DSK%d verify %d.%d (%x)", drv, uptr->CYL, sec, uptr->CYL*8 + sec);
uptr->FUNC = func; if (raw_disk_debug)
sim_activate(uptr, dsk_rwait); 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; break;
case XIO_INITW: 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); 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 #ifdef TRACE_DMS_IO
if (trace_dms) 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->pos = newpos + 2*DSK_NUMWD;
} }
uptr->FUNC = func; uptr->FUNC = DSK_FUNC_WRITE;
sim_activate(uptr, dsk_rwait); sim_activate(uptr, dsk_rwait);
break; break;
@ -332,7 +329,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
else if (newcyl >= DSK_NUMCY) else if (newcyl >= DSK_NUMCY)
newcyl = DSK_NUMCY-1; newcyl = DSK_NUMCY-1;
uptr->FUNC = func; uptr->FUNC = DSK_FUNC_SEEK;
uptr->CYL = newcyl; uptr->CYL = newcyl;
sim_activate(uptr, dsk_swait); /* schedule interrupt */ 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 */ sim_cancel(uptr); /* cancel any pending ops */
SETBIT(uptr->flags, errflag); /* set the error flag */ 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 */ sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */
} }
t_stat dsk_svc (UNIT *uptr) 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); SETBIT(dsk_dsw[drv], DSK_DSW_OP_COMPLETE);
if (uptr->flags & (UNIT_OPERR|UNIT_HARDERR)) { /* word count error or data error */ if (uptr->flags & (UNIT_OPERR|UNIT_HARDERR)) { /* word count error or data error */
SETBIT(dsk_dsw[drv], DSK_DSW_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]); SETBIT(ILSW[dsk_ilswlevel[drv]], dsk_ilswbit[drv]);
#ifdef XXXX switch (uptr->FUNC) { /* take care of business */
switch (uptr->FUNC) { case DSK_FUNC_IDLE:
case XIO_CONTROL: case DSK_FUNC_VERIFY:
case XIO_INITR: case DSK_FUNC_WRITE:
case XIO_INITW: case DSK_FUNC_SEEK:
case XIO_FAILED: 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; break;
default: default:
@ -402,8 +447,8 @@ t_stat dsk_svc (UNIT *uptr)
break; 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; return SCPE_OK;
} }
@ -428,7 +473,7 @@ t_stat dsk_reset (DEVICE *dptr)
CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR); CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR);
uptr->CYL = 0; uptr->CYL = 0;
uptr->FUNC = -1; uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = (uptr->flags & UNIT_ATT) ? DSK_DSW_CARRIAGE_HOME : 0; 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; return rval;
uptr->CYL = 0; // reset the device uptr->CYL = 0; // reset the device
uptr->FUNC = -1; uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME; dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME;
CLRBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_BUFABLE|UNIT_BUF|UNIT_RONLY|UNIT_OPERR|UNIT_HARDERR); 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')); enable_dms_tracing(sim_switches & SWMASK('D'));
raw_disk_debug = sim_switches & SWMASK('G');
return SCPE_OK; return SCPE_OK;
} }
@ -498,7 +544,7 @@ static t_stat dsk_detach (UNIT *uptr)
calc_ints(); calc_ints();
uptr->CYL = 0; uptr->CYL = 0;
uptr->FUNC = -1; uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = DSK_DSW_NOT_READY; dsk_dsw[drv] = DSK_DSW_NOT_READY;
if (drv == 0) { if (drv == 0) {
@ -518,7 +564,7 @@ static t_stat dsk_boot (int unitno, DEVICE *dptr)
if ((rval = reset_all(0)) != SCPE_OK) if ((rval = reset_all(0)) != SCPE_OK)
return rval; return rval;
return load_cr_boot(unitno); return load_cr_boot(unitno, sim_switches);
} }
#ifdef TRACE_DMS_IO #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. * or modifications.
* *
* This is not a supported product, but I welcome bug reports and fixes. * 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() #define BLIT_MODE // normally defined, undefine when debugging generate_image()

View file

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

View file

@ -23,7 +23,7 @@
* or modifications. * or modifications.
* *
* This is not a supported product, but I welcome bug reports and fixes. * 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" #include "ibm1130_defs.h"

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,7 @@
* or modifications. * or modifications.
* *
* This is not a supported product, but I welcome bug reports and fixes. * 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" #include "ibm1130_defs.h"

View file

@ -58,9 +58,11 @@ ibm1130D = ./
ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \ ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \
${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \ ${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \
${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.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_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 dmsr2v12phases.h dmsr2v12slet.h
# #

View file

@ -1,5 +1,10 @@
Here's the 1130 simulator as it stands now. 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 Status: 13Sep2002
* Added support for 1403 printer. It's MUCH faster * 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): 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 2003-03-18 Fixed bug in asm1130 that produced an error message
with a (legal) offset of +127 in MDX instructions. with a (legal) offset of +127 in MDX instructions.

View file

@ -13,6 +13,7 @@
// ASM1130 - IBM 1130 Cross Assembler // ASM1130 - IBM 1130 Cross Assembler
// //
// Version // 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.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) // 1.06 - 2002May02 - Fixed bug in ebdic constants (data goes into low byte)
// First stab at adding ISS level # info, this is iffy // First stab at adding ISS level # info, this is iffy
@ -156,7 +157,7 @@
#define TRUE 1 #define TRUE 1
#define FALSE 0 #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 #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 else
getexpr(tok, FALSE, &incr); 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)"); asm_error("Invalid increment value (8 bits signed)");
opcode |= (incr.value & 0xFF); opcode |= (incr.value & 0xFF);

View file

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

View file

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

View file

@ -15,25 +15,61 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef int BOOL;
int hollerith_to_ascii (unsigned short h); int hollerith_to_ascii (unsigned short h);
void bail (char *msg); void bail (char *msg);
void format_coldstart (unsigned short *buf);
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
FILE *fd; FILE *fd;
char line[82]; char *fname = NULL, line[82], *arg;
BOOL coldstart = FALSE;
unsigned short buf[80]; unsigned short buf[80];
int i, lastnb; 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) for (i = 1; i < argc; i++) { // process command line arguments
bail("Usage: viewdeck deckfile"); arg = argv[i];
if ((fd = fopen(argv[1], "rb")) == NULL) { if (*arg == '-') {
perror(argv[1]); 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; return 1;
} }
while (fread(buf, sizeof(short), 80, fd) == 80) { while (fread(buf, sizeof(short), 80, fd) == 80) {
if (coldstart) {
format_coldstart(buf);
break;
}
lastnb = -1; lastnb = -1;
for (i = 0; i < 80; i++) { for (i = 0; i < 80; i++) {
line[i] = hollerith_to_ascii(buf[i]); line[i] = hollerith_to_ascii(buf[i]);
@ -45,11 +81,39 @@ int main (int argc, char **argv)
fputs(line, stdout); fputs(line, stdout);
} }
if (coldstart) {
if (fread(buf, sizeof(short), 1, fd) == 1)
bail("Coldstart deck has more than one card");
}
fclose(fd); fclose(fd);
return 0; 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 { typedef struct {
unsigned short hollerith; unsigned short hollerith;
char ascii; char ascii;
@ -103,7 +167,7 @@ static CPCODE cardcode_029[] =
0x0120, '\'', 0x0120, '\'',
0x00A0, '=', 0x00A0, '=',
0x0060, '"', 0x0060, '"',
0x8820, 'c', // cent 0x8820, '\xA2', // cent, in MS-DOS encoding
0x8420, '.', 0x8420, '.',
0x8220, '<', // ) in 026 Fortran 0x8220, '<', // ) in 026 Fortran
0x8120, '(', 0x8120, '(',
@ -114,13 +178,47 @@ static CPCODE cardcode_029[] =
0x4220, '*', 0x4220, '*',
0x4120, ')', 0x4120, ')',
0x40A0, ';', 0x40A0, ';',
0x4060, 'n', // not 0x4060, '\xAC', // not, in MS-DOS encoding
0x2820, 'x', // what?
0x2420, ',', 0x2420, ',',
0x2220, '%', // ( in 026 Fortran 0x2220, '%', // ( in 026 Fortran
0x2120, '_', 0x2120, '_',
0x20A0, '>', 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) 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 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. 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 27-Feb-03 RMS Added relative addressing support
23-Dec-01 RMS Cloned from ID4 sources 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) t_stat get_imm (char *cptr, uint32 *imm, uint32 *inst, uint32 max)
{ {
char *tptr; char *tptr;
uint32 idx; int32 idx;
errno = 0; errno = 0;
*imm = strtoul (cptr, &tptr, 16); /* get immed */ *imm = strtoul (cptr, &tptr, 16); /* get immed */

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: Interdata 16b/32b Simulator Usage Subj: Interdata 16b/32b Simulator Usage
Date: 15-Mar-2003 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -39,10 +39,12 @@ This memorandum documents the Interdata 16b and 32b simulators.
sim/ sim_defs.h sim/ sim_defs.h
sim_rev.h sim_rev.h
sim_sock.h sim_sock.h
sim_tape.h
sim_tmxr.h sim_tmxr.h
scp.c scp.c
scp_tty.c scp_tty.c
sim_sock.c sim_sock.c
sim_tape.c
sim_tmxr.c sim_tmxr.c
sim/interdata/ id_defs.h sim/interdata/ id_defs.h
@ -519,8 +521,7 @@ The programmable interval clock (PIC) implements these registers:
IARM 1 clock interrupt armed IARM 1 clock interrupt armed
If the interval requested is an exact multiple of 1 msec, the If the interval requested is an exact multiple of 1 msec, the
programmable clock auto-calibrates; if not, it simply counts programmable clock auto-calibrates; if not, it counts instructions.
counts instructions.
2.4.7 Floppy Disk Controller (FD) 2.4.7 Floppy Disk Controller (FD)
@ -822,7 +823,7 @@ line switches:
alphabetic instruction mnemonic alphabetic instruction mnemonic
numeric octal number numeric octal number
2.7.1 16b Instruction Input 2.8.1 16b Instruction Input
Instruction input uses standard Interdata assembler syntax. There are Instruction input uses standard Interdata assembler syntax. There are
seven instruction classes: short branch, extended short branch, short 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) between 0 and 0xFFFF, and the index register is a hex (decimal)
number, optionally preceded by R, between 1 and F (15). 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 Instruction input uses standard Interdata assembler syntax. There are
nine instruction classes: short branch, extended short branch, short 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 TIME2 24 clock frequency, select = 2
TIME3 24 clock frequency, select = 3 TIME3 24 clock frequency, select = 3
The real-time clock autocalibrates; the clock interval is adjusted up or The real-time clock autocalibrates; the clock interval is adjusted up
down so that the clock tracks actual elapsed time. or down so that the clock tracks actual elapsed time.
2.2.7 Plotter (PTP) 2.2.7 Plotter (PTP)

View file

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

View file

@ -25,6 +25,7 @@
cpu PDP-1 central processor cpu PDP-1 central processor
23-Jul-03 RMS Revised to detect I/O wait hang
05-Dec-02 RMS Added drum support 05-Dec-02 RMS Added drum support
06-Oct-02 RMS Revised for V2.10 06-Oct-02 RMS Revised for V2.10
20-Aug-02 RMS Added DECtape support 20-Aug-02 RMS Added DECtape support
@ -239,6 +240,7 @@ int32 sbs = 0; /* sequence break */
int32 sbs_init = 0; /* seq break startup */ int32 sbs_init = 0; /* seq break startup */
int32 ioh = 0; /* I/O halt */ int32 ioh = 0; /* I/O halt */
int32 ioc = 0; /* I/O completion */ int32 ioc = 0; /* I/O completion */
int32 cpls = 0; /* pending completions */
int32 extm = 0; /* ext mem mode */ int32 extm = 0; /* ext mem mode */
int32 extm_init = 0; /* ext mem startup */ int32 extm_init = 0; /* ext mem startup */
int32 stop_inst = 0; /* stop on rsrv inst */ 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_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
extern int32 ptr (int32 inst, int32 dev, int32 IO); extern int32 ptr (int32 inst, int32 dev, int32 dat);
extern int32 ptp (int32 inst, int32 dev, int32 IO); extern int32 ptp (int32 inst, int32 dev, int32 dat);
extern int32 tti (int32 inst, int32 dev, int32 IO); extern int32 tti (int32 inst, int32 dev, int32 dat);
extern int32 tto (int32 inst, int32 dev, int32 IO); extern int32 tto (int32 inst, int32 dev, int32 dat);
extern int32 lpt (int32 inst, int32 dev, int32 IO); extern int32 lpt (int32 inst, int32 dev, int32 dat);
extern int32 dt (int32 inst, int32 dev, int32 IO); extern int32 dt (int32 inst, int32 dev, int32 dat);
extern int32 drm (int32 inst, int32 dev, int32 IO); extern int32 drm (int32 inst, int32 dev, int32 dat);
int32 sc_map[512] = { int32 sc_map[512] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */ 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; sim_interval = sim_interval - 1;
xct_instr: /* label for XCT */ 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 */ sbs = sbs & ~SB_IP; /* seq debreak */
PCQ_ENTRY; /* save old PC */ PCQ_ENTRY; /* save old PC */
OV = (M[1] >> 17) & 1; /* restore OV */ OV = (M[1] >> 17) & 1; /* restore OV */
@ -432,12 +434,15 @@ switch (op) { /* decode IR<0:4> */
case 001: /* AND */ case 001: /* AND */
AC = AC & M[MA]; AC = AC & M[MA];
break; break;
case 002: /* IOR */ case 002: /* IOR */
AC = AC | M[MA]; AC = AC | M[MA];
break; break;
case 003: /* XOR */ case 003: /* XOR */
AC = AC ^ M[MA]; AC = AC ^ M[MA];
break; break;
case 004: /* XCT */ case 004: /* XCT */
if (xct_count >= xct_max) { /* too many XCT's? */ if (xct_count >= xct_max) { /* too many XCT's? */
reason = STOP_XCT; reason = STOP_XCT;
@ -445,6 +450,7 @@ case 004: /* XCT */
xct_count = xct_count + 1; /* count XCT's */ xct_count = xct_count + 1; /* count XCT's */
IR = M[MA]; /* get instruction */ IR = M[MA]; /* get instruction */
goto xct_instr; /* go execute */ goto xct_instr; /* go execute */
case 007: /* CAL, JDA */ case 007: /* CAL, JDA */
MA = (PC & EPCMASK) | ((IR & IA)? (IR & DAMASK): 0100); MA = (PC & EPCMASK) | ((IR & IA)? (IR & DAMASK): 0100);
PCQ_ENTRY; PCQ_ENTRY;
@ -452,24 +458,31 @@ case 007: /* CAL, JDA */
AC = EPC_WORD; AC = EPC_WORD;
PC = INCR_ADDR (MA); PC = INCR_ADDR (MA);
break; break;
case 010: /* LAC */ case 010: /* LAC */
AC = M[MA]; AC = M[MA];
break; break;
case 011: /* LIO */ case 011: /* LIO */
IO = M[MA]; IO = M[MA];
break; break;
case 012: /* DAC */ case 012: /* DAC */
if (MEM_ADDR_OK (MA)) M[MA] = AC; if (MEM_ADDR_OK (MA)) M[MA] = AC;
break; break;
case 013: /* DAP */ case 013: /* DAP */
if (MEM_ADDR_OK (MA)) M[MA] = (AC & DAMASK) | (M[MA] & ~DAMASK); if (MEM_ADDR_OK (MA)) M[MA] = (AC & DAMASK) | (M[MA] & ~DAMASK);
break; break;
case 014: /* DIP */ case 014: /* DIP */
if (MEM_ADDR_OK (MA)) M[MA] = (AC & ~DAMASK) | (M[MA] & DAMASK); if (MEM_ADDR_OK (MA)) M[MA] = (AC & ~DAMASK) | (M[MA] & DAMASK);
break; break;
case 015: /* DIO */ case 015: /* DIO */
if (MEM_ADDR_OK (MA)) M[MA] = IO; if (MEM_ADDR_OK (MA)) M[MA] = IO;
break; break;
case 016: /* DZM */ case 016: /* DZM */
if (MEM_ADDR_OK (MA)) M[MA] = 0; if (MEM_ADDR_OK (MA)) M[MA] = 0;
break; break;
@ -498,6 +511,7 @@ case 020: /* ADD */
if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1; if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1;
if (AC == 0777777) AC = 0; /* minus 0 cleanup */ if (AC == 0777777) AC = 0; /* minus 0 cleanup */
break; break;
case 021: /* SUB */ case 021: /* SUB */
t = AC ^ 0777777; /* complement AC */ t = AC ^ 0777777; /* complement AC */
AC = t + M[MA]; /* -AC + MB */ AC = t + M[MA]; /* -AC + MB */
@ -505,32 +519,39 @@ case 021: /* SUB */
if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1; if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1;
AC = AC ^ 0777777; /* recomplement AC */ AC = AC ^ 0777777; /* recomplement AC */
break; break;
case 022: /* IDX */ case 022: /* IDX */
AC = M[MA] + 1; AC = M[MA] + 1;
if (AC >= 0777777) AC = (AC + 1) & 0777777; if (AC >= 0777777) AC = (AC + 1) & 0777777;
if (MEM_ADDR_OK (MA)) M[MA] = AC; if (MEM_ADDR_OK (MA)) M[MA] = AC;
break; break;
case 023: /* ISP */ case 023: /* ISP */
AC = M[MA] + 1; AC = M[MA] + 1;
if (AC >= 0777777) AC = (AC + 1) & 0777777; if (AC >= 0777777) AC = (AC + 1) & 0777777;
if (MEM_ADDR_OK (MA)) M[MA] = AC; if (MEM_ADDR_OK (MA)) M[MA] = AC;
if (AC < 0400000) PC = INCR_ADDR (PC); if (AC < 0400000) PC = INCR_ADDR (PC);
break; break;
case 024: /* SAD */ case 024: /* SAD */
if (AC != M[MA]) PC = INCR_ADDR (PC); if (AC != M[MA]) PC = INCR_ADDR (PC);
break; break;
case 025: /* SAS */ case 025: /* SAS */
if (AC == M[MA]) PC = INCR_ADDR (PC); if (AC == M[MA]) PC = INCR_ADDR (PC);
break; break;
case 030: /* JMP */ case 030: /* JMP */
PCQ_ENTRY; PCQ_ENTRY;
PC = MA; PC = MA;
break; break;
case 031: /* JSP */ case 031: /* JSP */
AC = EPC_WORD; AC = EPC_WORD;
PCQ_ENTRY; PCQ_ENTRY;
PC = MA; PC = MA;
break; break;
case 034: /* LAW */ case 034: /* LAW */
AC = (IR & 07777) ^ ((IR & IA)? 0777777: 0); AC = (IR & 07777) ^ ((IR & IA)? 0777777: 0);
break; break;
@ -691,8 +712,11 @@ case 035:
if (ioh) { /* I/O halt? */ if (ioh) { /* I/O halt? */
if (ioc) ioh = 0; /* comp pulse? done */ if (ioc) ioh = 0; /* comp pulse? done */
else { /* wait more */ 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 */ break; } /* skip iot */
ioh = 1; /* turn on halt */ ioh = 1; /* turn on halt */
PC = DECR_ADDR (PC); } /* re-execute */ 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_SKP) PC = INCR_ADDR (PC); /* skip? */
if (io_data >= IOT_REASON) reason = io_data >> IOT_V_REASON; if (io_data >= IOT_REASON) reason = io_data >> IOT_V_REASON;
break; break;
default: /* undefined */ default: /* undefined */
reason = STOP_RSRV; /* halt */ reason = STOP_RSRV; /* halt */
break; } /* end switch opcode */ break; } /* end switch opcode */
@ -759,7 +784,7 @@ t_stat cpu_reset (DEVICE *dptr)
{ {
sbs = sbs_init; sbs = sbs_init;
extm = extm_init; extm = extm_init;
ioh = ioc = 0; ioh = ioc = cpls = 0;
OV = 0; OV = 0;
PF = 0; PF = 0;
pcq_r = find_reg ("PCQ", NULL, dptr); 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 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. 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) 05-Dec-02 RMS Added IOT skip support (required by drum)
14-Apr-99 RMS Changed t_addr to unsigned 14-Apr-99 RMS Changed t_addr to unsigned
@ -34,7 +36,9 @@
Automatic multiply/divide Type 10 Automatic multiply/divide Type 10
Memory extension control Type 15 Memory extension control Type 15
Serial drum Type 24
Line printer control Type 62 Line printer control Type 62
Microtape (DECtape) control Type 550
*/ */
#include "sim_defs.h" #include "sim_defs.h"
@ -46,7 +50,7 @@
#define STOP_IBKPT 3 /* breakpoint */ #define STOP_IBKPT 3 /* breakpoint */
#define STOP_XCT 4 /* nested XCT's */ #define STOP_XCT 4 /* nested XCT's */
#define STOP_IND 5 /* nested indirects */ #define STOP_IND 5 /* nested indirects */
#define STOP_WAIT 6 /* wait state */ #define STOP_WAIT 6 /* IO wait hang */
/* Memory */ /* Memory */
@ -59,11 +63,14 @@
/* Architectural constants */ /* Architectural constants */
#define DMASK 0777777 /* data mask */ #define DMASK 0777777 /* data mask */
#define DAMASK 007777 /* direct addr */ #define DAMASK 0007777 /* direct addr */
#define EPCMASK (AMASK & ~DAMASK) /* extended addr */ #define EPCMASK (AMASK & ~DAMASK) /* extended addr */
#define IA 010000 /* indirect flag */ #define IA 0010000 /* indirect flag */
#define IO_WAIT 010000 /* I/O sync wait */ #define IO_WAIT 0010000 /* I/O sync wait */
#define IO_CPLS 004000 /* completion pulse */ #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? */ #define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */
/* IOT subroutine return codes */ /* IOT subroutine return codes */
@ -96,6 +103,17 @@
#define IOS_PNT (1 << IOS_V_PNT) #define IOS_PNT (1 << IOS_V_PNT)
#define IOS_SPC (1 << IOS_V_SPC) #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 */ /* Sequence break flags */
#define SB_V_IP 0 /* in progress */ #define SB_V_IP 0 /* in progress */

View file

@ -1,14 +1,14 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: PDP-1 Simulator Usage Subj: PDP-1 Simulator Usage
Date: 15-Dec-2002 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary: The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik Original code published in 1993-2003, 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), 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 memory reference address decoding
- more than XCTMAX nested executes are detected during - more than XCTMAX nested executes are detected during
instruction execution instruction execution
- wait state entered, and no I/O operations outstanding - I/O wait, and no I/O operations outstanding (i.e, no I/O
(ie, no interrupt can ever occur) completion will ever occur)
The PDP-1 loader supports RIM format tapes. The DUMP command is not The PDP-1 loader supports RIM format tapes. The DUMP command is not
implemented. 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 Copyright (c) 1993-2002, Robert M Supnik
@ -25,6 +25,7 @@
drm Type 24 serial drum drm Type 24 serial drum
23-Jul-03 RMS Fixed incorrect logical, missing activate
05-Dec-02 RMS Cloned from pdp18b_drm.c 05-Dec-02 RMS Cloned from pdp18b_drm.c
*/ */
@ -95,45 +96,44 @@ DEVICE drm_dev = {
/* IOT routines */ /* IOT routines */
int32 drm (int32 IR, int32 dev, int32 IO) int32 drm (int32 IR, int32 dev, int32 dat)
{ {
int32 t; int32 t;
int32 pulse = (IR >> 6) & 037; int32 pulse = (IR >> 6) & 037;
if (drm_dev.flags & DEV_DIS) /* disabled? */ if (drm_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 */
if ((pulse != 001) & (pulse != 011)) /* invalid pulse? */ 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 */
switch (dev) { /* switch on device */ switch (dev) { /* switch on device */
case 061: /* DWR, DRD */ 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 */ drm_unit.FUNC = pulse & DRM_WRITE; /* save function */
break; break;
case 062: /* DBL, DCN */ 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 */ iosta = iosta & ~IOS_DRM; /* clear flags */
drm_err = 0; drm_err = 0;
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time); t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t <= 0) t = t + DRM_NUMWDT; /* wrap around? */ if (t <= 0) t = t + DRM_NUMWDT; /* wrap around? */
sim_activate (&drm_unit, t); /* start operation */
break; break;
case 063: /* DTD */ 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 */ case 064: /* DSE, DSP */
if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */ if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
return (IO | IOT_SKP); return (dat | IOT_SKP);
} }
return IO; return dat;
} }
/* Unit service /* Unit service - this code assumes the entire drum is buffered */
This code assumes the entire drum is buffered.
*/
t_stat drm_svc (UNIT *uptr) t_stat drm_svc (UNIT *uptr)
{ {
int32 i; uint32 i, da;
uint32 da;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */ drm_err = 1; /* set error */

View file

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

View file

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

View file

@ -28,6 +28,7 @@
tti keyboard tti keyboard
tto teleprinter tto teleprinter
23-Jul-03 RMS Revised to detect I/O wait hang
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support 22-Dec-02 RMS Added break support
29-Nov-02 RMS Fixed output flag initialization (found by Derek Peschel) 29-Nov-02 RMS Fixed output flag initialization (found by Derek Peschel)
@ -52,16 +53,16 @@
#define TTI 0 #define TTI 0
#define TTO 1 #define TTO 1
extern int32 sbs, ioc, iosta, PF, IO, PC; int32 ptr_state = 0;
extern int32 M[]; int32 ptr_stopioe = 0;
int32 ptp_stopioe = 0;
int32 ptr_rpls = 0, ptr_stopioe = 0, ptr_state = 0;
int32 ptp_rpls = 0, ptp_stopioe = 0;
int32 tti_hold = 0; /* tti hold buf */ int32 tti_hold = 0; /* tti hold buf */
int32 tto_rpls = 0; /* tto restart */
int32 tty_buf = 0; /* tty buffer */ int32 tty_buf = 0; /* tty buffer */
int32 tty_uc = 0; /* tty uc/lc */ 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 ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr);
t_stat tti_svc (UNIT *uptr); t_stat tti_svc (UNIT *uptr);
@ -123,7 +124,7 @@ UNIT ptr_unit = {
REG ptr_reg[] = { REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 18) }, { ORDATA (BUF, ptr_unit.buf, 18) },
{ FLDATA (DONE, iosta, IOS_V_PTR) }, { FLDATA (DONE, iosta, IOS_V_PTR) },
{ FLDATA (RPLS, ptr_rpls, 0) }, { FLDATA (RPLS, cpls, CPLS_V_PTR) },
{ ORDATA (STATE, ptr_state, 5), REG_HRO }, { ORDATA (STATE, ptr_state, 5), REG_HRO },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
@ -150,7 +151,7 @@ UNIT ptp_unit = {
REG ptp_reg[] = { REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) }, { ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (DONE, iosta, IOS_V_PTP) }, { 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 (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) }, { FLDATA (STOP_IOE, ptp_stopioe, 0) },
@ -177,7 +178,7 @@ UNIT tty_unit[] = {
REG tty_reg[] = { REG tty_reg[] = {
{ ORDATA (BUF, tty_buf, 6) }, { ORDATA (BUF, tty_buf, 6) },
{ FLDATA (UC, tty_uc, UC_V) }, { FLDATA (UC, tty_uc, UC_V) },
{ FLDATA (RPLS, tto_rpls, 0) }, { FLDATA (RPLS, cpls, CPLS_V_TTO) },
{ ORDATA (HOLD, tti_hold, 9), REG_HRO }, { ORDATA (HOLD, tti_hold, 9), REG_HRO },
{ FLDATA (KDONE, iosta, IOS_V_TTI) }, { FLDATA (KDONE, iosta, IOS_V_TTI) },
{ DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT }, { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT },
@ -196,18 +197,18 @@ DEVICE tty_dev = {
/* Paper tape reader: IOT routine */ /* 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 */ iosta = iosta & ~IOS_PTR; /* clear flag */
if (dev == 0030) return ptr_unit.buf; /* RRB */ if (dev == 0030) return ptr_unit.buf; /* RRB */
ptr_state = (dev == 0002)? 18: 0; /* mode = bin/alp */ ptr_state = (dev == 0002)? 18: 0; /* mode = bin/alp */
ptr_rpls = 0;
ptr_unit.buf = 0; /* clear buffer */ ptr_unit.buf = 0; /* clear buffer */
sim_activate (&ptr_unit, ptr_unit.wait);
if (GEN_CPLS (inst)) { /* comp pulse? */ if (GEN_CPLS (inst)) { /* comp pulse? */
ioc = 0; ioc = 0;
ptr_rpls = 1; } cpls = cpls | CPLS_PTR; }
return data; else cpls = cpls & ~CPLS_PTR;
sim_activate (&ptr_unit, ptr_unit.wait);
return dat;
} }
/* Unit service */ /* Unit service */
@ -231,10 +232,12 @@ else if (temp & 0200) { /* binary */
ptr_state = ptr_state - 6; ptr_state = ptr_state - 6;
ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); } ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); }
if (ptr_state == 0) { /* done? */ 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 */ iosta = iosta | IOS_PTR; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */ sbs = sbs | SB_RQ; } /* req seq break */
ioc = ioc | ptr_rpls; } /* restart */
else sim_activate (&ptr_unit, ptr_unit.wait); /* get next char */ else sim_activate (&ptr_unit, ptr_unit.wait); /* get next char */
return SCPE_OK; return SCPE_OK;
} }
@ -245,7 +248,7 @@ t_stat ptr_reset (DEVICE *dptr)
{ {
ptr_state = 0; /* clear state */ ptr_state = 0; /* clear state */
ptr_unit.buf = 0; ptr_unit.buf = 0;
ptr_rpls = 0; cpls = cpls & ~CPLS_PTR;
iosta = iosta & ~IOS_PTR; /* clear flag */ iosta = iosta & ~IOS_PTR; /* clear flag */
sim_cancel (&ptr_unit); /* deactivate unit */ sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK; return SCPE_OK;
@ -253,48 +256,61 @@ return SCPE_OK;
/* Bootstrap routine */ /* Bootstrap routine */
#define BOOT_START 07772 int32 ptr_getw (UNIT *uptr)
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) {
int32 i, tmp, word;
static const int32 boot_rom[] = { for (i = word = 0; i < 3;) {
0730002, /* r, rpb + wait */ if ((tmp = getc (uptr->fileref)) == EOF) return -1;
0327776, /* dio x */ uptr->pos = uptr->pos + 1;
0107776, /* xct x */ if (tmp & 0200) {
0730002, /* rpb + wait */ word = (word << 6) | (tmp & 077);
0760400, /* x, halt */ i++; } }
0607772 /* jmp r */ return word;
}; }
t_stat ptr_boot (int32 unitno, DEVICE *dptr) 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]; for (;;) {
PC = BOOT_START; if ((val = ptr_getw (&ptr_unit)) < 0) return SCPE_FMT;
return SCPE_OK; 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 */ /* 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 */ iosta = iosta & ~IOS_PTP; /* clear flag */
ptp_rpls = 0; ptp_unit.buf = (dev == 0006)? ((dat >> 12) | 0200): (dat & 0377);
ptp_unit.buf = (dev == 0006)? ((data >> 12) | 0200): (data & 0377);
sim_activate (&ptp_unit, ptp_unit.wait); /* start unit */
if (GEN_CPLS (inst)) { /* comp pulse? */ if (GEN_CPLS (inst)) { /* comp pulse? */
ioc = 0; ioc = 0;
ptp_rpls = 1; } cpls = cpls | CPLS_PTP; }
return data; else cpls = cpls & ~CPLS_PTP;
sim_activate (&ptp_unit, ptp_unit.wait); /* start unit */
return dat;
} }
/* Unit service */ /* Unit service */
t_stat ptp_svc (UNIT *uptr) 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 */ iosta = iosta | IOS_PTP; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */ sbs = sbs | SB_RQ; /* req seq break */
ioc = ioc | ptp_rpls; /* process restart */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT); return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */ 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) t_stat ptp_reset (DEVICE *dptr)
{ {
ptp_unit.buf = 0; /* clear state */ ptp_unit.buf = 0; /* clear state */
ptp_rpls = 0; cpls = cpls & ~CPLS_PTP;
iosta = iosta & ~IOS_PTP; /* clear flag */ iosta = iosta & ~IOS_PTP; /* clear flag */
sim_cancel (&ptp_unit); /* deactivate unit */ sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK; return SCPE_OK;
@ -318,7 +334,7 @@ return SCPE_OK;
/* Typewriter IOT routines */ /* 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 */ iosta = iosta & ~IOS_TTI; /* clear flag */
if (inst & (IO_WAIT | IO_CPLS)) /* wait or sync? */ 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; 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 */ iosta = iosta & ~IOS_TTO; /* clear flag */
tto_rpls = 0; tty_buf = dat & TT_WIDTH; /* load buffer */
tty_buf = data & TT_WIDTH; /* load buffer */
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); /* activate unit */
if (GEN_CPLS (inst)) { /* comp pulse? */ if (GEN_CPLS (inst)) { /* comp pulse? */
ioc = 0; ioc = 0;
tto_rpls = 1; } cpls = cpls | CPLS_TTO; }
return data; else cpls = cpls & ~CPLS_TTO;
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); /* activate unit */
return dat;
} }
/* Unit service routines */ /* Unit service routines */
@ -373,9 +389,11 @@ t_stat tto_svc (UNIT *uptr)
{ {
int32 out; int32 out;
if (cpls & CPLS_TTO) { /* completion pulse? */
ioc = 1; /* restart */
cpls = cpls & ~CPLS_TTO; }
iosta = iosta | IOS_TTO; /* set flag */ iosta = iosta | IOS_TTO; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */ sbs = sbs | SB_RQ; /* req seq break */
ioc = ioc | tto_rpls; /* process restart */
if (tty_buf == FIODEC_UC) { /* upper case? */ if (tty_buf == FIODEC_UC) { /* upper case? */
tty_uc = UC; tty_uc = UC;
return SCPE_OK; } return SCPE_OK; }
@ -399,7 +417,7 @@ t_stat tty_reset (DEVICE *dptr)
tty_buf = 0; /* clear buffer */ tty_buf = 0; /* clear buffer */
tty_uc = 0; /* clear case */ tty_uc = 0; /* clear case */
tti_hold = 0; /* clear hold buf */ tti_hold = 0; /* clear hold buf */
tto_rpls = 0; /* clear reset pulse */ cpls = cpls & ~CPLS_TTO;
iosta = (iosta & ~IOS_TTI) | IOS_TTO; /* clear flag */ iosta = (iosta & ~IOS_TTI) | IOS_TTO; /* clear flag */
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate keyboard */ sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate keyboard */
sim_cancel (&tty_unit[TTO]); /* stop printer */ 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 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. 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 05-Dec-02 RMS Added drum support
21-Nov-02 RMS Changed typewriter to half duplex 21-Nov-02 RMS Changed typewriter to half duplex
20-Aug-02 RMS Added DECtape support 20-Aug-02 RMS Added DECtape support
@ -52,6 +53,7 @@ extern int32 M[];
extern int32 PC; extern int32 PC;
extern int32 ascii_to_fiodec[], fiodec_to_ascii[]; extern int32 ascii_to_fiodec[], fiodec_to_ascii[];
extern int32 sc_map[]; extern int32 sc_map[];
extern int32 sim_switches;
/* SCP data structures and interface routines /* SCP data structures and interface routines
@ -86,44 +88,83 @@ const char *sim_stop_messages[] = {
"Breakpoint", "Breakpoint",
"Nested XCT's", "Nested XCT's",
"Nested indirect addresses", "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 getw (FILE *inf)
*/
int32 getword (FILE *fileref)
{ {
int32 i, tmp, word; int32 i, tmp, word;
word = 0; word = 0;
for (i = 0; i < 3;) { for (i = 0; i < 3;) {
if ((tmp = getc (fileref)) == EOF) return -1; if ((tmp = getc (inf)) == EOF) return -1;
if (tmp & 0200) { if (tmp & 0200) {
word = (word << 6) | (tmp & 077); word = (word << 6) | (tmp & 077);
i++; } } i++; } }
return word; return word;
} }
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) t_stat rim_load (FILE *inf)
{ {
int32 origin, val; int32 origin, val;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
for (;;) { for (;;) {
if ((val = getword (fileref)) < 0) return SCPE_FMT; if ((val = getw (inf)) < 0) return SCPE_FMT;
if (((val & 0770000) == 0320000) || /* DIO? */ if (((val & 0760000) == OP_DIO) || /* DIO? */
((val & 0770000) == 0240000)) { /* DAC? - incorrect */ ((val & 0760000) == OP_DAC)) { /* hack - Macro1 err */
origin = val & 07777; origin = val & 07777;
if ((val = getword (fileref)) < 0) return SCPE_FMT; if ((val = getw (inf)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; } M[origin] = val; }
else if ((val & 0770000) == 0600000) { /* JMP? */ else if ((val & 0760000) == OP_JMP) { /* JMP? */
PC = val & 007777; PC = val & 007777;
break; } break; }
else return SCPE_FMT; /* bad instr */
} }
return SCPE_OK; /* done */ 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 */ /* 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. compilation command line.
sim/ sim_defs.h sim/ sim_defs.h
sim_ether.h
sim_rev.h sim_rev.h
sim_sock.h sim_sock.h
sim_tape.h
sim_tmxr.h sim_tmxr.h
sim_ether.h
scp.c scp.c
scp_tty.c scp_tty.c
sim_sock.c
sim_tmxr.c
sim_ether.c sim_ether.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/pdp10/ pdp10_defs.h sim/pdp10/ pdp10_defs.h
pdp10_cpu.c 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 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 with a bug fix for a boostrap problem in TOPS-20 V4.1, or ITS
microcode microcode:
SET CPU STANDARD Standard microcode SET CPU STANDARD Standard microcode
SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix
SET CPU ITS ITS compatible microcode 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 SHOW CPU IOSPACE show I/O space address map
CPU registers include the visible state of the processor as well as the 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: the console output is unit 1. It supports two options:
SET FE STOP halts the PDP-10 operating system 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: 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 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 DZ11's
modem controls; the optional switch -a turns on active disconnects 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 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 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 DOUBLE set unit n double density (default)
SET RYn AUTOSIZE set unit n autosized 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 The floppy disk requires an unsupported driver under TOPS-10 and
is not supported under TOPS-20 or ITS. is not supported under TOPS-20 or ITS.

View file

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

View file

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

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: PDP-11 Simulator Usage Subj: PDP-11 Simulator Usage
Date: 15-Mar-2003 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -40,11 +40,13 @@ sim/ sim_defs.h
sim_ether.h sim_ether.h
sim_rev.h sim_rev.h
sim_sock.h sim_sock.h
sim_tape.h
sim_tmxr.h sim_tmxr.h
scp.c scp.c
scp_tty.c scp_tty.c
sim_ether.c sim_ether.c
sim_sock.c sim_sock.c
sim_tape.c
sim_tmxr.c sim_tmxr.c
sim/pdp11/ pdp11_defs.h 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 2048K (or 2M) set memory size = 2048KB
SET CPU 3072K (or 3M) set memory size = 3072KB SET CPU 3072K (or 3M) set memory size = 3072KB
SET CPU 4096K (or 4M) set memory size = 4096KB 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 SHOW CPU IOSPACE show I/O space address map
If memory size is being reduced, and the memory being truncated contains 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) 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 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. 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 connected to a user-specified port. The ATTACH command specifies
the port to be used: 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 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 DZ11's
modem controls; the optional switch -a turns on active disconnects 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 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 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 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. 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 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 BOOT command. In a Unibus system, an RQ supports 18b addressing. In
a Qbus (22B) system, an RQ supports 22b addressing. 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 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) 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: XQ has the following registers:
name size comments name size comments
SA0 16 station address word 0 SA0 16 station address word 0
SA1 16 station address word 1 SA1 16 station address word 1
SA2 16 station address word 2 SA2 16 station address word 2
SA3 16 station address word 3 SA3 16 station address word 3
SA4 16 station address word 4 SA4 16 station address word 4
SA5 16 station address word 5 SA5 16 station address word 5
CSR 16 control status register CSR 16 control status register
VAR 16 vector address register VAR 16 vector address register
RBDL 32 receive buffer descriptor list RBDL 32 receive buffer descriptor list
XBDL 32 trans(X)mit buffer descriptorlList XBDL 32 trans(X)mit buffer descriptorlList
One final note: because of it's asynchronous nature, the XQ controller is 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, not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers,

View file

@ -26,6 +26,7 @@
rq RQDX3 disk controller 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 19-May-03 RMS Revised for new conditional compilation scheme
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
14-Mar-03 RMS Fixed variable size interaction with save/restore 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; return SCPE_ARG;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT; if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
if (cptr) { 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; if ((r != SCPE_OK) || (cap < RA8U_MINC)) return SCPE_ARG;
drv_tab[val].lbn = cap << (20 - 9); } drv_tab[val].lbn = cap << (20 - 9); }
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (val << UNIT_V_DTYPE); 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 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. 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 25-Apr-03 RMS Revised for extended file support
04-Feb-03 RMS Added RB09, LP09 support 04-Feb-03 RMS Added RB09, LP09 support
22-Nov-02 RMS Added PDP-4 drum support 22-Nov-02 RMS Added PDP-4 drum support
@ -48,7 +51,7 @@
model memory CPU options I/O options 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 integral paper tape reader
Type 75 paper tape punch Type 75 paper tape punch
integral real time clock integral real time clock
@ -79,19 +82,19 @@
KA15 auto pri intr PC15 paper tape reader and punch KA15 auto pri intr PC15 paper tape reader and punch
KF15 power detection KW15 real time clock KF15 power detection KW15 real time clock
KM15 mem protection LP09 line printer KM15 mem protection LP09 line printer
??KT15 mem relocation LP15 line printer KT15 mem relocation LP15 line printer
RP15 disk pack FP15 floating point RP15 disk pack
RF15/RF09 fixed head disk XVM option RF15/RF09 fixed head disk
TC59D magnetic tape TC59D magnetic tape
TC15/TU56 DECtape TC15/TU56 DECtape
LT15 second Teletype LT15 second Teletype
??Indicates not implemented. The PDP-4 manual refers to both an EAE ??Indicates not implemented. The PDP-4 manual refers to a memory
??and a memory extension control; there is no documentation on either. ??extension control; there is no documentation on it.
*/ */
#if !defined (PDP4) && !defined (PDP7) && !defined (PDP9) && !defined (PDP15) #if !defined (PDP4) && !defined (PDP7) && !defined (PDP9) && !defined (PDP15)
#define PDP9 0 /* default to PDP-9 */ #define PDP15 0 /* default to PDP-15 */
#endif #endif
/* Simulator stop codes */ /* Simulator stop codes */
@ -102,6 +105,7 @@
#define STOP_XCT 4 /* nested XCT's */ #define STOP_XCT 4 /* nested XCT's */
#define STOP_API 5 /* invalid API int */ #define STOP_API 5 /* invalid API int */
#define STOP_NONSTD 6 /* non-std dev num */ #define STOP_NONSTD 6 /* non-std dev num */
#define STOP_MME 7 /* mem mgt error */
/* Peripheral configuration */ /* Peripheral configuration */
@ -136,17 +140,49 @@
#define TC02 0 /* DECtape */ #define TC02 0 /* DECtape */
#define TTY1 0 /* second Teletype */ #define TTY1 0 /* second Teletype */
#define BRMASK 0377400 /* bounds mask */ #define BRMASK 0377400 /* bounds mask */
#define BRMASK_XVM 0777400 /* bounds mask, XVM */
#endif #endif
/* Memory */ /* Memory */
#define ADDRMASK ((1 << ADDRSIZE) - 1) /* address mask */ #define AMASK ((1 << ADDRSIZE) - 1) /* address mask */
#define IAMASK 077777 /* ind 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 MAXMEMSIZE (1 << ADDRSIZE) /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */ #define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) #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 */ /* Architectural constants */
#define DMASK 0777777 /* data mask */ #define DMASK 0777777 /* data mask */
@ -165,6 +201,39 @@
#define IOT_REASON (1 << IOT_V_REASON) #define IOT_REASON (1 << IOT_V_REASON)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ #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 */ /* Device information block */
@ -239,6 +308,15 @@ typedef struct pdp18b_dib DIB;
37 - 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 API_HLVL 4 /* hwre levels */
#define ACH_SWRE 040 /* swre int vec */ #define ACH_SWRE 040 /* swre int vec */

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: 18b PDP Simulator Usage Subj: 18b PDP Simulator Usage
Date: 01-Feb-2003 Date: 25-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -44,29 +44,33 @@ PDP-7/ PDP7
PDP-9/ PDP9 PDP-9/ PDP9
PDP-15/ PDP15 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 PDP-4 PDP-7 PDP-9 PDP-15
sim_rev.h sim/ sim_defs.h x x x x
sim_sock.h sim_rev.h x x x x
sim_tmxr.h sim_sock.h x x x x
scp.c sim_tape.h x x
scp_tty.c sim_tmxr.h x x x x
sim_sock.c scp.c x x x x
sim_tmxr.c 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 sim/pdp18b/ pdp18b_defs.h x x x x
pdp18b_cpu.c pdp18b_cpu.c x x x x
pdp18b_drm.c pdp18b_drm.c x x
pdp18b_dt.c pdp18b_dt.c x x x x
pdp18b_lp.c pdp18b_fpp.c x
pdp18b_mt.c pdp18b_lp.c x x x x
pdp18b_rb.c pdp18b_mt.c x x
pdp18b_rf.c pdp18b_rb.c x
pdp18b_rp.c pdp18b_rf.c x x
pdp18b_stddev.c pdp18b_rp.c x
pdp18b_sys.c pdp18b_stddev.c x x x x
pdp18b_tt1.c pdp18b_sys.c x x x x
pdp18b_tt1.c x x
2. 18b PDP Features 2. 18b PDP Features
@ -77,6 +81,7 @@ system device simulates
name(s) name(s)
PDP-4 CPU PDP-4 CPU with 8KW of memory PDP-4 CPU PDP-4 CPU with 8KW of memory
- Type 18 extended arithmetic element (EAE)
PTR,PTP integral paper tape/Type 75 punch PTR,PTP integral paper tape/Type 75 punch
TTI,TTO KSR28 console terminal (Baudot code) TTI,TTO KSR28 console terminal (Baudot code)
LPT Type 62 line printer (Hollerith 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) - KA15 automatic priority interrupt (API)
- KF15 power detection - KF15 power detection
- KM15 memory protection - 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 PTR,PTP PC15 paper tape reader/punch
TTI,TTO KSR 35 console terminal TTI,TTO KSR 35 console terminal
TTI1,TTO1 LT15 second 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 - more than XCTMAX nested executes are detected during
instruction execution instruction execution
The PDP-4 and PDP-7 loaders support only RIM format tapes. The PDP-9 The PDP-4 and PDP-7 LOAD command supports only "second stage" RIM format
and PDP-15 support both RIM and BIN format tapes. If the file extension files (alternating DAC address instructions and data):
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 LOAD file load PDP-4/PDP-7 RIM format file
specified, the file is assumed to be BIN format. RIM loading requires
that the loading address be specified on the command line. 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 2.1 CPU
The CPU options are the presence of the EAE, the presense of the API (for The CPU options are the presence of the EAE, the presense of the API and
the PDP-9 and PDP-15), and the size of main memory. 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 system option comment
SET CPU NOEAE disable EAE
SET CPU API enable API all SET CPU EAE enable EAE
SET CPU NOAPI disable API all SET CPU NOEAE disable EAE
SET CPU 4K set memory size = 4K 9,15 SET CPU API enable API
SET CPU 8K set memory size = 8K 9,15 SET CPU NOAPI disable API
SET CPU 12K set memory size = 12K 9,15 SET CPU PROT enable memory protection
SET CPU 16K set memory size = 16K 15 SET CPU RELOC enable memory relocation
SET CPU 20K set memory size = 20K 15 SET CPU XVM enable XVM relocation
SET CPU 24K set memory size = 24K 9,15 SET CPU NOPROT disable protection, relocation, XVM
SET CPU 28K set memory size = 28K 4 SET CPU 4K set memory size = 4K
SET CPU 32K set memory size = 32K all SET CPU 8K set memory size = 8K
SET CPU 48K set memory size = 48K all SET CPU 12K set memory size = 12K
SET CPU 64K set memory size = 64K all SET CPU 16K set memory size = 16K
SET CPU 80K set memory size = 80K all SET CPU 20K set memory size = 20K
SET CPU 96K set memory size = 96K all SET CPU 24K set memory size = 24K
SET CPU 112K set memory size = 112K all SET CPU 28K set memory size = 28K
SET CPU 128K set memory size = 128K 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 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. 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 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. 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 CPU registers include the visible state of the processor as well as the
control registers for the interrupt system. control registers for the interrupt system.
@ -191,10 +227,11 @@ control registers for the interrupt system.
all PC addr program counter all PC addr program counter
all AC 18 accumulator all AC 18 accumulator
all L 1 link all L 1 link
7,9,15 MQ 18 multiplier-quotient all MQ 18 multiplier-quotient
7,9,15 SC 6 shift counter all SC 6 shift counter
7,9,15 EAE_AC_SIGN 1 EAE AC sign all EAE_AC_SIGN 1 EAE AC sign
all SR 18 front panel switches all SR 18 front panel switches
all ASW addr address switches for RIM load
all INT[0:4] 32 interrupt requests, all INT[0:4] 32 interrupt requests,
0:3 = API levels 0-3 0:3 = API levels 0-3
4 = PI level 4 = PI level
@ -204,12 +241,15 @@ control registers for the interrupt system.
9,15 APIENB 1 API enable 9,15 APIENB 1 API enable
9,15 APIREQ 8 API requesting levels 9,15 APIREQ 8 API requesting levels
9,15 APIACT 8 API active 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 XR 18 index register
15 LR 18 limit 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 USMD 1 user mode
9,15 USMDBUF 1 user mode buffer 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 NEXM 1 non-existent memory violation
9,15 PRVN 1 privilege violation 9,15 PRVN 1 privilege violation
7,9 EXTM 1 extend mode 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 "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). 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 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, register specifies the number of the next data item to be read. Thus,
by changing POS, the user can backspace or advance the reader. 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. The paper tape reader supports the BOOT command. The specific forms
BOOT PTR copies the RIM loader into memory and starts it running, while recognized vary from system to system:
BOOT -F PTR copies the funny format binary loader into memory and starts
it running. 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 The PTR ATTACH command recognizes one switch, -A for ASCII mode. In
ASCII mode, data returned by the read alphabetic command has even parity. 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 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 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. 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 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) 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 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 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 The terminal output (TTO) writes to the simulator console window. It
implements these registers: implements these registers:
@ -346,7 +417,7 @@ implements these registers:
POS 32 number of chararacters output POS 32 number of chararacters output
TIME 24 time from I/O initiation to interrupt 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 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. 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 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: 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 The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time. 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 consists of two independent devices, TTI1 and TTO1.
The second terminal performs input and output through a Telnet session 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 DONE 1 device done flag
TIME 24 time from I/O initiation to interrupt 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: 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 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: 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 Drum data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur. 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 The RB09 was an early fixed-head disk for the PDP-9. It was superceded
by the RF09/RS09. It is disabled by default. 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 RB09 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur. 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 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 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 RF15/RF09 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur. 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-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 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 - ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME 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 Magnetic tape options include the ability to make units write enabled or
or write locked. or write locked.
@ -727,7 +798,7 @@ Error handling is as follows:
OS I/O error parity error; if STOP_IOE, stop 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 The 18b PDP simulators implement symbolic display and input. Display is
controlled by command line switches: 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 # or -p five character packed ASCII string in
two 18b words 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, 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 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 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 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). 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 The simulator does not check the legality of the proposed combination. The
operands for MUY and DVI must be deposited explicitly. operands for MUY and DVI must be deposited explicitly.
Finally, the LAW instruction has the format The LAW instruction has the format
LAW immediate LAW immediate
where immediate is in the range of 0 to 017777. 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 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 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) t_stat drm_boot (int32 unitno, DEVICE *dptr)
{ {
int32 i; int32 i;
extern int32 saved_PC; extern int32 PC;
if (drm_dib.dev != DEV_DRM) return STOP_NONSTD; /* non-std addr? */ 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]; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START; PC = BOOT_START;
return SCPE_OK; 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 }; 0, -1, -1, -1, -1, -1, -1, -1 };
DEVICE dt_dev; DEVICE dt_dev;
int32 dt75 (int32 pulse, int32 AC); int32 dt75 (int32 pulse, int32 dat);
int32 dt76 (int32 pulse, int32 AC); int32 dt76 (int32 pulse, int32 dat);
int32 dt_iors (void); int32 dt_iors (void);
t_stat dt_svc (UNIT *uptr); t_stat dt_svc (UNIT *uptr);
t_stat dt_reset (DEVICE *dptr); t_stat dt_reset (DEVICE *dptr);
@ -423,18 +423,18 @@ DEVICE dt_dev = {
/* IOT routines */ /* IOT routines */
#if defined (TC02) /* TC02/TC15 */ #if defined (TC02) /* TC02/TC15 */
int32 dt75 (int32 pulse, int32 AC) int32 dt75 (int32 pulse, int32 dat)
{ {
int32 old_dtsa = dtsa, fnc; int32 old_dtsa = dtsa, fnc;
UNIT *uptr; UNIT *uptr;
if (((pulse & 060) == 040) && (pulse & 05)) { /* select */ if (((pulse & 060) == 040) && (pulse & 05)) { /* select */
if (pulse & 01) dtsa = 0; /* DTCA */ if (pulse & 01) dtsa = 0; /* DTCA */
if (pulse & 02) AC = dtsa; /* DTRA!... */ if (pulse & 02) dat = dtsa; /* DTRA!... */
if (pulse & 04) { /* DTXA */ if (pulse & 04) { /* DTXA */
if ((AC & DTA_CERF) == 0) dtsb = dtsb & ~DTB_ALLERR; if ((dat & DTA_CERF) == 0) dtsb = dtsb & ~DTB_ALLERR;
if ((AC & DTA_CDTF) == 0) dtsb = dtsb & ~DTB_DTF; if ((dat & DTA_CDTF) == 0) dtsb = dtsb & ~DTB_DTF;
dtsa = dtsa ^ (AC & DTA_RW); } dtsa = dtsa ^ (dat & DTA_RW); }
if ((old_dtsa ^ dtsa) & DTA_UNIT) dt_deselect (old_dtsa); if ((old_dtsa ^ dtsa) & DTA_UNIT) dt_deselect (old_dtsa);
uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */ uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */
fnc = DTA_GETFNC (dtsa); /* get fnc */ fnc = DTA_GETFNC (dtsa); /* get fnc */
@ -445,41 +445,41 @@ if (((pulse & 060) == 040) && (pulse & 05)) { /* select */
dt_seterr (uptr, DTB_SEL); /* select err */ dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); /* new func */ else dt_newsa (dtsa); /* new func */
DT_UPDINT; DT_UPDINT;
return AC; } return dat; }
if ((pulse & 067) == 042) return dtsa; /* DTRA */ if ((pulse & 067) == 042) return dtsa; /* DTRA */
if ((pulse & 067) == 061) /* DTEF */ 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) == 062) return dtsb; /* DTRB */
if ((pulse & 067) == 063) /* DTEF!DTRB */ if ((pulse & 067) == 063) /* DTEF!DTRB */
return ((dtsb & DTB_ERF)? IOT_SKP + dtsb: dtsb); 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 */ if ((pulse & 01) && (dtsb & DTB_DTF)) /* DTDF */
return IOT_SKP + AC; return IOT_SKP + dat;
return AC; return dat;
} }
#else /* Type 550 */ #else /* Type 550 */
int32 dt75 (int32 pulse, int32 AC) int32 dt75 (int32 pulse, int32 dat)
{ {
if (((pulse & 041) == 001) && (dtsb & DTB_DTF)) /* MMDF */ 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 */ else if (((pulse & 041) == 041) && (dtsb & DTB_ERF)) /* MMEF */
AC = AC | IOT_SKP; dat = dat | IOT_SKP;
if (pulse & 002) { /* MMRD */ if (pulse & 002) { /* MMRD */
AC = (AC & ~DMASK) | dtdb; dat = (dat & ~DMASK) | dtdb;
dtsb = dtsb & ~(DTB_DTF | DTB_BEF); } dtsb = dtsb & ~(DTB_DTF | DTB_BEF); }
if (pulse & 004) { /* MMWR */ if (pulse & 004) { /* MMWR */
dtdb = AC & DMASK; dtdb = dat & DMASK;
dtsb = dtsb & ~(DTB_DTF | DTB_BEF); } dtsb = dtsb & ~(DTB_DTF | DTB_BEF); }
DT_UPDINT; DT_UPDINT;
return AC; return dat;
} }
int32 dt76 (int32 pulse, int32 AC) int32 dt76 (int32 pulse, int32 dat)
{ {
int32 fnc, mot, unum; int32 fnc, mot, unum;
UNIT *uptr = NULL; UNIT *uptr = NULL;
@ -487,7 +487,7 @@ UNIT *uptr = NULL;
unum = DTA_GETUNIT (dtsa); /* get unit no */ unum = DTA_GETUNIT (dtsa); /* get unit no */
if (unum >= 0) uptr = dt_dev.units + unum; /* get unit */ if (unum >= 0) uptr = dt_dev.units + unum; /* get unit */
if ((pulse & 001) && (dtsb & DTB_BEF)) /* MMBF */ if ((pulse & 001) && (dtsb & DTB_BEF)) /* MMBF */
AC = AC | IOT_SKP; dat = dat | IOT_SKP;
if (pulse & 002) { /* MMRS */ if (pulse & 002) { /* MMRS */
dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */ dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */
if (uptr) { /* valid unit? */ 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_DIR) dtsb = dtsb | DTB_REV; /* rev? set */
if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700)) if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700))
dtsb = dtsb | DTB_GO; } /* accel? go */ dtsb = dtsb | DTB_GO; } /* accel? go */
AC = (AC & ~DMASK) | dtsb; } dat = (dat & ~DMASK) | dtsb; }
if ((pulse & 044) == 044) { /* MMSE */ if ((pulse & 044) == 044) { /* MMSE */
if ((dtsa ^ AC) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */ if ((dtsa ^ dat) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */
dtsa = (dtsa & ~DTA_UNIT) | (AC & DTA_UNIT); dtsa = (dtsa & ~DTA_UNIT) | (dat & DTA_UNIT);
dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); } dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); }
else if ((pulse & 044) == 004) { /* MMLC */ 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); dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR);
fnc = DTA_GETFNC (dtsa); /* get fnc */ fnc = DTA_GETFNC (dtsa); /* get fnc */
if ((uptr == NULL) || /* invalid? */ if ((uptr == NULL) || /* invalid? */
@ -512,7 +512,7 @@ else if ((pulse & 044) == 004) { /* MMLC */
dt_seterr (uptr, DTB_SEL); /* select err */ dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); } else dt_newsa (dtsa); }
DT_UPDINT; DT_UPDINT;
return AC; return dat;
} }
#endif #endif
@ -836,7 +836,7 @@ case FNC_SRCH: /* search */
return SCPE_OK; } return SCPE_OK; }
sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */ sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* inc WC */ 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 (MEM_ADDR_OK (ma)) M[ma] = blk; /* store block # */
if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0))
dtsb = dtsb | DTB_DTF; /* set DTF */ dtsb = dtsb | DTB_DTF; /* set DTF */
@ -870,7 +870,7 @@ case FNC_READ: /* read */
case 0: /* normal read */ case 0: /* normal read */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK; 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 */ ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
dtdb = bptr[ba]; /* get tape word */ dtdb = bptr[ba]; /* get tape word */
if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */ 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_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK; M[DT_CA] = (M[DT_CA] + 1) & DMASK;
case DTO_WCO: /* wc ovflo */ 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 */ ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
dtdb = dt_substate? 0: M[ma]; /* get word */ dtdb = dt_substate? 0: M[ma]; /* get word */
if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */ 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 */ relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK; 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? */ if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr); wrd = DT_LIN2WD (uptr->pos, uptr);
@ -989,7 +989,7 @@ case FNC_WALL:
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK; 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? */ if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
dtdb = M[ma]; /* get mem word */ dtdb = M[ma]; /* get mem word */
@ -1122,7 +1122,7 @@ return;
int32 dt_comobv (int32 dat) int32 dt_comobv (int32 dat)
{ {
dat = dat ^ 0777777; /* compl obverse */ dat = dat ^ DMASK; /* compl obverse */
dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) | dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) |
((dat >> 3) & 0700) | ((dat & 0700) << 3) | ((dat >> 3) & 0700) | ((dat & 0700) << 3) |
((dat & 070) << 9) | ((dat & 07) << 15); ((dat & 070) << 9) | ((dat & 07) << 15);
@ -1140,16 +1140,16 @@ int32 i, csum, wrd;
#if defined (TC02) /* TC02/TC15 */ #if defined (TC02) /* TC02/TC15 */
csum = 077; /* init csum */ csum = 077; /* init csum */
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ 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; } csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; }
return (csum & 077); return (csum & 077);
#else /* Type 550 */ #else /* Type 550 */
csum = 0777777; csum = DMASK;
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
wrd = bptr[ba + i]; /* get word */ wrd = bptr[ba + i]; /* get word */
csum = csum + wrd; /* 1's comp add */ csum = csum + wrd; /* 1's comp add */
if (csum > 0777777) csum = (csum + 1) & 0777777; } if (csum > DMASK) csum = (csum + 1) & DMASK; }
return (csum ^ 0777777); /* 1's comp res */ return (csum ^ DMASK); /* 1's comp res */
#endif #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 */ if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
return (dt_csum (uptr, blk) << 12); return (dt_csum (uptr, blk) << 12);
#else #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 */ if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
return (dt_csum (uptr, blk)); return (dt_csum (uptr, blk));
#endif /* Type 550 */ #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 lp09 (PDP-9,15) LP09 line printer
lp15 (PDP-15) LP15 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 25-Apr-03 RMS Revised for extended file support
05-Feb-03 RMS Added LP09, fixed conditionalization 05-Feb-03 RMS Added LP09, fixed conditionalization
05-Oct-02 RMS Added DIB, device number support 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_MAX 40 /* pointer max */
#define BPTR_MASK 077 /* buf ptr 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_stopioe = 0;
int32 lp62_bp = 0; /* buffer ptr */ int32 lp62_bp = 0; /* buffer ptr */
char lp62_buf[LP62_BSIZE + 1] = { 0 }; char lp62_buf[LP62_BSIZE + 1] = { 0 };
@ -73,8 +75,8 @@ static const char *lp62_cc[] = {
"\f" }; "\f" };
DEVICE lp62_dev; DEVICE lp62_dev;
int32 lp62_65 (int32 pulse, int32 AC); int32 lp62_65 (int32 pulse, int32 dat);
int32 lp62_66 (int32 pulse, int32 AC); int32 lp62_66 (int32 pulse, int32 dat);
int32 lp62_iors (void); int32 lp62_iors (void);
t_stat lp62_svc (UNIT *uptr); t_stat lp62_svc (UNIT *uptr);
t_stat lp62_reset (DEVICE *dptr); t_stat lp62_reset (DEVICE *dptr);
@ -97,7 +99,8 @@ REG lp62_reg[] = {
{ FLDATA (DONE, int_hwre[API_LPT], INT_V_LPT) }, { FLDATA (DONE, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) }, { FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) },
{ DRDATA (BPTR, lp62_bp, 6) }, { 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 (POS, lp62_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, lp62_unit.wait, 24), PV_LEFT }, { DRDATA (TIME, lp62_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lp62_stopioe, 0) }, { FLDATA (STOP_IOE, lp62_stopioe, 0) },
@ -118,62 +121,62 @@ DEVICE lp62_dev = {
/* IOT routines */ /* IOT routines */
int32 lp62_65 (int32 pulse, int32 AC) int32 lp62_65 (int32 pulse, int32 dat)
{ {
int32 i; 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) { if (pulse & 02) {
int32 sb = pulse & 060; /* subopcode */ int32 sb = pulse & 060; /* subopcode */
if (sb == 000) CLR_INT (LPT); /* LPCF */ if (sb == 000) CLR_INT (LPT); /* LPCF */
if ((sb == 040) && (lp62_bp < BPTR_MAX)) { /* LPLD */ if ((sb == 040) && (lp62_bp < BPTR_MAX)) { /* LPLD */
i = lp62_bp * 3; /* cvt to chr ptr */ i = lp62_bp * 3; /* cvt to chr ptr */
lp62_buf[i] = lp62_trans[(AC >> 12) & 077]; lp62_buf[i] = lp62_trans[(dat >> 12) & 077];
lp62_buf[i + 1] = lp62_trans[(AC >> 6) & 077]; lp62_buf[i + 1] = lp62_trans[(dat >> 6) & 077];
lp62_buf[i + 2] = lp62_trans[AC & 077]; lp62_buf[i + 2] = lp62_trans[dat & 077];
lp62_bp = (lp62_bp + 1) & BPTR_MASK; } lp62_bp = (lp62_bp + 1) & BPTR_MASK; }
} }
if (pulse & 04) /* LPSE */ if (pulse & 04) { /* LPSE */
sim_activate (&lp62_unit, lp62_unit.wait); /* activate */ lp62_spc = 0; /* print */
return AC; 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 */ if ((pulse & 01) && TST_INT (LPTSPC)) /* LSSF */
AC = IOT_SKP | AC; dat = IOT_SKP | dat;
if (pulse & 02) CLR_INT (LPTSPC); /* LSCF */ if (pulse & 02) CLR_INT (LPTSPC); /* LSCF */
if (pulse & 04) { /* LSPR */ 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 */ 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_spc = 0 write buffer to file, set overprint
lp62_iot = 10 write cr, then write buffer to file lp62_spc = 2x space command x, clear overprint
lp62_iot = 2x space command x, then set state to 0
*/ */
t_stat lp62_svc (UNIT *uptr) t_stat lp62_svc (UNIT *uptr)
{ {
int32 i; int32 i;
if (lp62_iot & 020) { /* space? */ if (lp62_spc) { /* space? */
SET_INT (LPTSPC); /* set flag */ SET_INT (LPTSPC); /* set flag */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lp62_stopioe, SCPE_UNATT); 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? */ if (ferror (uptr->fileref)) { /* error? */
perror ("LPT I/O error"); perror ("LPT I/O error");
clearerr (uptr->fileref); clearerr (uptr->fileref);
return SCPE_IOERR; } return SCPE_IOERR; }
lp62_iot = 0; } /* clear state */ lp62_ovrpr = 0; } /* clear overprint */
else { SET_INT (LPT); /* print */ else { SET_INT (LPT); /* print */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lp62_stopioe, SCPE_UNATT); 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 */ fputs (lp62_buf, uptr->fileref); /* print buffer */
if (ferror (uptr->fileref)) { /* test error */ if (ferror (uptr->fileref)) { /* test error */
perror ("LPT I/O error"); perror ("LPT I/O error");
@ -181,7 +184,7 @@ else { SET_INT (LPT); /* print */
return SCPE_IOERR; } return SCPE_IOERR; }
lp62_bp = 0; lp62_bp = 0;
for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */ 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 */ uptr->pos = ftell (uptr->fileref); /* update position */
return SCPE_OK; return SCPE_OK;
} }
@ -197,7 +200,8 @@ CLR_INT (LPTSPC);
sim_cancel (&lp62_unit); /* deactivate unit */ sim_cancel (&lp62_unit); /* deactivate unit */
lp62_bp = 0; /* clear buffer ptr */ lp62_bp = 0; /* clear buffer ptr */
for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */ 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; return SCPE_OK;
} }
@ -235,8 +239,8 @@ static const char *lp647_cc[] = {
"\f" }; "\f" };
DEVICE lp647_dev; DEVICE lp647_dev;
int32 lp647_65 (int32 pulse, int32 AC); int32 lp647_65 (int32 pulse, int32 dat);
int32 lp647_66 (int32 pulse, int32 AC); int32 lp647_66 (int32 pulse, int32 dat);
int32 lp647_iors (void); int32 lp647_iors (void);
t_stat lp647_svc (UNIT *uptr); t_stat lp647_svc (UNIT *uptr);
t_stat lp647_reset (DEVICE *dptr); t_stat lp647_reset (DEVICE *dptr);
@ -285,12 +289,12 @@ DEVICE lp647_dev = {
/* IOT routines */ /* IOT routines */
int32 lp647_65 (int32 pulse, int32 AC) int32 lp647_65 (int32 pulse, int32 dat)
{ {
int32 i, sb; int32 i, sb;
sb = pulse & 060; /* subcode */ 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 */ if (pulse & 02) { /* pulse 02 */
lp647_don = 0; /* clear done */ lp647_don = 0; /* clear done */
CLR_INT (LPT); /* clear int req */ CLR_INT (LPT); /* clear int req */
@ -310,32 +314,32 @@ if (pulse & 004) { /* LPDI */
break; break;
case 040: /* LPB3 */ case 040: /* LPB3 */
if (lp647_bp < LP647_BSIZE) { 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; } lp647_bp = lp647_bp + 1; }
case 020: /* LPB2 */ case 020: /* LPB2 */
if (lp647_bp < LP647_BSIZE) { 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; } lp647_bp = lp647_bp + 1; }
case 060: /* LPB1 */ case 060: /* LPB1 */
if (lp647_bp < LP647_BSIZE) { 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_bp = lp647_bp + 1; }
lp647_don = 1; /* set done */ lp647_don = 1; /* set done */
if (lp647_ie) SET_INT (LPT); /* set int */ if (lp647_ie) SET_INT (LPT); /* set int */
break; } /* end case */ 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 */ if (pulse & 02) { /* LPCF */
lp647_don = 0; /* clear done, int */ lp647_don = 0; /* clear done, int */
CLR_INT (LPT); } CLR_INT (LPT); }
if (pulse & 04) { if (pulse & 04) {
if ((pulse & 060) < 060) { /* LPLS, LPPB, LPPS */ 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 */ sim_activate (&lp647_unit, lp647_unit.wait); } /* activate */
#if defined (PDP9) #if defined (PDP9)
else { /* LPEI */ else { /* LPEI */
@ -343,7 +347,7 @@ if (pulse & 04) {
if (lp647_don) SET_INT (LPT); } if (lp647_don) SET_INT (LPT); }
#endif #endif
} }
return AC; return dat;
} }
/* Unit service. lp647_iot specifies the action to be taken /* Unit service. lp647_iot specifies the action to be taken
@ -442,7 +446,7 @@ int32 lp09_ie = 1; /* int enable */
int32 lp09_stopioe = 0; int32 lp09_stopioe = 0;
DEVICE lp09_dev; DEVICE lp09_dev;
int32 lp09_66 (int32 pulse, int32 AC); int32 lp09_66 (int32 pulse, int32 dat);
int32 lp09_iors (void); int32 lp09_iors (void);
t_stat lp09_svc (UNIT *uptr); t_stat lp09_svc (UNIT *uptr);
t_stat lp09_reset (DEVICE *dptr); t_stat lp09_reset (DEVICE *dptr);
@ -486,13 +490,13 @@ DEVICE lp09_dev = {
/* IOT routines */ /* IOT routines */
int32 lp09_66 (int32 pulse, int32 AC) int32 lp09_66 (int32 pulse, int32 dat)
{ {
int32 sb = pulse & 060; /* subopcode */ int32 sb = pulse & 060; /* subopcode */
if (pulse & 001) { if (pulse & 001) {
if ((sb == 000) && lp09_don) AC = IOT_SKP | AC; /* LSDF */ if ((sb == 000) && lp09_don) dat = IOT_SKP | dat; /* LSDF */
if ((sb == 020) && lp09_err) AC = IOT_SKP | AC; /* LSEF */ if ((sb == 020) && lp09_err) dat = IOT_SKP | dat; /* LSEF */
} }
if (pulse & 002) { if (pulse & 002) {
if (sb == 000) { /* LSCF */ if (sb == 000) { /* LSCF */
@ -501,11 +505,11 @@ if (pulse & 002) {
else if (sb == 020) { /* LPLD */ else if (sb == 020) { /* LPLD */
lp09_don = 0; /* clear done, int */ lp09_don = 0; /* clear done, int */
CLR_INT (LPT); 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) || if ((lp09_unit.buf == 015) || (lp09_unit.buf == 014) ||
(lp09_unit.buf == 012)) (lp09_unit.buf == 012))
sim_activate (&lp09_unit, lp09_unit.wait); 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 (pulse & 004) {
if (sb == 000) { /* LIOF */ if (sb == 000) { /* LIOF */
@ -515,7 +519,7 @@ if (pulse & 004) {
lp09_ie = 1; /* set int enab */ lp09_ie = 1; /* set int enab */
if (lp09_don) SET_INT (LPT); } /* if done, set int */ if (lp09_don) SET_INT (LPT); } /* if done, set int */
} }
return AC; return dat;
} }
/* Unit service */ /* Unit service */
@ -608,8 +612,8 @@ int32 lp15_bp = 0;
char lp15_buf[LP15_BSIZE] = { 0 }; char lp15_buf[LP15_BSIZE] = { 0 };
DEVICE lp15_dev; DEVICE lp15_dev;
int32 lp15_65 (int32 pulse, int32 AC); int32 lp15_65 (int32 pulse, int32 dat);
int32 lp15_66 (int32 pulse, int32 AC); int32 lp15_66 (int32 pulse, int32 dat);
int32 lp15_iors (void); int32 lp15_iors (void);
t_stat lp15_svc (UNIT *uptr); t_stat lp15_svc (UNIT *uptr);
t_stat lp15_reset (DEVICE *dptr); t_stat lp15_reset (DEVICE *dptr);
@ -656,18 +660,18 @@ DEVICE lp15_dev = {
/* IOT routines */ /* IOT routines */
int32 lp15_65 (int32 pulse, int32 AC) int32 lp15_65 (int32 pulse, int32 dat)
{ {
int32 header, sb; int32 header, sb;
sb = pulse & 060; /* subopcode */ sb = pulse & 060; /* subopcode */
if (pulse & 01) { if (pulse & 01) {
if ((sb == 000) && (lp15_sta & (STA_ERR | STA_DON))) /* LPSF */ 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 */ else if ((sb == 020) || (sb == 040)) { /* LPP1, LPPM */
sim_activate (&lp15_unit, lp15_unit.wait); /* activate */ sim_activate (&lp15_unit, lp15_unit.wait); /* activate */
header = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */ header = M[(M[LPT_CA] + 1) & AMASK]; /* get first word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777; M[LPT_CA] = (M[LPT_CA] + 2) & DMASK;
lp15_mode = header & 1; /* mode */ lp15_mode = header & 1; /* mode */
if (sb == 040) lp15_lc = 1; /* line count */ if (sb == 040) lp15_lc = 1; /* line count */
else lp15_lc = (header >> 9) & 0377; else lp15_lc = (header >> 9) & 0377;
@ -675,18 +679,18 @@ if (pulse & 01) {
lp15_bp = 0; } /* reset buf ptr */ lp15_bp = 0; } /* reset buf ptr */
else if (sb == 060) lp15_ie = 0; /* LPDI */ 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 */ if ((pulse & 04) && (sb == 040)) lp15_ie = 1; /* LPEI */
lp15_updsta (0); /* update status */ 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 == 021) lp15_sta = lp15_sta & ~STA_DON; /* LPCD */
if (pulse == 041) lp15_sta = 0; /* LPCF */ if (pulse == 041) lp15_sta = 0; /* LPCF */
lp15_updsta (0); /* update status */ lp15_updsta (0); /* update status */
return AC; return dat;
} }
/* Unit service */ /* Unit service */
@ -709,9 +713,9 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
return IORETURN (lp15_stopioe, SCPE_UNATT); } return IORETURN (lp15_stopioe, SCPE_UNATT); }
for (more = 1; more != 0; ) { /* loop until ctrl */ for (more = 1; more != 0; ) { /* loop until ctrl */
w0 = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */ w0 = M[(M[LPT_CA] + 1) & AMASK]; /* get first word */
w1 = M[(M[LPT_CA] + 2) & ADDRMASK]; /* get second word */ w1 = M[(M[LPT_CA] + 2) & AMASK]; /* get second word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777; /* advance mem addr */ M[LPT_CA] = (M[LPT_CA] + 2) & DMASK; /* advance mem addr */
if (lp15_mode) { /* unpacked? */ if (lp15_mode) { /* unpacked? */
c[0] = w0 & 0177; c[0] = w0 & 0177;
c[1] = w1 & 0177; c[1] = w1 & 0177;

View file

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

View file

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

View file

@ -26,6 +26,7 @@
rf (PDP-9) RF09/RF09 rf (PDP-9) RF09/RF09
(PDP-15) RF15/RS09 (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 14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing 03-Mar-03 RMS Fixed autosizing
12-Feb-03 RMS Removed 8 platter sizing hack 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 */ int32 rf_stopioe = 1; /* stop on error */
DEVICE rf_dev; DEVICE rf_dev;
int32 rf70 (int32 pulse, int32 AC); int32 rf70 (int32 pulse, int32 dat);
int32 rf72 (int32 pulse, int32 AC); int32 rf72 (int32 pulse, int32 dat);
int32 rf_iors (void); int32 rf_iors (void);
t_stat rf_svc (UNIT *uptr); t_stat rf_svc (UNIT *uptr);
t_stat rf_reset (DEVICE *dptr); t_stat rf_reset (DEVICE *dptr);
@ -151,14 +152,14 @@ REG rf_reg[] = {
{ NULL } }; { NULL } };
MTAB rf_mod[] = { MTAB rf_mod[] = {
{ UNIT_PLAT, 0, NULL, "1P", &rf_set_size }, { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
{ UNIT_PLAT, 1, NULL, "2P", &rf_set_size }, { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
{ UNIT_PLAT, 2, NULL, "3P", &rf_set_size }, { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
{ UNIT_PLAT, 3, NULL, "4P", &rf_set_size }, { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
{ UNIT_PLAT, 4, NULL, "5P", &rf_set_size }, { UNIT_PLAT, (4 << UNIT_V_PLAT), NULL, "5P", &rf_set_size },
{ UNIT_PLAT, 5, NULL, "6P", &rf_set_size }, { UNIT_PLAT, (5 << UNIT_V_PLAT), NULL, "6P", &rf_set_size },
{ UNIT_PLAT, 6, NULL, "7P", &rf_set_size }, { UNIT_PLAT, (6 << UNIT_V_PLAT), NULL, "7P", &rf_set_size },
{ UNIT_PLAT, 7, NULL, "8P", &rf_set_size }, { UNIT_PLAT, (7 << UNIT_V_PLAT), NULL, "8P", &rf_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL }, { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } }; { 0 } };
@ -172,14 +173,14 @@ DEVICE rf_dev = {
/* IOT routines */ /* IOT routines */
int32 rf70 (int32 pulse, int32 AC) int32 rf70 (int32 pulse, int32 dat)
{ {
int32 t, sb; int32 t, sb;
sb = pulse & 060; /* subopcode */ sb = pulse & 060; /* subopcode */
if (pulse & 01) { if (pulse & 01) {
if ((sb == 000) && (rf_sta & (RFS_ERR | RFS_DON))) 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 == 020) rf_reset (&rf_dev); /* DSCC */
else if (sb == 040) { /* DSCF */ else if (sb == 040) { /* DSCF */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */ if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
@ -187,19 +188,19 @@ if (pulse & 01) {
} }
if (pulse & 02) { if (pulse & 02) {
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */ 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 */ else if (sb == 020) /* DRAL */
AC = AC | (rf_da & 0777777); dat = dat | (rf_da & DMASK);
else if (sb == 040) /* DSFX */ 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 */ 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 (pulse & 04) {
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */ 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 */ else if (sb == 020) /* DLAL */
rf_da = (rf_da & ~0777777) | (AC & 0777777); rf_da = (rf_da & ~DMASK) | (dat & DMASK);
else if (sb == 040) { /* DSCN */ else if (sb == 040) { /* DSCN */
rf_sta = rf_sta & ~RFS_DON; /* clear done */ rf_sta = rf_sta & ~RFS_DON; /* clear done */
if (GET_FNC (rf_sta) != FN_NOP) { if (GET_FNC (rf_sta) != FN_NOP) {
@ -207,20 +208,20 @@ if (pulse & 04) {
if (t < 0) t = t + RF_NUMWD; /* wrap around? */ if (t < 0) t = t + RF_NUMWD; /* wrap around? */
sim_activate (&rf_unit, t * rf_time); } } /* schedule op */ sim_activate (&rf_unit, t * rf_time); } } /* schedule op */
else if (sb == 060) { /* DLAH */ 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 */ if ((uint32) rf_da >= rf_unit.capac) /* for sizing */
rf_updsta (RFS_NED); } rf_updsta (RFS_NED); }
} }
rf_updsta (0); /* update status */ 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; int32 sb = pulse & 060;
if (pulse & 02) { 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); (sim_is_active (&rf_unit)? 0400000: 0);
else if (sb == 040) { /* DSCD */ else if (sb == 040) { /* DSCD */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */ if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
@ -228,9 +229,9 @@ if (pulse & 02) {
rf_updsta (0); } rf_updsta (0); }
else if (sb == 060) { /* DSRS */ else if (sb == 060) { /* DSRS */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */ 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 */ /* 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? */ do { if ((uint32) rf_da >= uptr->capac) { /* disk overflow? */
rf_updsta (RFS_NED); /* nx disk error */ rf_updsta (RFS_NED); /* nx disk error */
break; } break; }
M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */ M[RF_WC] = (M[RF_WC] + 1) & DMASK; /* incr word count */
pa = M[RF_CA] = (M[RF_CA] + 1) & ADDRMASK; /* incr mem addr */ pa = M[RF_CA] = (M[RF_CA] + 1) & AMASK; /* incr mem addr */
if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */ if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */
M[pa] = *(((int32 *) uptr->filebuf) + rf_da); M[pa] = *(((int32 *) uptr->filebuf) + rf_da);
if ((f == FN_WCHK) && /* write check? */ 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) 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; 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; uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK; return SCPE_OK;
} }

View file

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

View file

@ -29,6 +29,8 @@
tto teleprinter tto teleprinter
clk clock 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 25-Apr-03 RMS Revised for extended file support
14-Mar-03 RMS Clean up flags on detach 14-Mar-03 RMS Clean up flags on detach
01-Mar-03 RMS Added SET/SHOW CLK FREQ support, SET TTI CTRL-C support 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) #define UNIT_PASCII (1 << UNIT_V_PASCII)
extern int32 M[]; 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 int32 sim_switches;
extern UNIT cpu_unit; extern UNIT cpu_unit;
@ -74,10 +76,10 @@ int32 tto_state = 0;
int32 clk_tps = 60; /* ticks/second */ int32 clk_tps = 60; /* ticks/second */
int32 tmxr_poll = 16000; /* term mux poll */ int32 tmxr_poll = 16000; /* term mux poll */
int32 ptr (int32 pulse, int32 AC); int32 ptr (int32 pulse, int32 dat);
int32 ptp (int32 pulse, int32 AC); int32 ptp (int32 pulse, int32 dat);
int32 tti (int32 pulse, int32 AC); int32 tti (int32 pulse, int32 dat);
int32 tto (int32 pulse, int32 AC); int32 tto (int32 pulse, int32 dat);
int32 clk_iors (void); int32 clk_iors (void);
int32 ptr_iors (void); int32 ptr_iors (void);
int32 ptp_iors (void); int32 ptp_iors (void);
@ -188,7 +190,7 @@ DEVICE ptr_dev = {
DIB ptp_dib = { DEV_PTP, 1, &ptp_iors, { &ptp } }; DIB ptp_dib = { DEV_PTP, 1, &ptp_iors, { &ptp } };
UNIT ptp_unit = { 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[] = { REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) }, { 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 } }; 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[] = { REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, TTO_WIDTH) }, { ORDATA (BUF, tto_unit.buf, TTO_WIDTH) },
@ -358,10 +360,10 @@ DEVICE tto_dev = {
/* Clock: IOT routine */ /* Clock: IOT routine */
int32 clk (int32 pulse, int32 AC) int32 clk (int32 pulse, int32 dat)
{ {
if (pulse & 001) { /* CLSF */ 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 & 004) { /* CLON/CLOF */
if (pulse & 040) { /* CLON */ if (pulse & 040) { /* CLON */
CLR_INT (CLK); /* clear flag */ CLR_INT (CLK); /* clear flag */
@ -370,7 +372,7 @@ if (pulse & 004) { /* CLON/CLOF */
sim_activate (&clk_unit, /* start, calibr */ sim_activate (&clk_unit, /* start, calibr */
sim_rtc_init (clk_unit.wait)); } sim_rtc_init (clk_unit.wait)); }
else clk_reset (&clk_dev); } /* CLOF */ else clk_reset (&clk_dev); } /* CLOF */
return AC; return dat;
} }
/* Unit service */ /* Unit service */
@ -380,7 +382,7 @@ t_stat clk_svc (UNIT *uptr)
int32 t; int32 t;
if (clk_state) { /* clock on? */ 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 */ if (M[7] == 0) SET_INT (CLK); /* ovrflo? set flag */
t = sim_rtc_calb (clk_tps); /* calibrate clock */ t = sim_rtc_calb (clk_tps); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */ sim_activate (&clk_unit, t); /* reactivate unit */
@ -426,19 +428,19 @@ return SCPE_OK;
/* Paper tape reader: IOT routine */ /* Paper tape reader: IOT routine */
int32 ptr (int32 pulse, int32 AC) int32 ptr (int32 pulse, int32 dat)
{ {
if (pulse & 001) { /* RSF */ 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 */ if (pulse & 002) { /* RRB, RCF */
CLR_INT (PTR); /* clear done */ CLR_INT (PTR); /* clear done */
AC = AC | ptr_unit.buf; } /* return buffer */ dat = dat | ptr_unit.buf; } /* return buffer */
if (pulse & 004) { /* RSA, RSB */ if (pulse & 004) { /* RSA, RSB */
ptr_state = (pulse & 040)? 18: 0; /* set mode */ ptr_state = (pulse & 040)? 18: 0; /* set mode */
CLR_INT (PTR); /* clear done */ CLR_INT (PTR); /* clear done */
ptr_unit.buf = 0; /* clear buffer */ ptr_unit.buf = 0; /* clear buffer */
sim_activate (&ptr_unit, ptr_unit.wait); } sim_activate (&ptr_unit, ptr_unit.wait); }
return AC; return dat;
} }
/* Unit service */ /* Unit service */
@ -526,6 +528,39 @@ ptr_unit.flags = ptr_unit.flags & ~UNIT_RASCII;
return detach_unit (uptr); 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) #if defined (PDP4) || defined (PDP7)
/* Bootstrap routine, PDP-4 and PDP-7 /* 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 a 4K system, the boostrap resides at 7762-7776.
In an 8K or greater system, the bootstrap resides at 17762-17776. In an 8K or greater system, the bootstrap resides at 17762-17776.
Because the program is so small, simple masking can be 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_START 017577
#define BOOT_FPC 017577 #define BOOT_FPC 017577 /* funny format loader */
#define BOOT_RPC 017770 #define BOOT_RPC 017770 /* RIM loader */
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = { static const int32 boot_rom[] = {
@ -677,6 +711,10 @@ t_stat ptr_boot (int32 unitno, DEVICE *dptr)
int32 i, mask, wd; int32 i, mask, wd;
extern int32 sim_switches; 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 (ptr_dib.dev != DEV_PTR) return STOP_NONSTD; /* non-std addr? */
if (MEMSIZE < 8192) mask = 0767777; /* 4k? */ if (MEMSIZE < 8192) mask = 0767777; /* 4k? */
else mask = 0777777; else mask = 0777777;
@ -684,7 +722,7 @@ for (i = 0; i < BOOT_LEN; i++) {
wd = boot_rom[i]; wd = boot_rom[i];
if ((wd >= 0040000) && (wd < 0640000)) wd = wd & mask; if ((wd >= 0040000) && (wd < 0640000)) wd = wd & mask;
M[(BOOT_START & mask) + i] = wd; } 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; return SCPE_OK;
} }
@ -694,24 +732,24 @@ return SCPE_OK;
t_stat ptr_boot (int32 unitno, DEVICE *dptr) t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{ {
return SCPE_ARG; return ptr_rim_load (ptr_unit.fileref, ASW);
} }
#endif #endif
/* Paper tape punch: IOT routine */ /* Paper tape punch: IOT routine */
int32 ptp (int32 pulse, int32 AC) int32 ptp (int32 pulse, int32 dat)
{ {
if (pulse & 001) { /* PSF */ 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 & 002) CLR_INT (PTP); /* PCF */
if (pulse & 004) { /* PSA, PSB, PLS */ if (pulse & 004) { /* PSA, PSB, PLS */
CLR_INT (PTP); /* clear flag */ CLR_INT (PTP); /* clear flag */
ptp_unit.buf = (pulse & 040)? /* load punch buf */ 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 */ sim_activate (&ptp_unit, ptp_unit.wait); } /* activate unit */
return AC; return dat;
} }
/* Unit service */ /* Unit service */
@ -782,16 +820,16 @@ return detach_unit (uptr);
/* Terminal input: IOT routine */ /* Terminal input: IOT routine */
int32 tti (int32 pulse, int32 AC) int32 tti (int32 pulse, int32 dat)
{ {
if (pulse & 001) { /* KSF */ if (pulse & 001) { /* KSF */
if (TST_INT (TTI)) AC = AC | IOT_SKP; } if (TST_INT (TTI)) dat = dat | IOT_SKP; }
if (pulse & 002) { /* KRB */ if (pulse & 002) { /* KRB */
CLR_INT (TTI); /* clear flag */ 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 */ if (pulse & 004) { /* IORS */
AC = AC | upd_iors (); } dat = dat | upd_iors (); }
return AC; return dat;
} }
/* Unit service */ /* Unit service */
@ -870,15 +908,15 @@ return SCPE_OK;
/* Terminal output: IOT routine */ /* Terminal output: IOT routine */
int32 tto (int32 pulse, int32 AC) int32 tto (int32 pulse, int32 dat)
{ {
if (pulse & 001) { /* TSF */ 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 & 002) CLR_INT (TTO); /* clear flag */
if (pulse & 004) { /* load buffer */ if (pulse & 004) { /* load buffer */
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
tto_unit.buf = AC & TTO_MASK; } /* load buffer */ tto_unit.buf = dat & TTO_MASK; } /* load buffer */
return AC; return dat;
} }
/* Unit service */ /* Unit service */

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. 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 02-Mar-03 RMS Split loaders apart for greater flexibility
09-Feb-03 RMS Fixed bug in FMTASC (found by Hans Pufal) 09-Feb-03 RMS Fixed bug in FMTASC (found by Hans Pufal)
31-Jan-03 RMS Added support for RB09 31-Jan-03 RMS Added support for RB09
@ -47,6 +49,9 @@
#include <ctype.h> #include <ctype.h>
extern DEVICE cpu_dev; extern DEVICE cpu_dev;
#if defined (PDP15)
extern DEVICE fpp_dev;
#endif
extern DEVICE ptr_dev, ptp_dev; extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev; extern DEVICE tti_dev, tto_dev;
extern UNIT tti_unit, tto_unit; extern UNIT tti_unit, tto_unit;
@ -87,7 +92,7 @@ extern UNIT cpu_unit;
extern REG cpu_reg[]; extern REG cpu_reg[];
extern int32 M[]; extern int32 M[];
extern int32 memm; extern int32 memm;
extern int32 saved_PC; extern int32 PC;
/* SCP data structures and interface routines /* SCP data structures and interface routines
@ -111,9 +116,13 @@ char sim_name[] = "PDP-15";
REG *sim_PC = &cpu_reg[0]; 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, &ptr_dev,
&ptp_dev, &ptp_dev,
&tti_dev, &tti_dev,
@ -159,7 +168,8 @@ const char *sim_stop_messages[] = {
"Breakpoint", "Breakpoint",
"Nested XCT's", "Nested XCT's",
"Invalid API interrupt", "Invalid API interrupt",
"Non-standard device number" }; "Non-standard device number",
"Memory management error" };
/* Binary loaders */ /* Binary loaders */
@ -202,7 +212,7 @@ for (;;) {
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT; if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; } if (MEM_ADDR_OK (origin)) M[origin++] = val; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */ else if ((val & 0760000) == OP_JMP) { /* JMP? */
saved_PC = ((origin - 1) & 060000) | (val & 017777); PC = ((origin - 1) & 060000) | (val & 017777);
return SCPE_OK; } return SCPE_OK; }
else if (val == OP_HLT) return SCPE_OK; /* HLT? */ else if (val == OP_HLT) return SCPE_OK; /* HLT? */
else return SCPE_FMT; } /* error */ else return SCPE_FMT; } /* error */
@ -226,7 +236,7 @@ t_stat r;
if (*cptr != 0) { /* more input? */ if (*cptr != 0) { /* more input? */
cptr = get_glyph (cptr, gbuf, 0); /* get origin */ 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 (r != SCPE_OK) return r;
if (*cptr != 0) return SCPE_ARG; } /* no more */ if (*cptr != 0) return SCPE_ARG; } /* no more */
else origin = 0200; /* default 200 */ else origin = 0200; /* default 200 */
@ -234,7 +244,7 @@ else origin = 0200; /* default 200 */
for (;;) { /* word loop */ for (;;) { /* word loop */
if ((val = getword (fileref, &bits)) < 0) return SCPE_FMT; if ((val = getword (fileref, &bits)) < 0) return SCPE_FMT;
if (bits & 1) { /* end of tape? */ if (bits & 1) { /* end of tape? */
if ((val & 0760000) == OP_JMP) saved_PC = if ((val & 0760000) == OP_JMP) PC =
((origin - 1) & 060000) | (val & 017777); ((origin - 1) & 060000) | (val & 017777);
else if (val != OP_HLT) return SCPE_FMT; else if (val != OP_HLT) return SCPE_FMT;
break; } break; }
@ -258,16 +268,16 @@ return SCPE_OK;
t_stat bin_load_915 (FILE *fileref, char *cptr) 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 */ if (*cptr != 0) return SCPE_2MARG; /* no arguments */
do { val = getc (fileref); } /* find end RIM */ do { val = getword (fileref, & bits); } /* find end RIM */
while (((val & 0100) == 0) && (val != EOF)); while ((val >= 0) && ((bits & 1) == 0));
if (val == EOF) rewind (fileref); /* no RIM? rewind */ if (val < 0) rewind (fileref); /* no RIM? rewind */
for (;;) { /* block loop */ for (;;) { /* block loop */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT; if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (val & SIGN) { if (val & SIGN) {
if (val != DMASK) saved_PC = val & 077777; if (val != DMASK) PC = val & 077777;
break; } break; }
cksum = origin = val; /* save origin */ cksum = origin = val; /* save origin */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT; 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_EST 8 /* EAE setup */
#define I_V_ESH 9 /* EAE shift */ #define I_V_ESH 9 /* EAE shift */
#define I_V_EMD 10 /* EAE mul-div */ #define I_V_EMD 10 /* EAE mul-div */
#define I_NPN (I_V_NPN << I_V_FL) /* no operand */ #define I_V_FPM 11 /* FP15 mem ref */
#define I_NPI (I_V_NPI << I_V_FL) /* no operand IOT */ #define I_V_FPI 12 /* FP15 indirect */
#define I_IOT (I_V_IOT << I_V_FL) /* IOT */ #define I_V_FPN 13 /* FP15 no operand */
#define I_MRF (I_V_MRF << I_V_FL) /* memory reference */ #define I_NPN (I_V_NPN << I_V_FL)
#define I_OPR (I_V_OPR << I_V_FL) /* OPR */ #define I_NPI (I_V_NPI << I_V_FL)
#define I_LAW (I_V_LAW << I_V_FL) /* LAW */ #define I_IOT (I_V_IOT << I_V_FL)
#define I_XR (I_V_XR << I_V_FL) /* index */ #define I_MRF (I_V_MRF << I_V_FL)
#define I_XR9 (I_V_XR9 << I_V_FL) /* index literal */ #define I_OPR (I_V_OPR << I_V_FL)
#define I_EST (I_V_EST << I_V_FL) /* EAE setup */ #define I_LAW (I_V_LAW << I_V_FL)
#define I_ESH (I_V_ESH << I_V_FL) /* EAE shift */ #define I_XR (I_V_XR << I_V_FL)
#define I_EMD (I_V_EMD << I_V_FL) /* EAE mul-div */ #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)) #define MD(x) ((I_EMD) + ((x) << I_V_DC))
static const int32 masks[] = { static const int32 masks[] = {
0777777, 0777767, 0740000, 0760000, 0777777, 0777767, 0770000, 0760000,
0763730, 0760000, 0777000, 0777000, 0763730, 0760000, 0777000, 0777000,
0740700, 0760700, 0777700 }; 0740700, 0760700, 0777700, 0777777,
0777777, 0777777 };
static const char *opcode[] = { static const char *opcode[] = {
"CAL", "DAC", "JMS", "DZM", /* mem refs */ "CAL", "DAC", "JMS", "DZM", /* mem refs */
@ -452,9 +469,75 @@ static const char *opcode[] = {
#if defined (PDP15) #if defined (PDP15)
"SPCO", "SKP15", "RES", "SPCO", "SKP15", "RES",
"SBA", "DBA", "EBA", "SBA", "DBA", "EBA",
"ORMM", "RDMM", "LDMM", "MPLR",
"ENB", "INH", "MPRC", "IPFH",
"AAS", "PAX", "PAL", "AAC", "AAS", "PAX", "PAL", "AAC",
"PXA", "AXS", "PXL", "PLA", "PXA", "AXS", "PXL", "PLA",
"PLX", "CLAC","CLX", "CLLR", "AXR", "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 #endif
#if defined (PDP9) || defined (PDP15) #if defined (PDP9) || defined (PDP15)
"MPSK", "MPSNE", "MPCV", "MPEU", "MPSK", "MPSNE", "MPCV", "MPEU",
@ -617,9 +700,74 @@ static const int32 opc_val[] = {
#if defined (PDP15) #if defined (PDP15)
0703341+I_NPI, 0707741+I_NPI, 0707742+I_NPI, 0703341+I_NPI, 0707741+I_NPI, 0707742+I_NPI,
0707761+I_NPI, 0707762+I_NPI, 0707764+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, 0720000+I_XR9, 0721000+I_XR, 0722000+I_XR, 0723000+I_XR9,
0724000+I_XR, 0725000+I_XR9, 0726000+I_XR, 0730000+I_XR, 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, 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 #endif
#if defined (PDP9) || defined (PDP15) #if defined (PDP9) || defined (PDP15)
0701701+I_NPI, 0701741+I_NPI, 0701702+I_NPI, 0701742+I_NPI, 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 */ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ 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 */ switch (j) { /* case on class */
case I_V_NPN: /* no operands */ 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 */ case I_V_MRF: /* mem ref */
#if defined (PDP15) #if defined (PDP15)
if (memm) { if (memm) {
disp = inst & 017777; disp = inst & B_DAMASK;
ma = (addr & 0760000) | disp; } ma = (addr & (AMASK & ~B_DAMASK)) | disp; }
else { else {
disp = inst & 007777; disp = inst & P_DAMASK;
ma = (addr & 0770000) | disp; } ma = (addr & (AMASK & ~P_DAMASK)) | disp; }
fprintf (of, "%s %-o", opcode[i], (cflag? ma & ADDRMASK: disp)); fprintf (of, "%s %-o", opcode[i], (cflag? ma & AMASK: disp));
if (!memm && (inst & 0010000)) fprintf (of, ",X"); if (!memm && (inst & I_IDX)) fprintf (of, ",X");
#else #else
disp = inst & 017777; disp = inst & B_DAMASK;
ma = (addr & 0760000) | disp; ma = (addr & (AMASK & ~B_DAMASK)) | disp;
fprintf (of, "%s %-o", opcode[i], (cflag? ma & ADDRMASK: disp)); fprintf (of, "%s %-o", opcode[i], (cflag? ma & AMASK: disp));
#endif #endif
break; break;
case I_V_OPR: /* operate */ 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]); if (disp == k) fprintf (of, "%s", opcode[i]);
else if (disp < k) fprintf (of, "%s -%-o", opcode[i], k - disp); else if (disp < k) fprintf (of, "%s -%-o", opcode[i], k - disp);
else fprintf (of, "%s +%-o", opcode[i], disp - k); 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 */ return SCPE_OK; } /* end if */
} /* end for */ } /* end for */
return SCPE_ARG; 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) 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; int32 cflag, d, i, j, k, sign, damask, epcmask;
t_stat r; t_stat r, sta = SCPE_OK;
char gbuf[CBUFSIZE]; char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit); cflag = (uptr == NULL) || (uptr == &cpu_unit);
@ -895,31 +1051,31 @@ case I_V_LAW: /* law */
break; break;
case I_V_MRF: /* mem ref */ case I_V_MRF: /* mem ref */
#if defined (PDP15) #if defined (PDP15)
if (memm) dmask = 017777; if (memm) damask = B_DAMASK;
else dmask = 07777; else damask = P_DAMASK;
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
#else #else
dmask = 017777; damask = B_DAMASK;
cptr = get_glyph (cptr, gbuf, 0); /* get next field */ cptr = get_glyph (cptr, gbuf, 0); /* get next field */
#endif #endif
#if defined (PDP4) || defined (PDP7) #if defined (PDP4) || defined (PDP7)
if (strcmp (gbuf, "I") == 0) { /* indirect? */ if (strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | 020000; val[0] = val[0] | I_IND;
cptr = get_glyph (cptr, gbuf, 0); } cptr = get_glyph (cptr, gbuf, 0); }
#endif #endif
epcmask = ADDRMASK & ~dmask; /* get ePC */ epcmask = AMASK & ~damask; /* get ePC */
d = get_uint (gbuf, 8, ADDRMASK, &r); /* get addr */ d = get_uint (gbuf, 8, AMASK, &r); /* get addr */
if (r != SCPE_OK) return SCPE_ARG; 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)) 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; else return SCPE_ARG;
#if defined (PDP15) #if defined (PDP15)
if (!memm) { if (!memm) {
cptr = get_glyph (cptr, gbuf, 0); cptr = get_glyph (cptr, gbuf, 0);
if (gbuf[0] != 0) { if (gbuf[0] != 0) {
if (strcmp (gbuf, "X") != 0) return SCPE_ARG; if (strcmp (gbuf, "X") != 0) return SCPE_ARG;
val[0] = val[0] | 010000; } } val[0] = val[0] | I_IDX; } }
#endif #endif
break; break;
case I_V_EMD: /* or'able */ 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; if (sign > 0) val[0] = val[0] + d;
else if (sign < 0) val[0] = val[0] - d; else if (sign < 0) val[0] = val[0] - d;
else 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 */ break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */ 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 */ TMXR tt_desc = { 1, 0, 0, &tt1_ldsc }; /* mux descriptor */
DEVICE tti1_dev, tto1_dev; DEVICE tti1_dev, tto1_dev;
int32 tti1 (int32 pulse, int32 AC); int32 tti1 (int32 pulse, int32 dat);
int32 tto1 (int32 pulse, int32 AC); int32 tto1 (int32 pulse, int32 dat);
t_stat tti1_svc (UNIT *uptr); t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr); t_stat tto1_svc (UNIT *uptr);
t_stat tti1_reset (DEVICE *dptr); t_stat tti1_reset (DEVICE *dptr);
@ -150,14 +150,14 @@ DEVICE tto1_dev = {
/* Terminal input: IOT routine */ /* Terminal input: IOT routine */
int32 tti1 (int32 pulse, int32 AC) int32 tti1 (int32 pulse, int32 dat)
{ {
if (pulse & 001) { /* KSF1 */ if (pulse & 001) { /* KSF1 */
if (TST_INT (TTI1)) AC = AC | IOT_SKP; } if (TST_INT (TTI1)) dat = dat | IOT_SKP; }
if (pulse & 002) { /* KRB1 */ if (pulse & 002) { /* KRB1 */
CLR_INT (TTI1); /* clear flag */ CLR_INT (TTI1); /* clear flag */
AC= AC | tti1_unit.buf; } /* return buffer */ dat= dat | tti1_unit.buf; } /* return buffer */
return AC; return dat;
} }
/* Unit service */ /* Unit service */
@ -204,15 +204,15 @@ return SCPE_OK;
/* Terminal output: IOT routine */ /* Terminal output: IOT routine */
int32 tto1 (int32 pulse, int32 AC) int32 tto1 (int32 pulse, int32 dat)
{ {
if (pulse & 001) { /* TSF */ 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 & 002) CLR_INT (TTO1); /* clear flag */
if (pulse & 004) { /* load buffer */ if (pulse & 004) { /* load buffer */
sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */ sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */
tto1_unit.buf = AC & 0377; } /* load buffer */ tto1_unit.buf = dat & 0377; } /* load buffer */
return AC; return dat;
} }
/* Unit service */ /* Unit service */

View file

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

View file

@ -25,6 +25,7 @@
rf RF08 fixed head disk 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 14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing 03-Mar-03 RMS Fixed autosizing
02-Feb-03 RMS Added variable platter and autosizing support 02-Feb-03 RMS Added variable platter and autosizing support
@ -154,10 +155,10 @@ REG rf_reg[] = {
{ NULL } }; { NULL } };
MTAB rf_mod[] = { MTAB rf_mod[] = {
{ UNIT_PLAT, 0, NULL, "1P", &rf_set_size }, { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
{ UNIT_PLAT, 1, NULL, "2P", &rf_set_size }, { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
{ UNIT_PLAT, 2, NULL, "3P", &rf_set_size }, { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
{ UNIT_PLAT, 3, NULL, "4P", &rf_set_size }, { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL }, { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL }, &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) 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; 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; uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK; 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) MODE[0:7] 12 channel mode (from EOM instruction)
FLAG[0:7] 9 channel flags FLAG[0:7] 9 channel flags
The user can display all the registers in a channel with the command SHOW The user can display all the registers in a channel with the command:
CHAN <chan>.
SHOW CHAN channel-letter
2.3 Console Input (TTI) 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 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. connections are lost when the simulator shuts down or MUX is detached.
2.10 Project Genie Drum (DRM) 2.10 Project Genie Drum (DRM)
@ -419,11 +420,8 @@ Error handling is as follows:
not attached 1 report error and stop not attached 1 report error and stop
0 disk not ready 0 disk not ready
end of file x assume rest of disk is zero 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.
OS I/O error x report error and stop
By default, the rapid access disk is assigned to channel E.
2.12 Moving Head Disk (DSK) 2.12 Moving Head Disk (DSK)
@ -456,9 +454,12 @@ Error handling is as follows:
not attached 1 report error and stop not attached 1 report error and stop
0 disk not ready 0 disk not ready
Rapid access disk data files are buffered in memory; therefore, end of file end of file x assume rest of disk is zero
and OS I/O errors cannot occur. By default, the rapid access disk is
assigned to channel F. 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) 2.13 Magnetic Tape (MT)

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: VAX Simulator Usage Subj: VAX Simulator Usage
Date: 15-Jun-2003 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -37,17 +37,20 @@ This memorandum documents the VAX simulator.
1. Simulator Files 1. Simulator Files
To compile the VAX, you must define VM_VAX and USE_INT64 as part of the compilation 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/ sim_defs.h
sim_ether.h sim_ether.h
sim_rev.h sim_rev.h
sim_sock.h sim_sock.h
sim_tape.h
sim_tmxr.h sim_tmxr.h
scp.c scp.c
scp_tty.c scp_tty.c
sim_ether.c sim_ether.c
sim_sock.c sim_sock.c
sim_tape.c
sim_tmxr.c sim_tmxr.c
sim/vax/ vax_defs.h sim/vax/ vax_defs.h
@ -59,6 +62,7 @@ sim/vax/ vax_defs.h
vax_mmu.c vax_mmu.c
vax_stddev.c vax_stddev.c
vax_sys.c vax_sys.c
vax_sysdev.c
sim/pdp11/ pdp11_mscp.h sim/pdp11/ pdp11_mscp.h
pdp11_uqssp.h pdp11_uqssp.h
@ -90,7 +94,7 @@ PTR,PTP PCV11 paper tape reader/punch
TTI,TTO console terminal TTI,TTO console terminal
LPT LPV11 line printer LPT LPV11 line printer
CLK real-time clock 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 RL RLV12/RL01(2) cartridge disk controller with four drives
RQ RQDX3 MSCP controller with four drives RQ RQDX3 MSCP controller with four drives
RQB second 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 64M set memory size = 64MB
SET CPU SIMHALT kernel HALT returns to simulator SET CPU SIMHALT kernel HALT returns to simulator
SET CPU CONHALT kernel HALT returns to boot ROM console 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 SHOW CPU IOSPACE show I/O space address map
If memory size is being reduced, and the memory being truncated contains 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. 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: This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY -- clear history buffer SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 -- disable history SET CPU HISTORY=0 disable history
SET CPU HISTORY=n -- enable history, display length = n SET CPU HISTORY=n enable history, display length = n
SHOW CPU HISTORY -- print CPU history SHOW CPU HISTORY print CPU history
The maximum length for the history is 4096 entries. 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 It has no registers. The boot ROM is loaded with a binary byte stream
using the LOAD -r command: 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 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 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 power-up self-test routines run correctly on very fast hosts. The delay
is controlled with the commands: is controlled with the commands:
SET ROM NODELAY -- ROM runs like RAM SET ROM NODELAY ROM runs like RAM
SET ROM DELAY -- ROM runs slowly SET ROM DELAY ROM runs slowly
2.1.4 Non-volatile Memory (NVR) 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 The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time. 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 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 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 may be incompatible with certain operating systems. The command
SET DZ 7B 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 connected to a user-specified port. The ATTACH command specifies
the port to be used: 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 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 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 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 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 SHOW DZ STATISTICS command displays statistics for active connections.
The SET DZ DISCONNECT=linenumber disconnects the specified line. The SET DZ DISCONNECT=linenumber disconnects the specified line.
The DZ11 implements these registers: The DZV11 implements these registers:
name size comments name size comments
@ -544,7 +554,7 @@ The DZ11 implements these registers:
MDMTCL 1 modem control enabled MDMTCL 1 modem control enabled
AUTODS 1 autodisconnect 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. lost when the simulator shuts down or the DZ is detached.
2.4 RLV12/RL01,RL02 Cartridge Disk (RL) 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 RA72 set type to RA72
SET RQn RA90 set type to RA90 SET RQn RA90 set type to RA90
SET RQn RA92 set type to RA92 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. 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. Units can also be set ONLINE or OFFLINE.
Each RQ controller implements the following special SHOW commands: 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 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) 2.6 TSV11/TSV05 Magnetic Tape (TS)
@ -780,13 +795,13 @@ The TQ controller implements these registers:
Error handling is as follows: 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) 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: XQ has the following registers:
name size comments name size comments
SA0 16 station address word 0 SA0 16 station address word 0
SA1 16 station address word 1 SA1 16 station address word 1
SA2 16 station address word 2 SA2 16 station address word 2
SA3 16 station address word 3 SA3 16 station address word 3
SA4 16 station address word 4 SA4 16 station address word 4
SA5 16 station address word 5 SA5 16 station address word 5
CSR 16 control status register CSR 16 control status register
VAR 16 vector address register VAR 16 vector address register
RBDL 32 receive buffer descriptor list RBDL 32 receive buffer descriptor list
XBDL 32 trans(X)mit buffer descriptorlList XBDL 32 trans(X)mit buffer descriptorlList
One final note: because of it's asynchronous nature, the XQ controller is 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, 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 \ 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_lp.c ${PDP18BD}pdp18b_mt.c ${PDP18BD}pdp18b_rf.c \
${PDP18BD}pdp18b_rp.c ${PDP18BD}pdp18b_stddev.c ${PDP18BD}pdp18b_sys.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} PDP4_OPT = -DPDP4 -I ${PDP18BD}
PDP7_OPT = -DPDP7 -I ${PDP18BD} PDP7_OPT = -DPDP7 -I ${PDP18BD}
PDP9_OPT = -DPDP9 -I ${PDP18BD} PDP9_OPT = -DPDP9 -I ${PDP18BD}
@ -150,7 +150,8 @@ IBM1130D = Ibm1130/
IBM1130 = ${IBM1130D}ibm1130_cpu.c ${IBM1130D}ibm1130_cr.c \ IBM1130 = ${IBM1130D}ibm1130_cpu.c ${IBM1130D}ibm1130_cr.c \
${IBM1130D}ibm1130_disk.c ${IBM1130D}ibm1130_stddev.c \ ${IBM1130D}ibm1130_disk.c ${IBM1130D}ibm1130_stddev.c \
${IBM1130D}ibm1130_sys.c ${IBM1130D}ibm1130_gdu.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} 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 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. 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 15-Jun-03 RMS Added register flag REG_VMIO
25-Apr-03 RMS Added extended address support (V3.0) 25-Apr-03 RMS Added extended address support (V3.0)
Fixed bug in SAVE (found by Peter Schorn) Fixed bug in SAVE (found by Peter Schorn)
@ -1324,7 +1325,6 @@ DEVICE *dptr;
uint32 i; uint32 i;
t_stat reason; t_stat reason;
if (start < 0) return SCPE_IERR;
for (i = 0; i < start; i++) { for (i = 0; i < start; i++) {
if (sim_devices[i] == NULL) return SCPE_IERR; } if (sim_devices[i] == NULL) return SCPE_IERR; }
for (i = start; (dptr = sim_devices[i]) != NULL; i++) { 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 */ c = sim_os_poll_kbd (); /* check for stop char */
if ((c == SCPE_STOP) || stop_cpu) return SCPE_STOP; if ((c == SCPE_STOP) || stop_cpu) return SCPE_STOP;
if ((i % 10) == 0) { /* Status every 10 sec */ if ((i % 10) == 0) { /* Status every 10 sec */
printf ("Waiting for console Telnet connnection\n"); printf ("Waiting for console Telnet connection\n");
fflush (stdout); } fflush (stdout); }
sim_os_sleep (1); /* wait 1 second */ sim_os_sleep (1); /* wait 1 second */
} }

View file

@ -185,9 +185,9 @@ int32 i;
sys$gettim (tod); /* time 0.1usec */ 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 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; quo = htod = 0;

View file

@ -29,12 +29,64 @@
#define SIM_MAJOR 3 #define SIM_MAJOR 3
#define SIM_MINOR 0 #define SIM_MINOR 0
#define SIM_PATCH 0 #define SIM_PATCH 1
/* V3.0 revision history /* V3.0 revision history
patch date module(s) and fix(es) 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: 0 15-Jun-03 scp.c:
-- added ASSIGN/DEASSIGN -- added ASSIGN/DEASSIGN
-- changed RESTORE to detach files -- changed RESTORE to detach files

View file

@ -528,7 +528,7 @@ if (map) map[objc] = tpos;
return objc; 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) t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map)
{ {

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: Simulator Usage, V3.0 Subj: Simulator Usage, V3.1
Date: 15-May-2004 Date: 15-Jul-2003
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -155,8 +155,7 @@ Examples:
The Windows-specific Ethernet code uses the WinPCAP 3.0 package. The Windows-specific Ethernet code uses the WinPCAP 3.0 package.
This package for windows simulates the libpcap package that is freely This package for windows simulates the libpcap package that is freely
available for Unix systems. Note that WinPCAP DOES NOT SUPPORT dual available for Unix systems.
CPU environments.
WinPCAP must be installed prior to building the PDP-11 and VAX WinPCAP must be installed prior to building the PDP-11 and VAX
simulators with Ethernet support. 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? 2.2 How do I install SIMH with Ethernet support on Windows?
First, you must download download and install the WinPCAP AutoInstaller and The pre-compiled binaries contain Ethernet support. Before running these
developer's kit from binaries, you must download download and install the WinPCAP AutoInstaller from
http://winpcap.polito.it http://winpcap.polito.it
This creates a network packet driver in Windows for SIMH to attach to. 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 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 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 autostart when the system boots; see the WinPCAP FAQ page for detailed