Notes For V2.10-2

1. New Features in 2.10-2

The build procedures have changed.  There is only one UNIX makefile.
To compile without Ethernet support, simply type

	gmake {target|all}

To compile with Ethernet support, type

	gmake USE_NETWORK=1 {target|all}

The Mingw batch files require Mingw release 2 and invoke the Unix
makefile.  There are still separate batch files for compilation
with or without Ethernet support.

1.1 SCP and Libraries

- The EVAL command will evaluate a symbolic type-in and display
  it in numeric form.
- The ! command (with no arguments) will launch the host operating
  system command shell.  The ! command (with an argument) executes
  the argument as a host operating system command.  (Code from
  Mark Pizzolato)
- Telnet sessions now recognize BREAK.  How a BREAK is transmitted
  dependent on the particular Telnet client.  (Code from Mark
  Pizzolato)
- The sockets library includes code for active connections as
  well as listening connections.
- The RESTORE command will restore saved memory size, if the
  simulator supports dynamic memory resizing.

1.2 PDP-1

- The PDP-1 supports the Type 24 serial drum (based on recently
  discovered documents).

1.3 18b PDP's

- The PDP-4 supports the Type 24 serial drum (based on recently
  discovered documents).

1.4 PDP-11

- The PDP-11 implements a stub DEUNA/DELUA (XU).  The real XU
  module will be included in a later release.

1.5 PDP-10

- The PDP-10 implements a stub DEUNA/DELUA (XU).  The real XU
  module will be included in a later release.

1.6 HP 2100

- The IOP microinstruction set is supported for the 21MX as well
  as the 2100.
- The HP2100 supports the Access Interprocessor Link (IPL).

1.7 VAX

- If the VAX console is attached to a Telnet session, BREAK is
  interpreted as console halt.
- The SET/SHOW HISTORY commands enable and display a history of
  the most recently executed instructions.  (Code from Mark
  Pizzolato)

1.8 Terminals Multiplexors

- BREAK detection was added to the HP, DEC, and Interdata terminal
  multiplexors.

1.9 Interdata 16b and 32b

- First release.  UNIX is not yet working.

1.10 SDS 940

- First release.

2. Bugs Fixed in 2.10-2

- PDP-11 console must default to 7b for early UNIX compatibility.
- PDP-11/VAX TMSCP emulator was using the wrong packet length for
  read/write end packets.
- Telnet IAC+IAC processing was fixed, both for input and output
  (found by Mark Pizzolato).
- PDP-11/VAX Ethernet setting flag bits wrong for chained
  descriptors (found by Mark Pizzolato).

3. New Features in 2.10 vs prior releases

3.1 SCP and Libraries

- The VT emulation package has been replaced by the capability
  to remote the console to a Telnet session.  Telnet clients
  typically have more complete and robust VT100 emulation.
- Simulated devices may now have statically allocated buffers,
  in addition to dynamically allocated buffers or disk-based
  data stores.
- The DO command now takes substitutable arguments (max 9).
  In command files, %n represents substitutable argument n.
- The initial command line is now interpreted as the command
  name and substitutable arguments for a DO command.  This is
  backward compatible to prior versions.
- The initial command line parses switches.  -Q is interpreted
  as quiet mode; informational messages are suppressed.
- The HELP command now takes an optional argument.  HELP <cmd>
  types help on the specified command.
- Hooks have been added for implementing GUI-based consoles,
  as well as simulator-specific command extensions.  A few
  internal data structures and definitions have changed.
- Two new routines (tmxr_open_master, tmxr_close_master) have
  been added to sim_tmxr.c.  The calling sequence for
  sim_accept_conn has been changed in sim_sock.c.
- The calling sequence for the VM boot routine has been modified
  to add an additional parameter.
- SAVE now saves, and GET now restores, controller and unit flags.
- Library sim_ether.c has been added for Ethernet support.

3.2 VAX

- Non-volatile RAM (NVR) can behave either like a memory or like
  a disk-based peripheral.  If unattached, it behaves like memory
  and is saved and restored by SAVE and RESTORE, respectively.
  If attached, its contents are loaded from disk by ATTACH and
  written back to disk at DETACH and EXIT.
- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape) has been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from vax_stddev.c and
  now references a common implementation file, dec_pt.h.
- Examine and deposit switches now work on all devices, not just
  the CPU.
- Device address conflicts are not detected until simulation starts.

3.3 PDP-11

- SHOW <device> VECTOR displays the device's interrupt vector.
  Most devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk),
  RX211 (double density floppy), and KW11P programmable clock
  have been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from pdp11_stddev.c and
  now references a common implementation file, dec_pt.h.
- Device bootstraps now use the actual CSR specified by the
  SET ADDRESS command, rather than just the default CSR.  Note
  that PDP-11 operating systems may NOT support booting with
  non-standard addresses.
- Specifying more than 256KB of memory, or changing the bus
  configuration, causes all peripherals that are not compatible
  with the current bus configuration to be disabled.
- Device address conflicts are not detected until simulation starts.

3.4 PDP-10

- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The RX211 (double density floppy) has been added; it is off
  by default.
- The paper tape now references a common implementation file,
  dec_pt.h.
- Device address conflicts are not detected until simulation starts.

3.5 PDP-1

- DECtape (then known as MicroTape) support has been added.
- The line printer and DECtape can be disabled and enabled.

3.6 PDP-8

- The RX28 (double density floppy) has been added as an option to
  the existing RX8E controller.
- SHOW <device> DEVNO displays the device's device number.  Most
  devices allow the device number to be changed with SET <device>
  DEVNO=nnn.
- Device number conflicts are not detected until simulation starts.

3.7 IBM 1620

- The IBM 1620 simulator has been released.

3.8 AltairZ80

- A hard drive has been added for increased storage.
- Several bugs have been fixed.

3.9 HP 2100

- The 12845A has been added and made the default line printer (LPT).
  The 12653A has been renamed LPS and is off by default.  It also
  supports the diagnostic functions needed to run the DCPC and DMS
  diagnostics.
- The 12557A/13210A disk defaults to the 13210A (7900/7901).
- The 12559A magtape is off by default.
- New CPU options (EAU/NOEAU) enable/disable the extended arithmetic
  instructions for the 2116.  These instructions are standard on
  the 2100 and 21MX.
- New CPU options (MPR/NOMPR) enable/disable memory protect for the
  2100 and 21MX.
- New CPU options (DMS/NODMS) enable/disable the dynamic mapping
  instructions for the 21MX.
- The 12539 timebase generator autocalibrates.

3.10 Simulated Magtapes

- Simulated magtapes recognize end of file and the marker
  0xFFFFFFFF as end of medium.  Only the TMSCP tape simulator
  can generate an end of medium marker.
- The error handling in simulated magtapes was overhauled to be
  consistent through all simulators.

3.11 Simulated DECtapes

- Added support for RT11 image file format (256 x 16b) to DECtapes.

4. Bugs Fixed in 2.10 vs prior releases

- TS11/TSV05 was not simulating the XS0_MOT bit, causing failures
  under VMS.  In addition, two of the CTL options were coded
  interchanged.
- IBM 1401 tape was not setting a word mark under group mark for
  load mode reads.  This caused the diagnostics to crash.
- SCP bugs in ssh_break and set_logon were fixed (found by Dave
  Hittner).
- Numerous bugs in the HP 2100 extended arithmetic, floating point,
  21MX, DMS, and IOP instructions were fixed.  Bugs were also fixed
  in the memory protect and DMS functions.  The moving head disks
  (DP, DQ) were revised to simulate the hardware more accurately.
  Missing functions in DQ (address skip, read address) were added.
- PDP-10 tape wouldn't boot, and then wouldn't read (reported by
  Michael Thompson and Harris Newman, respectively)
- PDP-1 typewriter is half duplex, with only one shift state for
  both input and output (found by Derek Peschel)

5. General Notes

WARNING: V2.10 has reorganized and renamed some of the definition
files for the PDP-10, PDP-11, and VAX.  Be sure to delete all
previous source files before you unpack the Zip archive, or
unpack it into a new directory structure.

WARNING: V2.10 has a new, more comprehensive save file format.
Restoring save files from previous releases will cause 'invalid
register' errors and loss of CPU option flags, device enable/
disable flags, unit online/offline flags, and unit writelock
flags.

WARNING: If you are using Visual Studio .NET through the IDE,
be sure to turn off the /Wp64 flag in the project settings, or
dozens of spurious errors will be generated.

WARNING: Compiling Ethernet support under Windows requires
extra steps; see the Ethernet readme file.  Ethernet support is
currently available only for Windows, Linux, NetBSD, and OpenBSD.
This commit is contained in:
Bob Supnik 2003-01-17 18:35:00 -08:00 committed by Mark Pizzolato
parent 4ea745b3ad
commit 2bcd1e7c4c
206 changed files with 30253 additions and 12114 deletions

View file

@ -1,28 +1,97 @@
Notes For V2.10-1
Notes For V2.10-2
WARNING: V2.10 has reorganized and renamed some of the definition
files for the PDP-10, PDP-11, and VAX. Be sure to delete all
previous source files before you unpack the Zip archive, or
unpack it into a new directory structure.
1. New Features in 2.10-2
WARNING: V2.10 has a new, more comprehensive save file format.
Restoring save files from previous releases will cause 'invalid
register' errors and loss of CPU option flags, device enable/
disable flags, unit online/offline flags, and unit writelock
flags.
The build procedures have changed. There is only one UNIX makefile.
To compile without Ethernet support, simply type
WARNING: If you are using Visual Studio .NET through the IDE,
be sure to turn off the /Wp64 flag in the project settings, or
dozens of spurious errors will be generated.
gmake {target|all}
WARNING: Compiling Ethernet support under Windows requires
extra steps; see the Ethernet readme file. Ethernet support is
currently available only for Windows, Linux, NetBSD, and OpenBSD.
To compile with Ethernet support, type
1. New Features
gmake USE_NETWORK=1 {target|all}
The Mingw batch files require Mingw release 2 and invoke the Unix
makefile. There are still separate batch files for compilation
with or without Ethernet support.
1.1 SCP and Libraries
- The EVAL command will evaluate a symbolic type-in and display
it in numeric form.
- The ! command (with no arguments) will launch the host operating
system command shell. The ! command (with an argument) executes
the argument as a host operating system command. (Code from
Mark Pizzolato)
- Telnet sessions now recognize BREAK. How a BREAK is transmitted
dependent on the particular Telnet client. (Code from Mark
Pizzolato)
- The sockets library includes code for active connections as
well as listening connections.
- The RESTORE command will restore saved memory size, if the
simulator supports dynamic memory resizing.
1.2 PDP-1
- The PDP-1 supports the Type 24 serial drum (based on recently
discovered documents).
1.3 18b PDP's
- The PDP-4 supports the Type 24 serial drum (based on recently
discovered documents).
1.4 PDP-11
- The PDP-11 implements a stub DEUNA/DELUA (XU). The real XU
module will be included in a later release.
1.5 PDP-10
- The PDP-10 implements a stub DEUNA/DELUA (XU). The real XU
module will be included in a later release.
1.6 HP 2100
- The IOP microinstruction set is supported for the 21MX as well
as the 2100.
- The HP2100 supports the Access Interprocessor Link (IPL).
1.7 VAX
- If the VAX console is attached to a Telnet session, BREAK is
interpreted as console halt.
- The SET/SHOW HISTORY commands enable and display a history of
the most recently executed instructions. (Code from Mark
Pizzolato)
1.8 Terminals Multiplexors
- BREAK detection was added to the HP, DEC, and Interdata terminal
multiplexors.
1.9 Interdata 16b and 32b
- First release. UNIX is not yet working.
1.10 SDS 940
- First release.
2. Bugs Fixed in 2.10-2
- PDP-11 console must default to 7b for early UNIX compatibility.
- PDP-11/VAX TMSCP emulator was using the wrong packet length for
read/write end packets.
- Telnet IAC+IAC processing was fixed, both for input and output
(found by Mark Pizzolato).
- PDP-11/VAX Ethernet setting flag bits wrong for chained
descriptors (found by Mark Pizzolato).
3. New Features in 2.10 vs prior releases
3.1 SCP and Libraries
- The VT emulation package has been replaced by the capability
to remote the console to a Telnet session. Telnet clients
typically have more complete and robust VT100 emulation.
@ -49,7 +118,7 @@ currently available only for Windows, Linux, NetBSD, and OpenBSD.
- SAVE now saves, and GET now restores, controller and unit flags.
- Library sim_ether.c has been added for Ethernet support.
1.2 VAX
3.2 VAX
- Non-volatile RAM (NVR) can behave either like a memory or like
a disk-based peripheral. If unattached, it behaves like memory
@ -69,7 +138,7 @@ currently available only for Windows, Linux, NetBSD, and OpenBSD.
the CPU.
- Device address conflicts are not detected until simulation starts.
1.3 PDP-11
3.3 PDP-11
- SHOW <device> VECTOR displays the device's interrupt vector.
Most devices allow the vector to be changed with SET
@ -91,7 +160,7 @@ currently available only for Windows, Linux, NetBSD, and OpenBSD.
with the current bus configuration to be disabled.
- Device address conflicts are not detected until simulation starts.
1.4 PDP-10
3.4 PDP-10
- SHOW <device> VECTOR displays the device's interrupt vector.
A few devices allow the vector to be changed with SET
@ -103,30 +172,30 @@ currently available only for Windows, Linux, NetBSD, and OpenBSD.
dec_pt.h.
- Device address conflicts are not detected until simulation starts.
1.5 PDP-1
3.5 PDP-1
- DECtape (then known as MicroTape) support has been added.
- The line printer and DECtape can be disabled and enabled.
1.6 PDP-8
3.6 PDP-8
- The RX28 (double density floppy) has been added as an option to
the existing RX8E controller.
- SHOW <device> DEVNO displays the device's device number. Most
devices allow the device number to be changed with SET <device>
DEVNO=nnn.
- Device number conflicts are not detected until simulation starts.
- Device number conflicts are not detected until simulation starts.
1.7 IBM 1620
3.7 IBM 1620
- The IBM 1620 simulator has been released.
1.8 AltairZ80
3.8 AltairZ80
- A hard drive has been added for increased storage.
- Several bugs have been fixed.
1.9 HP 2100
3.9 HP 2100
- The 12845A has been added and made the default line printer (LPT).
The 12653A has been renamed LPS and is off by default. It also
@ -143,7 +212,7 @@ currently available only for Windows, Linux, NetBSD, and OpenBSD.
instructions for the 21MX.
- The 12539 timebase generator autocalibrates.
1.10 Simulated Magtapes
3.10 Simulated Magtapes
- Simulated magtapes recognize end of file and the marker
0xFFFFFFFF as end of medium. Only the TMSCP tape simulator
@ -151,13 +220,11 @@ currently available only for Windows, Linux, NetBSD, and OpenBSD.
- The error handling in simulated magtapes was overhauled to be
consistent through all simulators.
1.11 Simulated DECtapes
3.11 Simulated DECtapes
- Added support for RT11 image file format (256 x 16b) to DECtapes.
2. Release Notes
2.1 Bugs Fixed
4. Bugs Fixed in 2.10 vs prior releases
- TS11/TSV05 was not simulating the XS0_MOT bit, causing failures
under VMS. In addition, two of the CTL options were coded
@ -176,18 +243,23 @@ currently available only for Windows, Linux, NetBSD, and OpenBSD.
- PDP-1 typewriter is half duplex, with only one shift state for
both input and output (found by Derek Peschel)
2.2 HP 2100 Debugging
5. General Notes
- The HP 2100 CPU nows runs all of the CPU diagnostics.
- The peripherals run most of the peripheral diagnostics. There
is still a problem in overlapped seek operation on the disks.
See the file hp2100_diag.txt for details.
WARNING: V2.10 has reorganized and renamed some of the definition
files for the PDP-10, PDP-11, and VAX. Be sure to delete all
previous source files before you unpack the Zip archive, or
unpack it into a new directory structure.
3. In Progress
WARNING: V2.10 has a new, more comprehensive save file format.
Restoring save files from previous releases will cause 'invalid
register' errors and loss of CPU option flags, device enable/
disable flags, unit online/offline flags, and unit writelock
flags.
These simulators are not finished and are available in a separate
Zip archive distribution.
WARNING: If you are using Visual Studio .NET through the IDE,
be sure to turn off the /Wp64 flag in the project settings, or
dozens of spurious errors will be generated.
- Interdata 16b/32b: coded, partially tested. See the file
id_diag.txt for details.
- SDS 940: coded, partially tested.
WARNING: Compiling Ethernet support under Windows requires
extra steps; see the Ethernet readme file. Ethernet support is
currently available only for Windows, Linux, NetBSD, and OpenBSD.

View file

@ -2,6 +2,16 @@ This file contains information about the XQ/SIM_ETHER package.
-------------------------------------------------------------------------------
16-Jan-03 Release:
1. Added VMScluster support (thanks to Mark Pizzolato)
2. Verified VAX remote boot functionality (>>>B XQA0)
3. Added major performance enhancements (thanks to Mark Pizzolato again)
4. Changed _DEBUG tracers to XQ_DEBUG and ETH_DEBUG
5. Added local packet processing
6. Added system id broadcast
-------------------------------------------------------------------------------
GOLD Changes: (08-Nov-02)
1. Added USE_NETWORK conditional to Sim_Ether
2. Fixed behaviour of SHOW XQ ETH if no devices exist
@ -68,19 +78,18 @@ supports Windows, Linux, and NetBSD.
Currently, the Sim_Ether module sets the selected ethernet card into
promiscuous mode to gather all packets, then filters out the packets that it
doesn't want. This method is somewhat inefficient and will be looked at in
future versions. Packets having the same source MAC address as the
doesn't want. In Windows, Packets having the same source MAC address as the
controller are ignored for WinPCAP compatibility (see Windows notes below).
If your ethernet card is plugged into a switch, the promiscuous mode setting
should not cause much of a problem, since the switch will still filter out
most of the undesirable traffic. You will only see "excessive" traffic if you
are on a hub(repeater) or a direct lan (thickwire/thinwire) segment.
are on a direct or hub(repeater) segment.
-------------------------------------------------------------------------------
Windows notes:
1. The Windows-specific code uses the WinPCAP 3.0 package from
1. The Windows-specific code uses the WinPCAP 3.0 (or 2.3) package from
http://winpcap.polito.it. This package for windows simulates the libpcap
package that is freely available for unix systems.
2. You must *install* WinPCAP.
@ -91,8 +100,9 @@ Windows notes:
but this defeats DECNET's duplicate node number detection scheme. A more
correct fix for WinPCAP will be explored as time allows.
5. The first time the WinPCAP driver is used, it will be dynamically loaded,
and the user must be an Administrator on the machine to do so. See the
WinPCAP documentation for a static load workaround if needed.
and the user must be an Administrator on the machine to do so. If you need
to run as an unprivileged user, you must set the service to autostart. See
the WinPCAP documentation for details on the static load workaround.
Building on Windows:
1. Install WinPCAP 3.0.
@ -109,8 +119,10 @@ Building on Windows:
Linux, NetBSD, and OpenBSD notes:
1. You must run SIMH(scp) as root so that the ethernet card can be set into
promiscuous mode by the driver.
promiscuous mode by the driver. Alternative suggestions will be welcomed.
Building on Linux, NetBSD, and OpenBSD:
1. Define USE_NETWORK if you want the network functionality.
-------------------------------------------------------------------------------
@ -136,28 +148,25 @@ Regression test criteria:
15. LAT loads sucessfully (passed)
16. SET HOST/LAT <nodename> works from SIMH to real VAX LAT machine (passed)
17. SET HOST/LAT <nodename> works from real VAX LAT machine to SIMH (passed)
18. SIMH node joins VMSCluster (passed)
19. SIMH node mounts other VMSCluster disks (passed)
20. SIMH node MSCP serves disks to other nodes (passed)
21. SIMH node remote boots into VMScluster (>>>B XQAO) (passed)
I have NOT tested the following, but have reports that the following work:
1. Operation with the PDP-11 emulator (RSX)
2. Remote booting of NetBSD (via >>> B XQA0)
I have tested the following, and they do NOT work correctly:
1. VMS NI Clustering (LAVC)
2. Remote VAX booting (>>>B XQA0) into a VMScluster;
the remote boot works, but VMS BUGCHECKs when joining the cluster
The following are known to NOT work:
1. PDP-11 using RSTS/E v10.1 (fails to enable device - needs bootrom support)
I have reports that the following work:
1. PDP-11 using RSX
2. VAX remote booting of NetBSD (via >>> B XQA0)
-------------------------------------------------------------------------------
Things planned for future releases:
1. Loopback packet processing
2. Full MOP implementation
3. Identity broadcast, which should occur every 8-10 minutes
4. Full support for network boot (>> B XQA0)
5. VMS NI Cluster (LAVC) support
6. More efficient Sim_Ether module implementation for windows
7. PDP-11 bootstrap
8. DESQA support (if someone can get me the user manuals)
9. DETQA support [DELQA-Turbo] (I have the manual)
1. Full MOP implementation
2. PDP-11 bootstrap/bootrom
3. DESQA support (if someone can get me the user manuals)
4. DETQA support [DELQA-Turbo] (I have the manual)
-------------------------------------------------------------------------------
@ -166,16 +175,13 @@ Things which I need help with:
2. Information about Remote MOP processing
3. PDP-11 bootstrap code.
4. VAX hardware diagnotics image file and docs, to test XQ thoroughly.
5. Feedback on the ethernet timing clock interval.
6. Feedback on operation with other VAX OS's.
7. Feedback on operation of PDP-11 OS's.
5. Feedback on operation with other VAX OS's.
6. Feedback on operation with PDP-11 OS's.
-------------------------------------------------------------------------------
Please send all patches, questions, feedback, clarifications, and help to:
dhittner AT northropgrumman DOT com
NOTE: I _have_ corrected my email address!! Sorry about the confusion!
Thanks, and Enjoy!!
Dave

View file

@ -93,10 +93,10 @@ int32 sio0s (int32 port, int32 io, int32 data);
int32 sio1d (int32 port, int32 io, int32 data);
int32 sio1s (int32 port, int32 io, int32 data);
void reset_sio_terminals(int32 useDefault);
t_stat simh_dev_reset(void);
t_stat simh_dev_reset(DEVICE *dptr);
t_stat simh_svc(UNIT *uptr);
t_stat simh_dev_set_timeron(void);
t_stat simh_dev_set_timeroff(void);
t_stat simh_dev_set_timeron(UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat simh_dev_set_timeroff(UNIT *uptr, int32 val, char *cptr, void *desc);
int32 simh_in(void);
int32 simh_out(int32 data);
void attachCPM(UNIT *uptr);
@ -641,7 +641,7 @@ struct tm *currentTime = NULL;
uint32 markTime[splimit];
char version[] = "SIMH002";
t_stat simh_dev_reset(void) {
t_stat simh_dev_reset(DEVICE *dptr) {
currentTime = NULL;
ClockZSDOSDelta = 0;
setClockZSDOSPos = 0;
@ -658,12 +658,12 @@ t_stat simh_dev_reset(void) {
lastCPMStatus = SCPE_OK;
timerInterrupt = FALSE;
if (simh_unit.flags & UNIT_SIMH_TIMERON) {
simh_dev_set_timeron();
simh_dev_set_timeron(NULL, 0, NULL, NULL);
}
return SCPE_OK;
}
t_stat simh_dev_set_timeron(void) {
t_stat simh_dev_set_timeron(UNIT *uptr, int32 val, char *cptr, void *desc) {
if (rtc_avail) {
timeOfNextInterrupt = sim_os_msec() + timerDelta;
return sim_activate(&simh_unit, simh_unit.wait); /* activate unit */
@ -674,7 +674,7 @@ t_stat simh_dev_set_timeron(void) {
}
}
t_stat simh_dev_set_timeroff(void) {
t_stat simh_dev_set_timeroff(UNIT *uptr, int32 val, char *cptr, void *desc) {
timerInterrupt = FALSE;
sim_cancel(&simh_unit);
return SCPE_OK;
@ -997,14 +997,14 @@ int32 simh_out(int32 data) {
cpu_unit.flags &= ~UNIT_CHIP;
break;
case startTimerInterruptsCmd:
if (simh_dev_set_timeron() == SCPE_OK) {
if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) {
timerInterrupt = FALSE;
simh_unit.flags |= UNIT_SIMH_TIMERON;
}
break;
case stopTimerInterruptsCmd:
simh_unit.flags &= ~UNIT_SIMH_TIMERON;
simh_dev_set_timeroff();
simh_dev_set_timeroff(NULL, 0, NULL, NULL);
break;
case setTimerDeltaCmd:
setTimerDeltaPos = 0;

View file

@ -395,10 +395,10 @@ else if ((dev_done & (INT_PENDING | ISR)) > (INT_PENDING)) { /* intr? */
int32 i, vec;
t = dev_done & ISR; /* find hi pri */
for (i = 15; i >= 0; i--) {
if ((t >> i) & 1) break; }
if ((t >> i) & 1) break; }
if ((i < 0) || ((vec = vec_map[i]) < 0)) { /* undefined? */
reason = STOP_ILLINT; /* stop */
break; }
reason = STOP_ILLINT; /* stop */
break; }
dev_done = dev_done & ~INT_ON; /* int off */
M[vec] = SC; /* save SC */
SC = vec + 1; /* new SC */
@ -433,39 +433,39 @@ else if ((src != U_MEM) && (dst == U_TRP)) { /* cond jump */
t = dev_tab[src].Src (src); /* get source */
switch (op >> 1) { /* case on jump */
case 00: /* never */
jmp = 0;
break;
jmp = 0;
break;
case 01: /* always */
jmp = 1;
break;
jmp = 1;
break;
case 02: /* src == 0 */
jmp = (t == 0);
break;
jmp = (t == 0);
break;
case 03: /* src != 0 */
jmp = (t != 0);
break;
jmp = (t != 0);
break;
case 04: /* src < 0 */
jmp = (t >= SIGN);
break;
jmp = (t >= SIGN);
break;
case 05: /* src >= 0 */
jmp = (t < SIGN);
break;
case 06:
jmp = (t == 0) || (t & SIGN); /* src <= 0 */
break;
case 07:
jmp = (t != 0) && !(t & SIGN); /* src > 0 */
break; }
jmp = (t < SIGN);
break;
case 06: /* src <= 0 */
jmp = (t == 0) || (t & SIGN);
break;
case 07: /* src > 0 */
jmp = (t != 0) && !(t & SIGN);
break; }
if (jmp) { /* jump taken? */
SCQ_ENTRY; /* save SC */
SC = (SC + 1) & AMASK; /* incr SC once */
MA = M[SC]; /* get jump addr */
if (op & TRP_DEF) { /* defer? */
t = (M[MA] + 1) & DMASK; /* autoinc */
if (MEM_ADDR_OK (MA)) M[MA] = t;
MA = t & AMASK; } /* ind addr */
TRP = SC; /* save SC */
SC = MA; } /* load new SC */
SCQ_ENTRY; /* save SC */
SC = (SC + 1) & AMASK; /* incr SC once */
MA = M[SC]; /* get jump addr */
if (op & TRP_DEF) { /* defer? */
t = (M[MA] + 1) & DMASK; /* autoinc */
if (MEM_ADDR_OK (MA)) M[MA] = t;
MA = t & AMASK; } /* ind addr */
TRP = SC; /* save SC */
SC = MA; } /* load new SC */
else SC = (SC + 2) & AMASK; } /* incr SC twice */
else if ((src != U_MEM) && (dst != U_MEM)) { /* reg-reg? */
@ -481,31 +481,31 @@ else if ((src != U_MEM) && (dst != U_MEM)) { /* reg-reg? */
else { SC = (SC + 1) & AMASK; /* incr SC */
switch (op & MEM_MOD) { /* case on addr mode */
case MEM_DIR: /* direct */
MA = M[SC] & AMASK; /* get address */
SC = (SC + 1) & AMASK; /* incr SC again */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
break;
MA = M[SC] & AMASK; /* get address */
SC = (SC + 1) & AMASK; /* incr SC again */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
break;
case MEM_DEF: /* defer */
MA = M[SC] & AMASK; /* get ind addr */
SC = (SC + 1) & AMASK; /* incr SC again */
t = (M[MA] + 1) & DMASK; /* autoinc */
if (MEM_ADDR_OK (MA)) M[MA] = t;
MA = t & AMASK; /* ind addr */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
break;
MA = M[SC] & AMASK; /* get ind addr */
SC = (SC + 1) & AMASK; /* incr SC again */
t = (M[MA] + 1) & DMASK; /* autoinc */
if (MEM_ADDR_OK (MA)) M[MA] = t;
MA = t & AMASK; /* ind addr */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
break;
case MEM_IMM: /* immediate */
MA = SC; /* eff addr */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
SC = (SC + 1) & AMASK; /* incr SC again */
break;
MA = SC; /* eff addr */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
SC = (SC + 1) & AMASK; /* incr SC again */
break;
case MEM_IDF: /* immediate defer */
MA = SC; /* get ind addr */
t = (M[MA] + 1) & DMASK; /* autoinc */
if (MEM_ADDR_OK (MA)) M[MA] = t;
MA = t & AMASK; /* ind addr */
SC = (SC + 1) & AMASK; /* incr SC again */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
break; } /* end switch */
MA = SC; /* get ind addr */
t = (M[MA] + 1) & DMASK; /* autoinc */
if (MEM_ADDR_OK (MA)) M[MA] = t;
MA = t & AMASK; /* ind addr */
SC = (SC + 1) & AMASK; /* incr SC again */
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
break; } /* end switch */
} /* end mem ref */
} /* end while */
@ -775,9 +775,9 @@ if (op == EAO_MUL) { /* mul? */
GR[0] = t & DMASK; }
if (op == EAO_DIV) { /* div? */
if (AY && (AX < AY)) {
t = (AX << 16) | GR[0]; /* AX'GR1 / AY */
GR[0] = t / AY; /* quo to GR1 */
AX = t % AY; } /* rem to AX */
t = (AX << 16) | GR[0]; /* AX'GR1 / AY */
GR[0] = t / AY; /* quo to GR1 */
AX = t % AY; } /* rem to AX */
}
return SCPE_OK;
}

View file

@ -29,6 +29,7 @@
hsp S42-006 high speed punch
rtc real time clock
22-Dec-02 RMS Added break support
01-Nov-02 RMS Added 7b/8B support to terminal
*/
@ -228,7 +229,8 @@ int32 c;
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
if (tti_unit.flags & UNIT_KSR) { /* KSR? */
if (c & SCPE_BREAK) tti_unit.buf = 0; /* break? */
else if (tti_unit.flags & UNIT_KSR) { /* KSR? */
c = c & 0177; /* force 7b */
if (islower (c)) c = toupper (c); /* cvt to UC */
tti_unit.buf = c | 0200; } /* add TTY bit */
@ -316,8 +318,8 @@ if ((hsr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (hsr_stopioe, SCPE_UNATT);
if ((temp = getc (hsr_unit.fileref)) == EOF) { /* read char */
if (feof (hsr_unit.fileref)) { /* err or eof? */
if (hsr_stopioe) printf ("HSR end of file\n");
else return SCPE_OK; }
if (hsr_stopioe) printf ("HSR end of file\n");
else return SCPE_OK; }
else perror ("HSR I/O error");
clearerr (hsr_unit.fileref);
return SCPE_IOERR; }
@ -388,4 +390,4 @@ t_stat rtc_reset (DEVICE *dhsr)
dev_done = dev_done & ~INT_RTC; /* clear ready */
sim_cancel (&rtc_unit); /* stop clock */
return SCPE_OK;
}
}

View file

@ -96,17 +96,17 @@ for (;;) { /* until EOF */
if (c == EOF) break; /* EOF? done */
for ( ; c != 0; ) { /* loop until ctl = 0 */
/* ign ctrl frame */
if ((c = getc (fileref)) == EOF) /* get high byte */
return SCPE_FMT; /* EOF is error */
if (!MEM_ADDR_OK (org)) return SCPE_NXM;
M[org] = ((c & 0377) << 8); /* store high */
if ((c = getc (fileref)) == EOF) /* get low byte */
return SCPE_FMT; /* EOF is error */
M[org] = M[org] | (c & 0377); /* store low */
org = org + 1; /* incr origin */
if ((c = getc (fileref)) == EOF) /* get ctrl frame */
return SCPE_OK; /* EOF is ok */
} /* end block for */
if ((c = getc (fileref)) == EOF) /* get high byte */
return SCPE_FMT; /* EOF is error */
if (!MEM_ADDR_OK (org)) return SCPE_NXM;
M[org] = ((c & 0377) << 8); /* store high */
if ((c = getc (fileref)) == EOF) /* get low byte */
return SCPE_FMT; /* EOF is error */
M[org] = M[org] | (c & 0377); /* store low */
org = org + 1; /* incr origin */
if ((c = getc (fileref)) == EOF) /* get ctrl frame */
return SCPE_OK; /* EOF is ok */
} /* end block for */
if (!(sim_switches & SWMASK ('C'))) return SCPE_OK;
} /* end tape for */
return SCPE_OK;
@ -275,10 +275,10 @@ int32 i, nfirst;
for (i = nfirst = 0; fname[i] != NULL; i++) {
if (((inst & fop[i].imask) == fop[i].inst) &&
((op & fop[i].omask) == fop[i].oper)) {
op = op & ~fop[i].omask;
if (nfirst) fputc (' ', of);
nfirst = 1;
fprintf (of, "%s", fname[i]); }
op = op & ~fop[i].omask;
if (nfirst) fputc (' ', of);
nfirst = 1;
fprintf (of, "%s", fname[i]); }
}
if (op) fprintf (of, " %o", op);
return;
@ -328,64 +328,65 @@ for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */
switch (j) { /* case on class */
case F_V_FO: /* func out */
fprintf (of, "%s ", opcode[i]);
fprint_op (of, inst, op);
fprintf (of, ",%s", undst[dst]);
break;
fprintf (of, "%s ", opcode[i]);
fprint_op (of, inst, op);
fprintf (of, ",%s", undst[dst]);
break;
case F_V_FOI: /* func out impl */
fprintf (of, "%s ", opcode[i]);
fprint_op (of, inst, op);
break;
fprintf (of, "%s ", opcode[i]);
fprint_op (of, inst, op);
break;
case F_V_SF: /* skip func */
fprintf (of, "%s %s,", opcode[i], unsrc[src]);
fprint_op (of, inst, op);
break;
fprintf (of, "%s %s,", opcode[i], unsrc[src]);
fprint_op (of, inst, op);
break;
case F_V_SFI: /* skip func impl */
fprintf (of, "%s ", opcode[i]);
fprint_op (of, inst, op);
break;
fprintf (of, "%s ", opcode[i]);
fprint_op (of, inst, op);
break;
case F_V_RR: /* reg reg */
if (strcmp (unsrc[src], undst[dst]) == 0) {
if (bop) fprintf (of, "%s %s,%s", opcode[i + 2],
unsrc[src], opname[bop]);
else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]); }
else { if (bop) fprintf (of, "%s %s,%s,%s", opcode[i],
unsrc[src], opname[bop], undst[dst]);
else fprintf (of, "%s %s,%s", opcode[i],
unsrc[src], undst[dst]); }
break;
if (strcmp (unsrc[src], undst[dst]) == 0) {
if (bop) fprintf (of, "%s %s,%s", opcode[i + 2],
unsrc[src], opname[bop]);
else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]); }
else {
if (bop) fprintf (of, "%s %s,%s,%s", opcode[i],
unsrc[src], opname[bop], undst[dst]);
else fprintf (of, "%s %s,%s", opcode[i],
unsrc[src], undst[dst]); }
break;
case F_V_ZR: /* zero reg */
if (bop) fprintf (of, "%s %s,%s", opcode[i],
opname[bop], undst[dst]);
else fprintf (of, "%s %s", opcode[i], undst[dst]);
break;
if (bop) fprintf (of, "%s %s,%s", opcode[i],
opname[bop], undst[dst]);
else fprintf (of, "%s %s", opcode[i], undst[dst]);
break;
case F_V_JC: /* jump cond */
fprintf (of, "%s %s,%s,%o", opcode[i],
unsrc[src], cdname[op >> 1], val[1]);
break;
fprintf (of, "%s %s,%s,%o", opcode[i],
unsrc[src], cdname[op >> 1], val[1]);
break;
case F_V_JU: /* jump uncond */
fprintf (of, "%s %o", opcode[i], val[1]);
break;
fprintf (of, "%s %o", opcode[i], val[1]);
break;
case F_V_RM: /* reg mem */
if (bop) fprintf (of, "%s %s,%s,%o", opcode[i],
unsrc[src], opname[bop], val[1]);
else fprintf (of, "%s %s,%o", opcode[i], unsrc[src], val[1]);
break;
if (bop) fprintf (of, "%s %s,%s,%o", opcode[i],
unsrc[src], opname[bop], val[1]);
else fprintf (of, "%s %s,%o", opcode[i], unsrc[src], val[1]);
break;
case F_V_ZM: /* zero mem */
if (bop) fprintf (of, "%s %s,%o", opcode[i],
opname[bop], val[1]);
else fprintf (of, "%s %o", opcode[i], val[1]);
break;
if (bop) fprintf (of, "%s %s,%o", opcode[i],
opname[bop], val[1]);
else fprintf (of, "%s %o", opcode[i], val[1]);
break;
case F_V_MR: /* mem reg */
if (bop) fprintf (of, "%s %o,%s,%s", opcode[i],
val[1], opname[bop], undst[dst]);
else fprintf (of, "%s %o,%s", opcode[i], val[1], undst[dst]);
break;
if (bop) fprintf (of, "%s %o,%s,%s", opcode[i],
val[1], opname[bop], undst[dst]);
else fprintf (of, "%s %o,%s", opcode[i], val[1], undst[dst]);
break;
case F_V_MS: /* mem self */
if (bop) fprintf (of, "%s %o,%s", opcode[i],
val[1], opname[bop]);
else fprintf (of, "%s %o", opcode[i], val[1]);
break; } /* end case */
if (bop) fprintf (of, "%s %o,%s", opcode[i],
val[1], opname[bop]);
else fprintf (of, "%s %o", opcode[i], val[1]);
break; } /* end case */
return (j >= F_2WD)? -1: SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
@ -409,22 +410,22 @@ uint32 inst = val[0];
uint32 fncv = 0, fncm = 0;
while (*cptr) {
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
d = get_uint (gbuf, 8, 017, &r); /* octal? */
if (r == SCPE_OK) { /* ok? */
if (d & fncm) return NULL; /* already filled? */
fncv = fncv | d; /* save */
fncm = fncm | d; } /* field filled */
else { /* symbol? */
for (i = 0; fname[i] != NULL; i++) { /* search table */
if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */
((inst & fop[i].imask) == fop[i].inst)) {
if (fop[i].oper & fncm) return NULL; /* already filled? */
fncm = fncm | fop[i].omask;
fncv = fncv | fop[i].oper;
break; } }
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
d = get_uint (gbuf, 8, 017, &r); /* octal? */
if (r == SCPE_OK) { /* ok? */
if (d & fncm) return NULL; /* already filled? */
fncv = fncv | d; /* save */
fncm = fncm | d; } /* field filled */
else { /* symbol? */
for (i = 0; fname[i] != NULL; i++) { /* search table */
if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */
((inst & fop[i].imask) == fop[i].inst)) {
if (fop[i].oper & fncm) return NULL;/* already filled? */
fncm = fncm | fop[i].omask;
fncv = fncv | fop[i].oper;
break; } }
if (fname[i] == NULL) return NULL; } /* end else */
} /* end while */
} /* end while */
val[0] = val[0] | (fncv << I_V_OP); /* store fnc */
return cptr;
}
@ -467,8 +468,8 @@ int32 i;
tptr = get_glyph (cptr, gbuf, term); /* get glyph */
for (i = 1; i < 4; i++) { /* symbol match? */
if (strcmp (gbuf, opname[i]) == 0) {
val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */
return tptr; } }
val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */
return tptr; } }
return cptr; /* original ptr */
}
@ -549,7 +550,7 @@ case F_V_JC: /* jump cond */
if (!cptr) return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, ','); /* cond */
for (k = 0; k < 8; k++) { /* symbol? */
if (strcmp (gbuf, cdname[k]) == 0) break; }
if (strcmp (gbuf, cdname[k]) == 0) break; }
if (k >= 8) return SCPE_ARG;
val[0] = val[0] | (k << (I_V_OP + 1)); /* or to inst */
case F_V_JU: /* jump uncond */

View file

@ -371,8 +371,8 @@ if ((dev_ready & (INT_PENDING | dev_enable)) > INT_PENDING) { /* int req? */
else { if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
reason = STOP_IBKPT; /* stop simulation */
break; }
Y = PC; /* set mem addr */
MB = Read (Y); /* fetch instr */
PC = NEWA (Y, Y + 1); /* incr PC */
@ -394,19 +394,19 @@ case 001: case 021: case 041: case 061: /* JMP */
PCQ_ENTRY; /* save PC */
PC = NEWA (PC, Y); /* set new PC */
if (dlog && sim_log) { /* logging? */
int32 op = I_GETOP (M[PC]) & 017; /* get target */
if ((op == 014) && (PC == (PCQ_TOP - 2))) { /* jmp .-1 to IO? */
turnoff = 1; /* yes, stop */
fprintf (sim_log, "Idle loop detected\n"); }
else turnoff = 0; } /* no, log */
int32 op = I_GETOP (M[PC]) & 017; /* get target */
if ((op == 014) && (PC == (PCQ_TOP - 2))) { /* jmp .-1 to IO? */
turnoff = 1; /* yes, stop */
fprintf (sim_log, "Idle loop detected\n"); }
else turnoff = 0; } /* no, log */
if (extoff_pending) ext = extoff_pending = 0; /* cond ext off */
break;
case 002: case 022: case 042: case 062: /* LDA */
if (reason = Ea (MB, &Y)) break; /* eff addr */
if (dp) { /* double prec? */
AR = Read (Y & ~1); /* get doubleword */
BR = Read (Y | 1);
sc = 0; }
AR = Read (Y & ~1); /* get doubleword */
BR = Read (Y | 1);
sc = 0; }
else AR = Read (Y); /* no, get word */
break;
case 003: case 023: case 043: case 063: /* ANA */
@ -416,9 +416,9 @@ case 003: case 023: case 043: case 063: /* ANA */
case 004: case 024: case 044: case 064: /* STA */
if (reason = Ea (MB, &Y)) break; /* eff addr */
if (dp) { /* double prec? */
if ((Y & 1) == 0) Write (AR, Y); /* if even, store A */
Write (BR, Y | 1); /* store B */
sc = 0; }
if ((Y & 1) == 0) Write (AR, Y); /* if even, store A */
Write (BR, Y | 1); /* store B */
sc = 0; }
else Write (AR, Y); /* no, store word */
break;
case 005: case 025: case 045: case 065: /* ERA */
@ -428,21 +428,21 @@ case 005: case 025: case 045: case 065: /* ERA */
case 006: case 026: case 046: case 066: /* ADD */
if (reason = Ea (MB, &Y)) break; /* eff addr */
if (dp) { /* double prec? */
t1 = GETDBL_S (AR, BR); /* get A'B */
t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1));
t1 = Add31 (t1, t2); /* 31b add */
PUTDBL_S (t1);
sc = 0; }
t1 = GETDBL_S (AR, BR); /* get A'B */
t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1));
t1 = Add31 (t1, t2); /* 31b add */
PUTDBL_S (t1);
sc = 0; }
else AR = Add16 (AR, Read (Y)); /* no, 16b add */
break;
case 007: case 027: case 047: case 067: /* SUB */
if (reason = Ea (MB, &Y)) break; /* eff addr */
if (dp) { /* double prec? */
t1 = GETDBL_S (AR, BR); /* get A'B */
t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1));
t1 = Add31 (t1, -t2); /* 31b sub */
PUTDBL_S (t1);
sc = 0; }
t1 = GETDBL_S (AR, BR); /* get A'B */
t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1));
t1 = Add31 (t1, -t2); /* 31b sub */
PUTDBL_S (t1);
sc = 0; }
else AR = Add16 (AR, (-Read (Y)) & DMASK); /* no, 16b sub */
break;
@ -483,25 +483,25 @@ case 035: case 075: /* LDX */
break;
case 016: case 036: case 056: case 076: /* MPY */
if (cpu_unit.flags & UNIT_HSA) { /* installed? */
if (reason = Ea (MB, &Y)) break; /* eff addr */
t1 = SEXT (AR) * SEXT (Read (Y));
PUTDBL_S (t1);
sc = 0; }
if (reason = Ea (MB, &Y)) break; /* eff addr */
t1 = SEXT (AR) * SEXT (Read (Y));
PUTDBL_S (t1);
sc = 0; }
else reason = stop_inst;
break;
case 017: case 037: case 057: case 077: /* DIV */
if (cpu_unit.flags & UNIT_HSA) { /* installed? */
if (reason = Ea (MB, &Y)) break; /* eff addr */
t2 = SEXT (Read (Y)); /* divr */
if (t2) { /* divr != 0? */
t1 = GETDBL_S (AR, BR); /* get A'B */
BR = (t1 % t2) & DMASK; /* remainder */
t1 = t1 / t2; /* quotient */
AR = t1 & DMASK;
if ((t1 > MMASK) || (t1 < (-SIGN))) C = 1;
else C = 0;
sc = 0; }
else C = 1; }
if (reason = Ea (MB, &Y)) break; /* eff addr */
t2 = SEXT (Read (Y)); /* divr */
if (t2) { /* divr != 0? */
t1 = GETDBL_S (AR, BR); /* get A'B */
BR = (t1 % t2) & DMASK; /* remainder */
t1 = t1 / t2; /* quotient */
AR = t1 & DMASK;
if ((t1 > MMASK) || (t1 < (-SIGN))) C = 1;
else C = 0;
sc = 0; }
else C = 1; }
else reason = stop_inst;
break;
@ -516,67 +516,67 @@ case 034: /* SKS */
t2 = iotab[MB & DEVMASK] (ioSKS, I_GETFNC (MB), AR);
reason = t2 >> IOT_V_REASON;
if (t2 & IOT_SKIP) { /* skip? */
PC = NEWA (PC, PC + 1);
turnoff = 0; }
PC = NEWA (PC, PC + 1);
turnoff = 0; }
break;
case 054: /* INA */
if (MB & INCLRA) AR = 0;
t2 = iotab[MB & DEVMASK] (ioINA, I_GETFNC (MB), AR);
reason = t2 >> IOT_V_REASON;
if (t2 & IOT_SKIP) { /* skip? */
PC = NEWA (PC, PC + 1);
turnoff = 0; }
PC = NEWA (PC, PC + 1);
turnoff = 0; }
AR = t2 & DMASK; /* data */
break;
case 074: /* OTA */
t2 = iotab[MB & DEVMASK] (ioOTA, I_GETFNC (MB), AR);
reason = t2 >> IOT_V_REASON;
if (t2 & IOT_SKIP) { /* skip? */
PC = NEWA (PC, PC + 1);
turnoff = 0; }
PC = NEWA (PC, PC + 1);
turnoff = 0; }
break;
/* Control */
case 000:
if ((MB & 1) == 0) { /* HLT */
reason = STOP_HALT;
break; }
reason = STOP_HALT;
break; }
if (MB & m14) { /* SGL, DBL */
if (cpu_unit.flags & UNIT_HSA) dp = (MB & m15)? 1: 0;
else reason = stop_inst; }
if (cpu_unit.flags & UNIT_HSA) dp = (MB & m15)? 1: 0;
else reason = stop_inst; }
if (MB & m13) { /* DXA, EXA */
if (!(cpu_unit.flags & UNIT_EXT)) reason = stop_inst;
else if (MB & m15) { /* EXA */
ext = 1;
extoff_pending = 0; } /* DXA */
else extoff_pending = 1; }
if (!(cpu_unit.flags & UNIT_EXT)) reason = stop_inst;
else if (MB & m15) { /* EXA */
ext = 1;
extoff_pending = 0; } /* DXA */
else extoff_pending = 1; }
if (MB & m12) /* RMP */
dev_ready = dev_ready & ~INT_MPE;
dev_ready = dev_ready & ~INT_MPE;
if (MB & m11) { /* SCA, INK */
if (MB & m15) /* INK */
AR = (C << 15) | (dp << 14) | (pme << 13) | (sc & 037);
else if (cpu_unit.flags & UNIT_HSA) /* SCA */
AR = sc & 037;
else reason = stop_inst; }
if (MB & m15) /* INK */
AR = (C << 15) | (dp << 14) | (pme << 13) | (sc & 037);
else if (cpu_unit.flags & UNIT_HSA) /* SCA */
AR = sc & 037;
else reason = stop_inst; }
else if (MB & m10) { /* NRM */
if (cpu_unit.flags & UNIT_HSA) {
for (sc = 0;
(sc <= 32) && ((AR & SIGN) != ((AR << 1) & SIGN));
sc++) {
AR = (AR & SIGN) | ((AR << 1) & MMASK) |
((BR >> 14) & 1);
BR = (BR & SIGN) | ((BR << 1) & MMASK); }
sc = sc & 037; }
else reason = stop_inst; }
if (cpu_unit.flags & UNIT_HSA) {
for (sc = 0;
(sc <= 32) && ((AR & SIGN) != ((AR << 1) & SIGN));
sc++) {
AR = (AR & SIGN) | ((AR << 1) & MMASK) |
((BR >> 14) & 1);
BR = (BR & SIGN) | ((BR << 1) & MMASK); }
sc = sc & 037; }
else reason = stop_inst; }
else if (MB & m9) { /* IAB */
sc = BR;
BR = AR;
AR = sc; }
sc = BR;
BR = AR;
AR = sc; }
if (MB & m8) /* ENB */
dev_ready = (dev_ready | INT_ON) & ~INT_NODEF;
dev_ready = (dev_ready | INT_ON) & ~INT_NODEF;
if (MB & m7) /* INH */
dev_ready = dev_ready & ~INT_ON;
dev_ready = dev_ready & ~INT_ON;
break;
/* Shift
@ -607,112 +607,116 @@ case 020:
if ((t1 = (-MB) & SHFMASK) == 0) break; /* shift count */
switch (I_GETFNC (MB)) { /* case shift fnc */
case 000: /* LRL */
if (t1 > 32) ut = 0; /* >32? all 0 */
else { ut = GETDBL_U (AR, BR); /* get A'B */
C = (ut >> (t1 - 1)) & 1; /* C = last out */
ut = ut >> t1; } /* log right */
PUTDBL_U (ut); /* store A,B */
break;
if (t1 > 32) ut = 0; /* >32? all 0 */
else {
ut = GETDBL_U (AR, BR); /* get A'B */
C = (ut >> (t1 - 1)) & 1; /* C = last out */
ut = ut >> t1; } /* log right */
PUTDBL_U (ut); /* store A,B */
break;
case 001: /* LRS */
if (t1 > 31) t1 = 31; /* limit to 31 */
t2 = GETDBL_S (SEXT (AR), BR); /* get A'B signed */
C = (t2 >> (t1 - 1)) & 1; /* C = last out */
t2 = t2 >> t1; /* arith right */
PUTDBL_S (t2); /* store A,B */
break;
if (t1 > 31) t1 = 31; /* limit to 31 */
t2 = GETDBL_S (SEXT (AR), BR); /* get A'B signed */
C = (t2 >> (t1 - 1)) & 1; /* C = last out */
t2 = t2 >> t1; /* arith right */
PUTDBL_S (t2); /* store A,B */
break;
case 002: /* LRR */
t2 = t1 % 32; /* mod 32 */
ut = GETDBL_U (AR, BR); /* get A'B */
ut = (ut >> t2) | (ut << (32 - t2)); /* rot right */
C = (ut >> 31) & 1; /* C = A<1> */
PUTDBL_U (ut); /* store A,B */
break;
t2 = t1 % 32; /* mod 32 */
ut = GETDBL_U (AR, BR); /* get A'B */
ut = (ut >> t2) | (ut << (32 - t2)); /* rot right */
C = (ut >> 31) & 1; /* C = A<1> */
PUTDBL_U (ut); /* store A,B */
break;
case 003: /* "long right arot" */
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
C = BR & 1; /* C = last out */
BR = (BR & SIGN) | ((AR & 1) << 14) |
((BR & MMASK) >> 1);
AR = ((AR & SIGN) | (C << 15)) | (AR >> 1); }
break;
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
C = BR & 1; /* C = last out */
BR = (BR & SIGN) | ((AR & 1) << 14) |
((BR & MMASK) >> 1);
AR = ((AR & SIGN) | (C << 15)) | (AR >> 1); }
break;
case 004: /* LGR */
if (t1 > 16) AR = 0; /* > 16? all 0 */
else { C = (AR >> (t1 - 1)) & 1; /* C = last out */
AR = (AR >> t1) & DMASK; } /* log right */
break;
if (t1 > 16) AR = 0; /* > 16? all 0 */
else {
C = (AR >> (t1 - 1)) & 1; /* C = last out */
AR = (AR >> t1) & DMASK; } /* log right */
break;
case 005: /* ARS */
if (t1 > 16) t1 = 16; /* limit to 16 */
C = ((SEXT (AR)) >> (t1 - 1)) & 1; /* C = last out */
AR = ((SEXT (AR)) >> t1) & DMASK; /* arith right */
break;
if (t1 > 16) t1 = 16; /* limit to 16 */
C = ((SEXT (AR)) >> (t1 - 1)) & 1; /* C = last out */
AR = ((SEXT (AR)) >> t1) & DMASK; /* arith right */
break;
case 006: /* ARR */
t2 = t1 % 16; /* mod 16 */
AR = ((AR >> t2) | (AR << (16 - t2))) & DMASK;
C = (AR >> 15) & 1; /* C = A<1> */
break;
t2 = t1 % 16; /* mod 16 */
AR = ((AR >> t2) | (AR << (16 - t2))) & DMASK;
C = (AR >> 15) & 1; /* C = A<1> */
break;
case 007: /* "short right arot" */
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
C = AR & 1; /* C = last out */
AR = ((AR & SIGN) | (C << 15)) | (AR >> 1); }
break;
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
C = AR & 1; /* C = last out */
AR = ((AR & SIGN) | (C << 15)) | (AR >> 1); }
break;
/* Shift, continued */
case 010: /* LLL */
if (t1 > 32) ut = 0; /* > 32? all 0 */
else { ut = GETDBL_U (AR, BR); /* get A'B */
C = (ut >> (32 - t1)) & 1; /* C = last out */
ut = ut << t1; } /* log left */
PUTDBL_U (ut); /* store A,B */
break;
if (t1 > 32) ut = 0; /* > 32? all 0 */
else {
ut = GETDBL_U (AR, BR); /* get A'B */
C = (ut >> (32 - t1)) & 1; /* C = last out */
ut = ut << t1; } /* log left */
PUTDBL_U (ut); /* store A,B */
break;
case 011: /* LLS */
if (t1 > 31) t1 = 31; /* limit to 31 */
t2 = GETDBL_S (SEXT (AR), BR); /* get A'B */
t3 = t2 << t1; /* "arith" left */
PUTDBL_S (t3); /* store A'B */
if ((t2 >> (31 - t1)) != /* shf out = sgn? */
((AR & SIGN)? -1: 0)) C = 1;
break;
if (t1 > 31) t1 = 31; /* limit to 31 */
t2 = GETDBL_S (SEXT (AR), BR); /* get A'B */
t3 = t2 << t1; /* "arith" left */
PUTDBL_S (t3); /* store A'B */
if ((t2 >> (31 - t1)) != /* shf out = sgn? */
((AR & SIGN)? -1: 0)) C = 1;
break;
case 012: /* LLR */
t2 = t1 % 32; /* mod 32 */
ut = GETDBL_U (AR, BR); /* get A'B */
ut = (ut << t2) | (ut >> (32 - t2)); /* rot left */
C = ut & 1; /* C = B<16> */
PUTDBL_U (ut); /* store A,B */
break;
t2 = t1 % 32; /* mod 32 */
ut = GETDBL_U (AR, BR); /* get A'B */
ut = (ut << t2) | (ut >> (32 - t2)); /* rot left */
C = ut & 1; /* C = B<16> */
PUTDBL_U (ut); /* store A,B */
break;
case 013: /* "long left arot" */
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
AR = (AR << 1) | ((BR >> 14) & 1);
BR = (BR & SIGN) | ((BR << 1) & MMASK) |
((AR >> 16) & 1);
if ((AR & SIGN) != ((AR >> 1) & SIGN)) C = 1;
AR = AR & DMASK; }
break;
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
AR = (AR << 1) | ((BR >> 14) & 1);
BR = (BR & SIGN) | ((BR << 1) & MMASK) |
((AR >> 16) & 1);
if ((AR & SIGN) != ((AR >> 1) & SIGN)) C = 1;
AR = AR & DMASK; }
break;
case 014: /* LGL */
if (t1 > 16) AR = 0; /* > 16? all 0 */
else { C = (AR >> (16 - t1)) & 1; /* C = last out */
AR = (AR << t1) & DMASK; } /* log left */
break;
if (t1 > 16) AR = 0; /* > 16? all 0 */
else {
C = (AR >> (16 - t1)) & 1; /* C = last out */
AR = (AR << t1) & DMASK; } /* log left */
break;
case 015: /* ALS */
if (t1 > 16) t1 = 16; /* limit to 16 */
t2 = SEXT (AR); /* save AR */
AR = (AR << t1) & DMASK; /* "arith" left */
if ((t2 >> (16 - t1)) != /* shf out + sgn */
((AR & SIGN)? -1: 0)) C = 1;
break;
if (t1 > 16) t1 = 16; /* limit to 16 */
t2 = SEXT (AR); /* save AR */
AR = (AR << t1) & DMASK; /* "arith" left */
if ((t2 >> (16 - t1)) != /* shf out + sgn */
((AR & SIGN)? -1: 0)) C = 1;
break;
case 016: /* ALR */
t2 = t1 % 16; /* mod 16 */
AR = ((AR << t2) | (AR >> (16 - t2))) & DMASK;
C = AR & 1; /* C = A<16> */
break;
t2 = t1 % 16; /* mod 16 */
AR = ((AR << t2) | (AR >> (16 - t2))) & DMASK;
C = AR & 1; /* C = A<16> */
break;
case 017: /* "short left arot" */
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
if ((AR & SIGN) != ((AR << 1) & SIGN)) C = 1;
AR = ((AR << 1) | (AR >> 15)) & DMASK; }
break; } /* end case fnc */
if (reason = stop_inst) break; /* stop on undef? */
for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
if ((AR & SIGN) != ((AR << 1) & SIGN)) C = 1;
AR = ((AR << 1) | (AR >> 15)) & DMASK; }
break; } /* end case fnc */
break;
/* Skip */
@ -740,12 +744,12 @@ case 060:
else if (MB == 0140100) AR = AR & ~SIGN; /* SSP */
else if (MB == 0140200) C = 0; /* RCB */
else if (MB == 0140320) { /* CSA */
C = (AR & SIGN) >> 15;
AR = AR & ~SIGN; }
C = (AR & SIGN) >> 15;
AR = AR & ~SIGN; }
else if (MB == 0140401) AR = AR ^ DMASK; /* CMA */
else if (MB == 0140407) { /* TCA */
AR = (-AR) & DMASK;
sc = 0; }
AR = (-AR) & DMASK;
sc = 0; }
else if (MB == 0140500) AR = AR | SIGN; /* SSM */
else if (MB == 0140600) C = 1; /* SCB */
else if (MB == 0141044) AR = AR & 0177400; /* CAR */
@ -755,7 +759,7 @@ case 060:
else if (MB == 0141216) AR = Add16 (AR, C); /* ACA */
else if (MB == 0141240) AR = (AR << 8) & DMASK; /* ICR */
else if (MB == 0141340) /* ICA */
AR = ((AR << 8) | (AR >> 8)) & DMASK;
AR = ((AR << 8) | (AR >> 8)) & DMASK;
else if (reason = stop_inst) break;
else AR = Operate (MB, AR); /* undefined */
break;
@ -792,14 +796,14 @@ int32 Y = IR & (IA | DISP); /* ind + disp */
if (IR & SC) Y = ((PC - 1) & PAGENO) | Y; /* cur sec? + pageno */
if (ext) { /* extend mode? */
for (i = 0; (i < ind_max) && (Y & IA); i++) { /* resolve ind addr */
Y = Read (Y & X_AMASK); } /* get ind addr */
Y = Read (Y & X_AMASK); } /* get ind addr */
if (IR & IDX) Y = Y + XR; /* post-index */
} /* end if ext */
else { /* non-extend */
Y = NEWA (PC, Y + ((IR & IDX)? XR: 0)); /* pre-index */
for (i = 0; (i < ind_max) && (IR & IA); i++) { /* resolve ind addr */
IR = Read (Y & X_AMASK); /* get ind addr */
Y = NEWA (Y, IR + ((IR & IDX)? XR: 0)); } /* post-index */
IR = Read (Y & X_AMASK); /* get ind addr */
Y = NEWA (Y, IR + ((IR & IDX)? XR: 0)); } /* post-index */
} /* end else */
*addr = Y = Y & X_AMASK; /* return addr */
if (dlog && sim_log && !turnoff) /* cycle log? */

View file

@ -127,81 +127,81 @@ switch (inst) { /* case on opcode */
case ioOCP: /* OCP */
switch (fnc) { /* case on fnc */
case 000: case 002: case 004: /* paper adv */
lpt_svcst = lpt_svcst | LPT_SVCPA; /* set state */
lpt_svcch = fnc >> 1; /* save channel */
sim_activate (&lpt_unit, lpt_ptime);
CLR_READY (INT_LPT); /* clear int */
break;
lpt_svcst = lpt_svcst | LPT_SVCPA; /* set state */
lpt_svcch = fnc >> 1; /* save channel */
sim_activate (&lpt_unit, lpt_ptime);
CLR_READY (INT_LPT); /* clear int */
break;
case 007: /* init scan */
lpt_prdn = 0; /* clear pr done */
lpt_wdpos = 0; /* init scan pos */
if (!sim_is_active (&lpt_unit)) lpt_xfer = 1;
CLR_READY (INT_LPT); /* clear int */
break;
lpt_prdn = 0; /* clear pr done */
lpt_wdpos = 0; /* init scan pos */
if (!sim_is_active (&lpt_unit)) lpt_xfer = 1;
CLR_READY (INT_LPT); /* clear int */
break;
default:
return IOBADFNC (dat); }
return IOBADFNC (dat); }
break;
case ioSKS: /* SKS */
switch (fnc) { /* case on fnc */
case 000: /* if xfer rdy */
if (lpt_xfer) return IOSKIP (dat);
break;
if (lpt_xfer) return IOSKIP (dat);
break;
case 002: /* if !alarm */
if (lpt_unit.flags & UNIT_ATT) return IOSKIP (dat);
break;
if (lpt_unit.flags & UNIT_ATT) return IOSKIP (dat);
break;
case 003: /* if odd col */
if (lpt_crpos) return IOSKIP (dat);
break;
if (lpt_crpos) return IOSKIP (dat);
break;
case 004: /* if !interrupt */
if (!TST_INTREQ (INT_LPT)) return IOSKIP (dat);
break;
if (!TST_INTREQ (INT_LPT)) return IOSKIP (dat);
break;
case 011: /* if line printed */
if (lpt_prdn) return IOSKIP (dat);
break;
if (lpt_prdn) return IOSKIP (dat);
break;
case 012: /* if !shuttling */
if (!(lpt_svcst & LPT_SVCSH)) return IOSKIP (dat);
break;
if (!(lpt_svcst & LPT_SVCSH)) return IOSKIP (dat);
break;
case 013:
if (lpt_prdn && !(lpt_svcst & LPT_SVCSH)) return IOSKIP (dat);
break;
if (lpt_prdn && !(lpt_svcst & LPT_SVCSH)) return IOSKIP (dat);
break;
case 014: /* if !advancing */
if (!(lpt_svcst & LPT_SVCPA)) return IOSKIP (dat);
break;
if (!(lpt_svcst & LPT_SVCPA)) return IOSKIP (dat);
break;
case 015:
if (lpt_prdn && !(lpt_svcst & LPT_SVCPA)) return IOSKIP (dat);
break;
if (lpt_prdn && !(lpt_svcst & LPT_SVCPA)) return IOSKIP (dat);
break;
case 016:
if (!(lpt_svcst & (LPT_SVCSH | LPT_SVCPA))) return IOSKIP (dat);
break;
if (!(lpt_svcst & (LPT_SVCSH | LPT_SVCPA))) return IOSKIP (dat);
break;
case 017:
if (lpt_prdn && !(lpt_svcst & (LPT_SVCSH | LPT_SVCPA)))
return IOSKIP (dat);
break;
if (lpt_prdn && !(lpt_svcst & (LPT_SVCSH | LPT_SVCPA)))
return IOSKIP (dat);
break;
default:
return IOBADFNC (dat); }
return IOBADFNC (dat); }
break;
case ioOTA: /* OTA */
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
if (lpt_xfer) { /* xfer ready? */
lpt_xfer = 0; /* clear xfer */
chr = (dat >> (lpt_crpos? 0: 8)) & 077; /* get 6b char */
if (chr == lpt_drpos) { /* match drum pos? */
if (chr < 040) chr = chr | 0100;
lpt_buf[2 * lpt_wdpos + lpt_crpos] = chr; }
lpt_wdpos++; /* adv scan pos */
if (lpt_wdpos >= LPT_SCAN) { /* end of scan? */
lpt_wdpos = 0; /* reset scan pos */
lpt_drpos++; /* adv drum pos */
if (lpt_drpos >= LPT_DRUM) { /* end of drum? */
lpt_drpos = 0; /* reset drum pos */
lpt_crpos = lpt_crpos ^ 1; /* shuttle */
lpt_svcst = lpt_svcst | LPT_SVCSH;
sim_activate (&lpt_unit, lpt_ptime);
} /* end if shuttle */
else sim_activate (&lpt_unit, lpt_etime);
} /* end if endscan */
else sim_activate (&lpt_unit, lpt_xtime);
return IOSKIP (dat); } /* skip return */
lpt_xfer = 0; /* clear xfer */
chr = (dat >> (lpt_crpos? 0: 8)) & 077; /* get 6b char */
if (chr == lpt_drpos) { /* match drum pos? */
if (chr < 040) chr = chr | 0100;
lpt_buf[2 * lpt_wdpos + lpt_crpos] = chr; }
lpt_wdpos++; /* adv scan pos */
if (lpt_wdpos >= LPT_SCAN) { /* end of scan? */
lpt_wdpos = 0; /* reset scan pos */
lpt_drpos++; /* adv drum pos */
if (lpt_drpos >= LPT_DRUM) { /* end of drum? */
lpt_drpos = 0; /* reset drum pos */
lpt_crpos = lpt_crpos ^ 1; /* shuttle */
lpt_svcst = lpt_svcst | LPT_SVCSH;
sim_activate (&lpt_unit, lpt_ptime);
} /* end if shuttle */
else sim_activate (&lpt_unit, lpt_etime);
} /* end if endscan */
else sim_activate (&lpt_unit, lpt_xtime);
return IOSKIP (dat); } /* skip return */
break; } /* end case op */
return dat;
}
@ -226,7 +226,7 @@ if (lpt_svcst & LPT_SVCSH) { /* shuttling */
if (lpt_svcst & LPT_SVCPA) { /* paper advance */
SET_READY (INT_LPT); /* interrupt */
for (i = LPT_WIDTH - 1; i >= 0; i++) {
if (lpt_buf[i] != ' ') break; }
if (lpt_buf[i] != ' ') break; }
lpt_buf[i + 1] = 0;
fputs (lpt_buf, uptr->fileref); /* output buf */
fputs (lpt_cc[lpt_svcch & 03], uptr->fileref); /* output eol */

View file

@ -28,6 +28,7 @@
tty 316/516-33 teleprinter
clk/options 316/516-12 real time clocks/internal options
22-Dec-02 RMS Added break support
01-Nov-02 RMS Added 7b/8b support to terminal
30-May-02 RMS Widened POS to 32b
03-Nov-01 RMS Implemented upper case for console output
@ -199,13 +200,13 @@ case ioSKS: /* SKS */
if (fnc & 013) return IOBADFNC (dat); /* only fnc 0,4 */
if (((fnc == 0) && TST_READY (INT_PTR)) || /* fnc 0? skip rdy */
((fnc == 4) && !TST_INTREQ (INT_PTR))) /* fnc 4? skip !int */
return IOSKIP (dat);
return IOSKIP (dat);
break;
case ioINA: /* INA */
if (fnc & 007) return IOBADFNC (dat); /* only fnc 0,10 */
if (TST_READY (INT_PTR)) { /* ready? */
CLR_READY (INT_PTR); /* clear ready */
return IOSKIP (ptr_unit.buf | dat); } /* ret buf, skip */
CLR_READY (INT_PTR); /* clear ready */
return IOSKIP (ptr_unit.buf | dat); } /* ret buf, skip */
break; } /* end case op */
return dat;
}
@ -220,8 +221,8 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte */
if (feof (ptr_unit.fileref)) {
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
@ -284,28 +285,28 @@ switch (inst) { /* case on opcode */
case ioOCP: /* OCP */
if (fnc & 016) return IOBADFNC (dat); /* only fnc 0,1 */
if (fnc) { /* fnc 1? pwr off */
CLR_READY (INT_PTP); /* not ready */
ptp_power = 0; /* turn off power */
sim_cancel (&ptp_unit); } /* stop punch */
CLR_READY (INT_PTP); /* not ready */
ptp_power = 0; /* turn off power */
sim_cancel (&ptp_unit); } /* stop punch */
else if (ptp_power == 0) /* fnc 0? start */
sim_activate (&ptp_unit, ptp_ptime);
sim_activate (&ptp_unit, ptp_ptime);
break;
case ioSKS: /* SKS */
if ((fnc & 012) || (fnc == 005)) /* only 0, 1, 4 */
return IOBADFNC (dat);
return IOBADFNC (dat);
if (((fnc == 00) && TST_READY (INT_PTP)) || /* fnc 0? skip rdy */
((fnc == 01) /* fnc 1? skip ptp on */
&& (ptp_power || sim_is_active (&ptp_unit))) ||
((fnc == 04) && !TST_INTREQ (INT_PTP))) /* fnc 4? skip !int */
return IOSKIP (dat);
return IOSKIP (dat);
break;
case ioOTA: /* OTA */
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
if (TST_READY (INT_PTP)) { /* if ptp ready */
CLR_READY (INT_PTP); /* clear ready */
ptp_unit.buf = dat & 0377; /* store byte */
sim_activate (&ptp_unit, ptp_unit.wait);
return IOSKIP (dat); } /* skip return */
CLR_READY (INT_PTP); /* clear ready */
ptp_unit.buf = dat & 0377; /* store byte */
sim_activate (&ptp_unit, ptp_unit.wait);
return IOSKIP (dat); } /* skip return */
break; }
return dat;
}
@ -349,11 +350,12 @@ switch (inst) { /* case on opcode */
case ioOCP: /* OCP */
if (fnc & 016) return IOBADFNC (dat); /* only fnc 0,1 */
if (fnc && (tty_mode == 0)) { /* input to output? */
if (!sim_is_active (&tty_unit[TTO])) SET_READY (INT_TTY);
tty_mode = 1; } /* mode is output */
if (!sim_is_active (&tty_unit[TTO])) /* set ready */
SET_READY (INT_TTY);
tty_mode = 1; } /* mode is output */
else if ((fnc == 0) && tty_mode) { /* output to input? */
CLR_READY (INT_TTY); /* clear ready */
tty_mode = 0; } /* mode is input */
CLR_READY (INT_TTY); /* clear ready */
tty_mode = 0; } /* mode is input */
break;
case ioSKS: /* SKS */
if (fnc & 012) return IOBADFNC (dat); /* fnc 0,1,4,5 */
@ -363,26 +365,26 @@ case ioSKS: /* SKS */
((fnc == 4) && !TST_INTREQ (INT_TTY)) || /* fnc 4? skip !int */
((fnc == 5) && /* fnc 5? skip !xoff */
!tty_mode && ((tty_buf & 0177) == 023)))
return IOSKIP (dat);
return IOSKIP (dat);
break;
case ioINA: /* INA */
if (fnc & 005) return IOBADFNC (dat); /* only 0,2,10,12 */
if (TST_READY (INT_TTY)) { /* ready? */
if (tty_mode == 0) CLR_READY (INT_TTY); /* inp? clear rdy */
return IOSKIP (dat |
(tty_buf & ((fnc & 002)? 077: 0377))); }
if (tty_mode == 0) CLR_READY (INT_TTY); /* inp? clear rdy */
return IOSKIP (dat |
(tty_buf & ((fnc & 002)? 077: 0377))); }
break;
case ioOTA:
if (fnc & 015) return IOBADFNC (dat); /* only 0,2 */
if (TST_READY (INT_TTY)) { /* ready? */
tty_buf = dat & 0377; /* store char */
if (fnc & 002) { /* binary mode? */
tty_buf = tty_buf | 0100; /* set ch 7 */
if (tty_buf & 040) tty_buf = tty_buf & 0277; }
if (tty_mode) {
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait);
CLR_READY (INT_TTY); }
return IOSKIP (dat); }
tty_buf = dat & 0377; /* store char */
if (fnc & 002) { /* binary mode? */
tty_buf = tty_buf | 0100; /* set ch 7 */
if (tty_buf & 040) tty_buf = tty_buf & 0277; }
if (tty_mode) {
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait);
CLR_READY (INT_TTY); }
return IOSKIP (dat); }
break; } /* end case op */
return dat;
}
@ -396,7 +398,8 @@ int32 out, c;
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
out = c & 0177; /* mask echo to 7b */
if (tty_unit[TTI].flags & UNIT_KSR) { /* KSR? */
if (c & SCPE_BREAK) c = 0; /* break? */
else if (tty_unit[TTI].flags & UNIT_KSR) { /* KSR? */
if (islower (out)) out = toupper (out); /* cvt to UC */
c = out | 0200; } /* add TTY bit */
else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177);
@ -404,7 +407,7 @@ if (tty_mode == 0) { /* input mode? */
tty_buf = c; /* put char in buf */
tty_unit[TTI].pos = tty_unit[TTI].pos + 1;
SET_READY (INT_TTY); /* set flag */
sim_putchar (out); } /* echo */
if (out) sim_putchar (out); } /* echo */
return SCPE_OK;
}
@ -452,31 +455,32 @@ case ioOCP: /* OCP */
if (fnc & 015) return IOBADFNC (dat); /* only fnc 0,2 */
CLR_READY (INT_CLK); /* reset ready */
if (fnc) sim_cancel (&clk_unit); /* fnc = 2? stop */
else { if (!sim_is_active (&clk_unit)) /* fnc = 0? start */
else { /* fnc = 0? */
if (!sim_is_active (&clk_unit))
sim_activate (&clk_unit, /* activate */
sim_rtc_init (clk_unit.wait)); } /* init calibr */
sim_rtc_init (clk_unit.wait)); } /* init calibr */
break;
case ioSKS: /* SKS */
if (fnc == 0) { /* clock skip !int */
if (!TST_INTREQ (INT_CLK)) return IOSKIP (dat); }
if (!TST_INTREQ (INT_CLK)) return IOSKIP (dat); }
else if ((fnc & 007) == 002) { /* mem parity? */
if (((fnc == 002) && !TST_READY (INT_MPE)) ||
((fnc == 012) && TST_READY (INT_MPE)))
return IOSKIP (dat); }
if (((fnc == 002) && !TST_READY (INT_MPE)) ||
((fnc == 012) && TST_READY (INT_MPE)))
return IOSKIP (dat); }
else return IOBADFNC (dat); /* invalid fnc */
break;
case ioOTA: /* OTA */
if (fnc == 000) dev_enable = dat; /* SMK */
else if (fnc == 010) { /* OTK */
C = (dat >> 15) & 1; /* set C */
if (cpu_unit.flags & UNIT_HSA) /* HSA included? */
dp = (dat >> 14) & 1; /* set dp */
if (cpu_unit.flags & UNIT_EXT) { /* ext opt? */
if (dat & 020000) { /* ext set? */
ext = 1; /* yes, set */
extoff_pending = 0; }
else extoff_pending = 1; } /* no, clr later */
sc = dat & 037; } /* set sc */
C = (dat >> 15) & 1; /* set C */
if (cpu_unit.flags & UNIT_HSA) /* HSA included? */
dp = (dat >> 14) & 1; /* set dp */
if (cpu_unit.flags & UNIT_EXT) { /* ext opt? */
if (dat & 020000) { /* ext set? */
ext = 1; /* yes, set */
extoff_pending = 0; }
else extoff_pending = 1; } /* no, clr later */
sc = dat & 037; } /* set sc */
else return IOBADFNC (dat);
break; }
return dat;

View file

@ -187,9 +187,9 @@ int32 i, j;
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((j == class) && (opc_val[i] & inst)) { /* same class? */
inst = inst & ~opc_val[i]; /* mask bit set? */
fprintf (of, (sp? " %s": "%s"), opcode[i]);
sp = 1; } }
inst = inst & ~opc_val[i]; /* mask bit set? */
fprintf (of, (sp? " %s": "%s"), opcode[i]);
sp = 1; } }
return sp;
}
@ -232,28 +232,28 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
switch (j) { /* case on class */
case I_V_NPN: /* no operands */
fprintf (of, "%s", opcode[i]); /* opcode */
break;
fprintf (of, "%s", opcode[i]); /* opcode */
break;
case I_V_MRF: case I_V_MRX: /* mem ref */
disp = inst & DISP; /* displacement */
fprintf (of, "%s ", opcode[i]); /* opcode */
if (inst & SC) { /* current sector? */
if (cflag) fprintf (of, "%-o", (addr & PAGENO) | disp);
else fprintf (of, "C %-o", disp); }
else fprintf (of, "%-o", disp); /* sector zero */
if ((j == I_V_MRF) && (inst & IDX)) fprintf (of, ",1");
break;
disp = inst & DISP; /* displacement */
fprintf (of, "%s ", opcode[i]); /* opcode */
if (inst & SC) { /* current sector? */
if (cflag) fprintf (of, "%-o", (addr & PAGENO) | disp);
else fprintf (of, "C %-o", disp); }
else fprintf (of, "%-o", disp); /* sector zero */
if ((j == I_V_MRF) && (inst & IDX)) fprintf (of, ",1");
break;
case I_V_IOT: /* I/O */
disp = inst & 01777; /* pulse+dev */
fprintf (of, "%s %o", opcode[i], disp);
break;
disp = inst & 01777; /* pulse+dev */
fprintf (of, "%s %o", opcode[i], disp);
break;
case I_V_SHF: /* shift */
disp = -inst & SHFMASK; /* shift count */
fprintf (of, "%s %o", opcode[i], disp);
break;
disp = -inst & SHFMASK; /* shift count */
fprintf (of, "%s %o", opcode[i], disp);
break;
case I_V_SK0: case I_V_SK1: /* skips */
fprint_opr (of, inst & 0777, j, 0); /* print skips */
break; } /* end case */
fprint_opr (of, inst & 0777, j, 0); /* print skips */
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
@ -315,15 +315,15 @@ case I_V_SHF: /* shift */
case I_V_MRF: case I_V_MRX: /* mem ref */
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */
val[0] = val[0] | SC;
cptr = get_glyph (cptr, gbuf, 0); }
val[0] = val[0] | SC;
cptr = get_glyph (cptr, gbuf, 0); }
else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */
cptr = get_glyph (cptr, gbuf, ','); }
cptr = get_glyph (cptr, gbuf, ','); }
d = get_uint (gbuf, 8, X_AMASK, &r); /* construe as addr */
if (r != SCPE_OK) return SCPE_ARG;
if (d <= DISP) val[0] = val[0] | d; /* fits? */
else if (cflag && !k && (((addr ^ d) & PAGENO) == 0))
val[0] = val[0] | (d & DISP) | SC;
val[0] = val[0] | (d & DISP) | SC;
else return SCPE_ARG;
if ((j == I_V_MRX) || (*cptr == 0)) break; /* indexed? */
cptr = get_glyph (cptr, gbuf, 0);
@ -334,12 +334,12 @@ case I_V_MRF: case I_V_MRX: /* mem ref */
case I_V_SK0: case I_V_SK1: /* skips */
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
k = opc_val[i] & DMASK;
if ((opcode[i] == NULL) || (((k ^ val[0]) & 0177000) != 0))
return SCPE_ARG;
val[0] = val[0] | k; }
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
k = opc_val[i] & DMASK;
if ((opcode[i] == NULL) || (((k ^ val[0]) & 0177000) != 0))
return SCPE_ARG;
val[0] = val[0] | k; }
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
return SCPE_OK;

View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Nov-02 RMS Added 21MX IOP support
24-Oct-02 RMS Fixed bugs in IOP and extended instructions
Fixed bugs in memory protection and DMS
Added clock calibration
@ -283,8 +284,9 @@
#define UNIT_V_FP (UNIT_V_UF + 3) /* FP */
#define UNIT_V_MPR (UNIT_V_UF + 4) /* mem prot */
#define UNIT_V_DMS (UNIT_V_UF + 5) /* DMS */
#define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP */
#define UNIT_V_MSIZE (UNIT_V_UF + 7) /* dummy mask */
#define UNIT_V_IOP (UNIT_V_UF + 6) /* 2100 IOP */
#define UNIT_V_IOPX (UNIT_V_UF + 7) /* 21MX IOP */
#define UNIT_V_MSIZE (UNIT_V_UF + 8) /* dummy mask */
#define UNIT_2100 (1 << UNIT_V_2100)
#define UNIT_21MX (1 << UNIT_V_21MX)
#define UNIT_EAU (1 << UNIT_V_EAU)
@ -292,6 +294,7 @@
#define UNIT_MPR (1 << UNIT_V_MPR)
#define UNIT_DMS (1 << UNIT_V_DMS)
#define UNIT_IOP (1 << UNIT_V_IOP)
#define UNIT_IOPX (1 << UNIT_V_IOPX)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define MOD_2116 1
@ -330,6 +333,7 @@ uint32 dms_ump = 0; /* dms user map */
uint32 dms_sr = 0; /* dms status reg */
uint32 dms_vr = 0; /* dms violation reg */
uint32 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */
uint32 iop_sp = 0; /* iop stack */
uint32 ind_max = 16; /* iadr nest limit */
uint32 stop_inst = 1; /* stop on ill inst */
uint32 stop_dev = 0; /* stop on ill dev */
@ -347,7 +351,7 @@ static struct opt_table opt_val[] = {
{ UNIT_FP, MOD_2100 },
{ UNIT_MPR, MOD_2100 | MOD_21MX },
{ UNIT_DMS, MOD_21MX },
{ UNIT_IOP, MOD_2100 },
{ UNIT_IOP, MOD_2100 | MOD_21MX },
{ 0, 0 } };
extern int32 sim_interval;
@ -431,6 +435,7 @@ REG cpu_reg[] = {
{ ORDATA (DMSSR, dms_sr, 16) },
{ ORDATA (DMSVR, dms_vr, 16) },
{ BRDATA (DMSMAP, dms_map, 8, PA_N_SIZE, MAP_NUM * MAP_LNT) },
{ ORDATA (IOPSP, iop_sp, 16) },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ FLDATA (STOP_DEV, stop_dev, 1) },
{ DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },
@ -448,34 +453,36 @@ REG cpu_reg[] = {
{ NULL } };
MTAB cpu_mod[] = {
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP,
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP+UNIT_IOPX,
0, NULL, "2116", NULL },
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP,
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP+UNIT_IOPX,
UNIT_2100+UNIT_EAU, NULL, "2100", NULL },
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP,
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP+UNIT_IOPX,
UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS, NULL, "21MX", NULL },
{ UNIT_2100+UNIT_21MX, 0, "2116", NULL, NULL },
{ UNIT_2100+UNIT_21MX, UNIT_2100, "2100", NULL, NULL },
{ UNIT_2100+UNIT_21MX, UNIT_21MX, "21MX", NULL, NULL },
{ UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt,
NULL, (void *) UNIT_EAU },
{ UNIT_EAU, 0, "NOEAU", "NOEAU", &cpu_set_opt,
{ UNIT_EAU, 0, "no EAU", "NOEAU", &cpu_set_opt,
NULL, (void *) UNIT_EAU },
{ UNIT_FP, UNIT_FP, "FP", "FP", &cpu_set_opt,
NULL, (void *) UNIT_FP },
{ UNIT_FP, 0, "NOFP", "NOFP", &cpu_set_opt,
{ UNIT_FP, 0, "no FP", "NOFP", &cpu_set_opt,
NULL, (void *) UNIT_FP },
{ UNIT_MPR, UNIT_MPR, "MPR", "MPR", &cpu_set_opt,
NULL, (void *) UNIT_MPR },
{ UNIT_MPR, 0, "NOMPR", "NOMPR", &cpu_set_opt,
{ UNIT_MPR, 0, "no MPR", "NOMPR", &cpu_set_opt,
NULL, (void *) UNIT_MPR },
{ UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt,
NULL, (void *) UNIT_DMS },
{ UNIT_DMS, 0, "NODMS", "NODMS", &cpu_set_opt,
{ UNIT_DMS, 0, "no DMS", "NODMS", &cpu_set_opt,
NULL, (void *) UNIT_DMS },
{ UNIT_IOP, UNIT_IOP, "IOP", "IOP", &cpu_set_opt,
{ UNIT_MSIZE, 2, NULL, "IOP", &cpu_set_opt,
NULL, (void *) UNIT_IOP },
{ UNIT_IOP, 0, "NOIOP", "NOIOP", &cpu_set_opt,
{ UNIT_IOP+UNIT_IOPX, UNIT_IOP, "IOP", NULL, NULL },
{ UNIT_IOP+UNIT_IOPX, UNIT_IOPX, "IOP", NULL, NULL },
{ UNIT_IOP+UNIT_IOPX, 0, "no IOP", "NOIOP", &cpu_set_opt,
NULL, (void *) UNIT_IOP },
{ UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
@ -544,6 +551,7 @@ DEVICE dma1_dev = {
#define E_21MX (UNIT_21MX >> (UNIT_V_UF - E_V_FL))
#define E_DMS (UNIT_DMS >> (UNIT_V_UF - E_V_FL))
#define E_IOP (UNIT_IOP >> (UNIT_V_UF - E_V_FL))
#define E_IOPX (UNIT_IOPX >> (UNIT_V_UF - E_V_FL))
#define E_V_TY 8 /* type */
#define E_M_TY 0xF
#define E_NO 0 /* no operands */
@ -558,7 +566,7 @@ DEVICE dma1_dev = {
#define ET_CN (E_CN << E_V_TY)
#define ET_AC (E_AC << E_V_TY)
#define ET_AZ (E_AZ << E_V_TY)
#define E_V_TYI 12 /* type if IOP */
#define E_V_TYI 12 /* type if 2100 IOP */
#define E_GETFL(x) (((x) >> E_V_FL) & E_M_FL)
#define E_GETTY(f,x) (((x) >> \
((((f) & E_IOP) && (cpu_unit.flags & UNIT_IOP))? \
@ -572,6 +580,9 @@ DEVICE dma1_dev = {
#define D_NO E_DMS | ET_NO
#define D_MR E_DMS | ET_AD
#define D_AA E_DMS | ET_AA
#define M_NO E_IOPX | ET_NO
#define M_CN E_IOPX | ET_CN
#define M_AC E_IOPX | ET_AC
#define I_NO E_IOP | (ET_NO << (E_V_TYI - E_V_TY))
#define I_CN E_IOP | (ET_CN << (E_V_TYI - E_V_TY))
#define I_AC E_IOP | (ET_AC << (E_V_TYI - E_V_TY))
@ -591,17 +602,20 @@ static const uint32 e_inst[512] = {
0,0,0,0,0,0,0,0,I_CN,0,0,0,0,0,0,0, /* CRC */
I_CN,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* TRSLT */
I_AZ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* WMOVE */
I_NO,I_NO,I_NO,I_NO,0,0,0,0,0,0,0,0,0,0,0,0, /* READF,PFRIO,PFREI,PFRIO */
I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,I_NO, /* ENQ,ENPQ */
I_NO,I_NO,I_NO,I_NO,0,0,0,0,0,0,0,0,0,0,0,0, /* READF,PFRIO,PFREI,PFREX */
I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,I_NO, /* ENQ,PENQ */
I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* DEQ */
I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SBYTE */
I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* LBYTE */
I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* REST */
0,0,I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SAVE */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0400 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0420 */
M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO, /* LAI-/SAI- */
M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,
M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO, /* LAI+/SAI+ */
M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0440 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0460 */
M_CN,M_NO,M_NO,M_NO,M_NO,M_NO,M_NO,M_CN, /* CRC,REST,READF,INS,ENQ,PENQ,DEQ,TR */
M_AC,M_NO,M_NO,M_NO,M_NO,0,0,0, /* ILIST,PFREI,PFREX,PFRIO,SAVE */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0500 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0520 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0540 */
@ -921,8 +935,8 @@ case 0014:case 0015:case 0016:case 0017:
t = (t + 1) & DMASK;
if (t == 0) E = 1;
if (t == SIGN) O = 1; }
if ((IR & 000002) && (t == 0)) skip = 1;/* SZx */
} /* end if ~RSS */
if ((IR & 000002) && (t == 0)) skip = 1; /* SZx */
} /* end if ~RSS */
ABREG[absel] = t; /* store result */
PC = (PC + skip) & VAMASK; /* add in skip */
break; /* end if alter/skip */
@ -1092,42 +1106,33 @@ case 0203:case 0213: /* MAC1 ext */
/* Floating point instructions */
case 0000: /* IOP ILIST/FAD */
if (cpu_unit.flags & UNIT_IOP) { /* ILIST (E_AC) */
do { /* for count */
WriteW (MA, AR); /* write AR to mem */
AR = (AR + 1) & DMASK; /* incr AR */
MA = (MA + 1) & VAMASK; /* incr MA */
wc = (wc - 1) & DMASK; } /* decr count */
while (wc != 0); }
else { /* FAD (E_AD) */
fop = ReadF (MA); /* get fop */
O = f_as (fop, 0); } /* add, upd ovflo */
if (cpu_unit.flags & UNIT_IOP) /* ILIST (E_AC) */
goto IOP_ILIST;
fop = ReadF (MA); /* get fop */
O = f_as (fop, 0); /* add, upd ovflo */
break;
case 0020: /* IOP LAI-/FSB */
if (cpu_unit.flags & UNIT_IOP) /* LAI -20 (I_NO) */
AR = ReadW ((BR - 020) & VAMASK); /* load AR */
else { /* FSB (E_AD) */
fop = ReadF (MA); /* get fop */
O = f_as (fop, 1); } /* sub, upd ovflo */
goto IOP_LAIM;
fop = ReadF (MA); /* get fop */
O = f_as (fop, 1); /* sub, upd ovflo */
break;
case 0040: /* IOP LAI+/FMP */
if (cpu_unit.flags & UNIT_IOP) /* LAI 0 (I_NO) */
AR = ReadW (BR & VAMASK); /* load AR */
else { /* FMP (E_AD) */
fop = ReadF (MA); /* get fop */
O = f_mul (fop); } /* mul, upd ovflo */
goto IOP_LAIP;
fop = ReadF (MA); /* get fop */
O = f_mul (fop); /* mul, upd ovflo */
break;
case 0060: /* IOP SAI-/FDV */
if (cpu_unit.flags & UNIT_IOP) /* SAI -20 (I_NO) */
WriteW ((BR - 020) & VAMASK, AR); /* store AR */
else { /* FDV (E_AD) */
fop = ReadF (MA); /* get fop */
O = f_div (fop); } /* div, upd ovflo */
goto IOP_SAIM;
fop = ReadF (MA); /* get fop */
O = f_div (fop); /* div, upd ovflo */
break;
case 0100: /* IOP SAI+/FIX */
if (cpu_unit.flags & UNIT_IOP) /* SAI 0 (I_NO) */
WriteW (BR & VAMASK, AR); /* store AR */
else O = f_fix (); /* FIX (E_NO) */
goto IOP_SAIP;
O = f_fix (); /* FIX (E_NO) */
break;
case 0120: /* IOP MBYTE/FLT */
if (cpu_unit.flags & UNIT_IOP) /* MBYTE (I_AZ) */
@ -1135,30 +1140,30 @@ case 0203:case 0213: /* MAC1 ext */
O = f_flt (); /* FLT (E_NO) */
break;
/* IOP instructions */
/* 2100 (and 21MX) IOP instructions */
case 0021: case 0022: case 0023: /* IOP LAI- (I_NO) */
IOP_LAIM: case 0021: case 0022: case 0023: /* IOP LAI- (I_NO) */
case 0024: case 0025: case 0026: case 0027:
case 0030: case 0031: case 0032: case 0033:
case 0034: case 0035: case 0036: case 0037:
MA = ((IR | 0177760) + BR) & VAMASK; /* IR<3:0> = -offset */
AR = ReadW (MA); /* load AR */
break;
case 0041: case 0042: case 0043: /* IOP LAI+ (I_NO) */
IOP_LAIP: case 0041: case 0042: case 0043: /* IOP LAI+ (I_NO) */
case 0044: case 0045: case 0046: case 0047:
case 0050: case 0051: case 0052: case 0053:
case 0054: case 0055: case 0056: case 0057:
MA = ((IR & 017) + BR) & VAMASK; /* IR<3:0> = +offset */
AR = ReadW (MA); /* load AR */
break;
case 0061: case 0062: case 0063: /* IOP SAI- (I_NO) */
IOP_SAIM: case 0061: case 0062: case 0063: /* IOP SAI- (I_NO) */
case 0064: case 0065: case 0066: case 0067:
case 0070: case 0071: case 0072: case 0073:
case 0074: case 0075: case 0076: case 0077:
MA = ((IR | 0177760) + BR) & VAMASK; /* IR<3:0> = -offset */
WriteW (MA, AR); /* store AR */
break;
case 0101: case 0102: case 0103: /* IOP SAI+ (I_NO) */
IOP_SAIP: case 0101: case 0102: case 0103: /* IOP SAI+ (I_NO) */
case 0104: case 0105: case 0106: case 0107:
case 0110: case 0111: case 0112: case 0113:
case 0114: case 0115: case 0116: case 0117:
@ -1166,6 +1171,7 @@ case 0203:case 0213: /* MAC1 ext */
WriteW (MA, AR); /* store AR */
break;
case 0150: /* IOP CRC (I_CN) */
case 0460: /* IOPX CRC (I_CN) */
t = (AR & 0xFF) ^ wc; /* start CRC */
for (i = 0; i < 8; i++) { /* apply polynomial */
t = (t >> 1) | ((t & 1) << 15); /* rotate right */
@ -1173,6 +1179,7 @@ case 0203:case 0213: /* MAC1 ext */
WriteW (awc, t); /* rewrite CRC */
break;
case 0160: /* IOP TRSLT (I_CN) */
case 0467: /* IOPX TRSLT (I_CN) */
if (wc & SIGN) break; /* cnt < 0? */
while (wc != 0) { /* loop */
MA = (AR + AR + ReadB (BR)) & VAMASK;
@ -1180,19 +1187,25 @@ case 0203:case 0213: /* MAC1 ext */
WriteB (BR, t); /* store char */
BR = (BR + 1) & DMASK; /* incr ptr */
wc = (wc - 1) & DMASK; /* decr cnt */
WriteW (awc, wc); }
WriteW (awc, wc);
if (wc && intrq) { /* more and intr? */
PC = err_PC; /* stop for now */
break; } }
break;
case 0220: /* IOP READF (I_NO) */
AR = mp_fence; /* copy mp_fence */
case 0462: /* IOPX READF (I_NO) */
AR = iop_sp; /* copy stk ptr */
break;
case 0221: /* IOP PRFIO (I_NO) */
case 0473: /* IOPX PFRIO (I_NO) */
IR = ReadW (PC); /* get IO instr */
PC = (PC + 1) & VAMASK;
WriteW (PC, 1); /* set flag */
PC = (PC + 1) & VAMASK;
reason = iogrp (IR, 0); /* execute instr */
break;
case 0222: /* IOP PRFIE (I_NO) */
case 0222: /* IOP PRFEI (I_NO) */
case 0471: /* IOPX PFREI (I_NO) */
IR = ReadW (PC); /* get IO instr */
PC = (PC + 1) & VAMASK;
WriteW (PC, 1); /* set flag */
@ -1200,12 +1213,14 @@ case 0203:case 0213: /* MAC1 ext */
reason = iogrp (IR, 0); /* execute instr */
/* fall through */
case 0223: /* IOP PRFEX (I_NO) */
case 0472: /* IOPX PFREX (I_NO) */
MA = ReadW (PC); /* exit addr */
PCQ_ENTRY;
PC = ReadW (MA) & VAMASK; /* jump indirect */
WriteW (MA, 0); /* clear exit */
break;
case 0240: /* IOP ENQ (I_NO) */
case 0464: /* IOPX ENQ (I_NO) */
hp = ReadW (AR & VAMASK); /* addr of head */
tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */
WriteW ((BR - 1) & VAMASK, 0); /* entry link */
@ -1213,7 +1228,8 @@ case 0203:case 0213: /* MAC1 ext */
WriteW ((AR + 1) & VAMASK, BR); /* queue tail */
if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */
break;
case 0257: /* IOP ENQP (I_NO) */
case 0257: /* IOP PENQ (I_NO) */
case 0465: /* IOPX PENQ (I_NO) */
hp = ReadW (AR & VAMASK); /* addr of head */
WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */
WriteW (AR & VAMASK, BR); /* queue head */
@ -1222,6 +1238,7 @@ case 0203:case 0213: /* MAC1 ext */
else PC = (PC + 1) & VAMASK; /* skip */
break;
case 0260: /* IOP DEQ (I_NO) */
case 0466: /* IOPX DEQ (I_NO) */
BR = ReadW (AR & VAMASK); /* addr of head */
if (BR) { /* queue not empty? */
hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */
@ -1239,23 +1256,56 @@ case 0203:case 0213: /* MAC1 ext */
BR = (BR + 1) & DMASK; /* incr ptr */
break;
case 0340: /* IOP REST (I_NO) */
mp_fence = (mp_fence - 1) & VAMASK; /* pop E/~O,BR,AR */
t = ReadW (mp_fence);
case 0461: /* IOPX REST (I_NO) */
iop_sp = (iop_sp - 1) & VAMASK; /* pop E/~O,BR,AR */
t = ReadW (iop_sp);
O = ((t >> 1) ^ 1) & 1;
E = t & 1;
mp_fence = (mp_fence - 1) & VAMASK;
BR = ReadW (mp_fence);
mp_fence = (mp_fence - 1) & VAMASK;
AR = ReadW (mp_fence);
iop_sp = (iop_sp - 1) & VAMASK;
BR = ReadW (iop_sp);
iop_sp = (iop_sp - 1) & VAMASK;
AR = ReadW (iop_sp);
if (cpu_unit.flags & UNIT_2100) mp_fence = iop_sp;
break;
case 0362: /* IOP SAVE (I_NO) */
WriteW (mp_fence, AR); /* push AR,BR,E/~O */
mp_fence = (mp_fence + 1) & VAMASK;
WriteW (mp_fence, BR);
mp_fence = (mp_fence + 1) & VAMASK;
case 0474: /* IOPX SAVE (I_NO) */
WriteW (iop_sp, AR); /* push AR,BR,E/~O */
iop_sp = (iop_sp + 1) & VAMASK;
WriteW (iop_sp, BR);
iop_sp = (iop_sp + 1) & VAMASK;
t = ((O ^ 1) << 1) | E;
WriteW (mp_fence, t);
mp_fence = (mp_fence + 1) & VAMASK;
WriteW (iop_sp, t);
iop_sp = (iop_sp + 1) & VAMASK;
if (cpu_unit.flags & UNIT_2100) mp_fence = iop_sp;
break;
case 0400: case 0401: case 0402: case 0403: /* IOPX LAI-/SAI- (I_NO) */
case 0404: case 0405: case 0406: case 0407:
case 0410: case 0411: case 0412: case 0413:
case 0414: case 0415: case 0416: case 0417:
MA = ((IR | 0177760) + BR) & VAMASK; /* IR<3:0> = -offset */
if (IR & I_AB) AR = ReadW (MA); /* AB = 1? LAI */
else WriteW (MA, AR); /* AB = 0? SAI */
break;
case 0420: case 0421: case 0422: case 0423: /* IOPX LAI+/SAI+ (I_NO) */
case 0424: case 0425: case 0426: case 0427:
case 0430: case 0431: case 0432: case 0433:
case 0434: case 0435: case 0436: case 0437:
MA = ((IR & 017) + BR) & VAMASK; /* IR<3:0> = +offset */
if (IR & I_AB) AR = ReadW (MA); /* AB = 1? LAI */
else WriteW (MA, AR); /* AB = 0? SAI */
break;
case 0463: /* IOPX INS (I_NO) */
iop_sp = AR; /* init stk ptr */
break;
case 0470: /* IOPX ILIST (I_CN) */
IOP_ILIST:
do { /* for count */
WriteW (MA, AR); /* write AR to mem */
AR = (AR + 1) & DMASK; /* incr AR */
MA = (MA + 1) & VAMASK; /* incr MA */
wc = (wc - 1) & DMASK; } /* decr count */
while (wc != 0);
break;
/* DMS instructions, move alternate - interruptible
@ -2220,6 +2270,7 @@ case ioLIX: /* load */
break;
case ioOTX: /* output */
mp_fence = dat & VAMASK;
if (cpu_unit.flags & UNIT_2100) iop_sp = mp_fence;
break;
case ioCTL: /* control clear/set */
if ((IR & I_CTL) == 0) { /* STC */
@ -2420,6 +2471,8 @@ else M[addr] = val & DMASK;
return SCPE_OK;
}
/* Memory size validation */
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
@ -2515,11 +2568,14 @@ mod = MOD_2116;
if (uptr->flags & UNIT_2100) mod = MOD_2100;
else if (uptr->flags & UNIT_21MX) mod = MOD_21MX;
for (i = 0; opt_val[i].optf != 0; i++) {
if ((val == opt_val[i].optf) && (mod & opt_val[i].cpuf)) {
if (mod == MOD_2100) {
if (val == UNIT_FP) uptr->flags = uptr->flags & ~UNIT_IOP;
if (val == UNIT_IOP) uptr->flags = uptr->flags & ~UNIT_FP; }
if (val == UNIT_DMS) uptr->flags = uptr->flags | UNIT_MPR;
if ((opt == opt_val[i].optf) && (mod & opt_val[i].cpuf)) {
if ((mod == MOD_2100) && (val == UNIT_FP))
uptr->flags = uptr->flags & ~UNIT_IOP;
if ((opt == UNIT_IOP) && val) {
if (mod == MOD_2100) uptr->flags =
(uptr->flags & ~UNIT_FP) | UNIT_IOP | UNIT_MPR;
if (mod == MOD_21MX) uptr->flags |= UNIT_IOPX | UNIT_MPR; }
if (val == UNIT_DMS) uptr->flags |= UNIT_MPR;
return SCPE_OK; } }
return SCPE_NOFNC;
}

View file

@ -45,6 +45,7 @@
#define STOP_IBKPT 4 /* breakpoint */
#define STOP_IND 5 /* indirect loop */
#define STOP_INDINT 6 /* indirect intr */
#define STOP_NOCONN 7 /* no connection */
#define ABORT_PRO 1 /* protection abort */
@ -207,6 +208,8 @@ struct DMA { /* DMA channel */
#define DRC 027 /* 12610A control */
#define MSD 030 /* 13181A data */
#define MSC 031 /* 13181A control */
#define IPLI 032 /* 12556B link in */
#define IPLO 033 /* 12556B link out */
#define MUXL 040 /* 12920A lower data */
#define MUXU 041 /* 12920A upper data */
#define MUXC 042 /* 12920A control */

View file

@ -1,3 +1,5 @@
HP2100 Diagnostics
CPU status writeup sources
24315 Memory reference group passed in 21MX CE no
@ -32,7 +34,27 @@ CPU status writeup sources
- prints diagnostic name
- prints END OF PASS 1 and halts
13206 IOP for 2100 group passed 13206 manual no
13206 IOP for 2100 passed 13206 manual no
- load diagnostic via configurator
- D S 0
- SET CPU 2100
- SET CPU IOP
- RUN 2000
- prints diagnostic name
- prints section names, PASS 000001, and halts
- note: will not pass interruptibility tests
13207 IOP for 21MX passed 13207 manual no
- load diagnostic via configurator
- D S 13
- SET CPU 21MX
- SET CPU IOP
- RUN 100
- HLT 74, PC = 2425
- D S 0
- CON
- prints diagnostic name
- prints section names, PASS 000001, and halts
24320 Floating point passed in 21MX CE no
- load diagnostic via configurator

View file

@ -51,6 +51,7 @@ sim/hp2100/ hp2100_defs.h
hp2100_dp.c
hp2100_dq.c
hp2100_dr.c
hp2100_ipl.c
hp2100_lps.c
hp2100_lpt.c
hp2100_mt.c
@ -85,6 +86,8 @@ DR 12606B fixed head disk controller with 2770/2771 disks
MT 12559C magnetic tape controller with one 3030 drive
MS 13181A magnetic tape controller with four 7970B drives
13183A magnetic tape controller with four 7970E drives
IPLI 12556B interprocessor link, input side
IPLO 12556B interprocessor link, output side
The HP2100 simulator implements several unique stop conditions:
@ -107,8 +110,8 @@ CPU options include choice of instruction set and memory size.
SET CPU NOEAU no EAU instructions (2116 only)
SET CPU FP FP instructions (2100 only)
SET CPU NOFP no FP instructions (2100 only)
SET CPU IOP IOP instructions (2100 only)
SET CPU NOIOP no IOP instructions (2100 only)
SET CPU IOP IOP instructions (2100, 21MX only)
SET CPU NOIOP no IOP instructions (2100, 21MX only)
SET CPU DMS DMS instructions (21MX only)
SET CPU NODMS no DMS instructions (21MX only)
SET CPU 4K set memory size = 4K
@ -505,6 +508,62 @@ The modem control (MUXM) implements these registers:
The terminal multiplexor does not support save and restore. All open
connections are lost when the simulator shuts down or MUXU is detached.
2.4.8 Interprocessor Link (IPLI, IPLO)
The interprocessor link is a pair of 12556B parallel interfaces that
are cross coupled to provide interprocessor communications to a second
copy of the HP2100 simulator. The IPL is intended to support simulation
of a two system HP TimeShared Basic configuration. The links are actually
bidirectional half-duplex; TimeShared Basic uses them unidirectionally.
The IPL is disabled by default.
To operate, the IPL devices must be enabled and then connected to the IPL
devices in another copy of the simulator. The IPLI device in the first
simulator is connected to the IPLO device in the second, and vice versa.
Connections are established with the ATTACH command. One copy of the
simulator listens for connections on a specified port (ATTACH -L); the
other establishes connections to an IP address and port (ATTACH -C).
Either copy may perform either operation, but the operations must be
done in matched pairs:
simulator #1 simulator #2
sim> set ipli ena sim> set ipli ena
(also enables iplo) (also enables iplo)
sim> att -lw ipli 4000
Listening on port 4000
Waiting for connection
sim> att -c iplo 4000
Connection established Connected to 127.0.0.1 port 4000
sim> att -lw iplo 4000
Listening on port 4001
Waiting for connection
sim> att -c ipli 4001
Connection established Connected to 127.0.0.1 port 4000
Both forms of ATTACH take a modifier -W (wait); if specified, the command
will wait up to 30 seconds for the connection process to complete. ATTACH
-C can specify both an IP address and a port, in the form aa.bb.cc.dd:port;
if the IP address is omitted, it defaults to 127.0.0.1 (local system).
Both IPLI and IPLO implement the BOOT command. BOOT loads the HP Access
Basic Block Loader for the IOP into the top 64 words of memory and starts
it running.
Both IPLI and IPLO implement these registers:
name size comments
BUF 16 buffer
HOLD 8 holding buffer
CMD 1 device enable
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
TIME 24 polling interval for input
STOP_IOE 1 stop on I/O error
2.5 12557A Disk Controller (DPC, DPD) with 2781 Drives
13210A Disk Controller (DPC, DPD) with 7900 Drives

View file

@ -119,8 +119,8 @@
#define STA_MBZ13 (STA_ATN + STA_RWU + STA_SKI) /* zero in 13210 */
extern uint16 *M;
extern int32 PC, SR;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC, SR;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern int32 sim_switches;
extern UNIT cpu_unit;
@ -702,8 +702,8 @@ return SCPE_OK;
/* 7900/7901 bootstrap routine (HP 12992F ROM) */
#define LDR_BASE 077
#define CHANGE_DEV (1 << 24)
#define CHANGE_ADDR (1 << 23)
static const int32 dboot[IBL_LNT] = {
0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */
@ -766,7 +766,7 @@ static const int32 dboot[IBL_LNT] = {
0027700, /* JMP ST ; no, retry */
0117751, /*XT JSB ADDR2,I ; start program */
0120000+CHANGE_DEV, /*DMACW 120000+DC */
CHANGE_ADDR }; /* -ST */
0000000 }; /* -ST */
t_stat dpc_boot (int32 unitno, DEVICE *dptr)
{
@ -778,11 +778,10 @@ PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
SR = IBL_DP + (dev << IBL_V_DEV); /* set SR */
if (sim_switches & SWMASK ('F')) SR = SR | IBL_FIX; /* boot from fixed? */
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
if (dboot[i] & CHANGE_ADDR) /* memory limit? */
M[PC + i] = (-PC) & DMASK;
else if (dboot[i] & CHANGE_DEV) /* IO instr? */
if (dboot[i] & CHANGE_DEV) /* IO instr? */
M[PC + i] = (dboot[i] + dev) & DMASK;
else M[PC + i] = dboot[i]; }
else M[PC + i] = dboot[i]; }
M[PC + LDR_BASE] = (~PC + 1) & DMASK;
return SCPE_OK;
}

View file

@ -104,8 +104,8 @@
#define STA_ALLERR (STA_NRDY + STA_EOC + STA_AER + STA_FLG + STA_DTE)
extern uint16 *M;
extern int32 PC, SR;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC, SR;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern int32 sim_switches;
extern UNIT cpu_unit;
@ -654,8 +654,8 @@ return SCPE_OK;
/* 2883/2884 bootstrap routine (subset HP 12992A ROM) */
#define LDR_BASE 077
#define CHANGE_DEV (1 << 24)
#define CHANGE_ADDR (1 << 23)
static const int32 dboot[IBL_LNT] = {
0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */
@ -698,7 +698,7 @@ static const int32 dboot[IBL_LNT] = {
0164000, /*CNT -6144. */
0117773, /*XT JSB ADDR2,I ; start program */
0120000+CHANGE_DEV, /*DMACW 120000+DC */
CHANGE_ADDR }; /* -ST */
0000000 }; /* -ST */
t_stat dqc_boot (int32 unitno, DEVICE *dptr)
{
@ -709,10 +709,9 @@ dev = dqd_dib.devno; /* get data chan dev */
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
SR = IBL_DQ + (dev << IBL_V_DEV); /* set SR */
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
if (dboot[i] & CHANGE_ADDR) /* memory limit? */
M[PC + i] = (-PC) & DMASK;
else if (dboot[i] & CHANGE_DEV) /* IO instr? */
if (dboot[i] & CHANGE_DEV) /* IO instr? */
M[PC + i] = (dboot[i] + dev) & DMASK;
else M[PC + i] = dboot[i]; }
M[PC + LDR_BASE] = (~PC + 1) & DMASK;
return SCPE_OK;
}

View file

@ -94,8 +94,8 @@
extern UNIT cpu_unit;
extern uint16 *M;
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
int32 drc_cw = 0; /* fnc, addr */
int32 drc_sta = 0; /* status */

465
HP2100/hp2100_ipl.c Normal file
View file

@ -0,0 +1,465 @@
/* hp2100_ipl.c: HP 2000 interprocessor link simulator
Copyright (c) 2002, 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.
ipli, iplo 12556B interprocessor link pair
*/
#include "hp2100_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
#define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */
#define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */
#define UNIT_DIAG (1 << UNIT_V_DIAG)
#define UNIT_ACTV (1 << UNIT_V_ACTV)
#define UNIT_ESTB (1 << UNIT_V_ESTB)
#define DSOCKET u3 /* data socket */
#define LSOCKET u4 /* listening socket */
#define HOLD wait /* holding byte */
#define IPL_HOLD 0100000
extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern FILE *sim_log;
int32 ipl_ptime = 400; /* polling interval */
int32 ipl_stopioe = 0; /* stop on error */
DEVICE ipli_dev, iplo_dev;
int32 ipliio (int32 inst, int32 IR, int32 dat);
int32 iploio (int32 inst, int32 IR, int32 dat);
int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat);
t_stat ipl_svc (UNIT *uptr);
t_stat ipl_reset (DEVICE *dptr);
t_stat ipl_attach (UNIT *uptr, char *cptr);
t_stat ipl_detach (UNIT *uptr);
t_stat ipl_boot (int32 unitno, DEVICE *dptr);
t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc);
t_bool ipl_check_conn (UNIT *uptr);
/* IPLI data structures
ipli_dev IPLI device descriptor
ipli_unit IPLI unit descriptor
ipli_reg IPLI register list
*/
DIB ipl_dib[] = {
{ IPLI, 0, 0, 0, 0, &ipliio },
{ IPLO, 0, 0, 0, 0, &iploio } };
#define ipli_dib ipl_dib[0]
#define iplo_dib ipl_dib[1]
UNIT ipl_unit[] = {
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) },
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) } };
#define ipli_unit ipl_unit[0]
#define iplo_unit ipl_unit[1]
REG ipli_reg[] = {
{ ORDATA (BUF, ipli_unit.buf, 16) },
{ FLDATA (CMD, ipli_dib.cmd, 0) },
{ FLDATA (CTL, ipli_dib.ctl, 0) },
{ FLDATA (FLG, ipli_dib.flg, 0) },
{ FLDATA (FBF, ipli_dib.fbf, 0) },
{ ORDATA (HOLD, ipli_unit.HOLD, 16) },
{ DRDATA (TIME, ipl_ptime, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ipl_stopioe, 0) },
{ ORDATA (DEVNO, ipli_dib.devno, 6), REG_HRO },
{ NULL } };
MTAB ipl_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag },
{ UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT",
&ipl_dscln, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &ipli_dev },
{ 0 } };
DEVICE ipli_dev = {
"IPLI", &ipli_unit, ipli_reg, ipl_mod,
1, 10, 31, 1, 16, 16,
&tmxr_ex, &tmxr_dep, &ipl_reset,
&ipl_boot, &ipl_attach, &ipl_detach,
&ipli_dib, DEV_DISABLE | DEV_DIS };
/* IPLO data structures
iplo_dev IPLO device descriptor
iplo_unit IPLO unit descriptor
iplo_reg IPLO register list
*/
REG iplo_reg[] = {
{ ORDATA (BUF, iplo_unit.buf, 16) },
{ FLDATA (CMD, iplo_dib.cmd, 0) },
{ FLDATA (CTL, iplo_dib.ctl, 0) },
{ FLDATA (FLG, iplo_dib.flg, 0) },
{ FLDATA (FBF, iplo_dib.fbf, 0) },
{ ORDATA (HOLD, iplo_unit.HOLD, 16) },
{ DRDATA (TIME, ipl_ptime, 24), PV_LEFT },
{ ORDATA (DEVNO, iplo_dib.devno, 6), REG_HRO },
{ NULL } };
DEVICE iplo_dev = {
"IPLO", &iplo_unit, iplo_reg, ipl_mod,
1, 10, 31, 1, 16, 16,
&tmxr_ex, &tmxr_dep, &ipl_reset,
&ipl_boot, &ipl_attach, &ipl_detach,
&iplo_dib, DEV_DISABLE | DEV_DIS };
/* Interprocessor link I/O routines */
int32 ipliio (int32 inst, int32 IR, int32 dat)
{
return iplio (&ipli_unit, inst, IR, dat);
}
int32 iploio (int32 inst, int32 IR, int32 dat)
{
return iplio (&iplo_unit, inst, IR, dat);
}
int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat)
{
uint32 u, dev, odev;
int32 sta;
int8 msg[2];
dev = IR & I_DEVMASK; /* get device no */
switch (inst) { /* case on opcode */
case ioFLG: /* flag clear/set */
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
uptr->buf = dat;
break;
case ioLIX: /* load */
dat = uptr->buf; /* return val */
break;
case ioMIX: /* merge */
dat = dat | uptr->buf; /* get return data */
break;
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear ctl, cmd */
clrCTL (dev); }
else { /* STC */
setCMD (dev); /* set ctl, cmd */
setCTL (dev);
if (uptr->flags & UNIT_ATT) { /* attached? */
if ((uptr->flags & UNIT_ESTB) == 0) { /* established? */
if (!ipl_check_conn (uptr)) /* not established? */
return STOP_NOCONN; /* lose */
uptr->flags = uptr->flags | UNIT_ESTB; }
msg[0] = (uptr->buf >> 8) & 0377;
msg[1] = uptr->buf & 0377;
sta = sim_write_sock (uptr->DSOCKET, msg, 2);
if (sta == SOCKET_ERROR) {
printf ("IPL: socket write error\n");
return SCPE_IOERR; }
sim_os_sleep (0); }
else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */
u = (uptr - ipl_unit) ^ 1; /* find other device */
ipl_unit[u].buf = uptr->buf; /* output to other */
odev = ipl_dib[u].devno; /* other device no */
setFLG (odev); } /* set other flag */
else return SCPE_UNATT; } /* lose */
break;
default:
break; }
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
return dat;
}
/* Unit service - poll for input */
t_stat ipl_svc (UNIT *uptr)
{
int32 u, nb, dev;
int8 msg[2];
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */
sim_activate (uptr, ipl_ptime); /* reactivate */
if ((uptr->flags & UNIT_ESTB) == 0) { /* not established? */
if (!ipl_check_conn (uptr)) return SCPE_OK; /* check for conn */
uptr->flags = uptr->flags | UNIT_ESTB; }
nb = sim_read_sock (uptr->DSOCKET, msg, uptr->HOLD? 1: 2);
if (nb < 0) { /* connection closed? */
printf ("IPL: socket read error\n");
return SCPE_IOERR; }
if (nb == 0) return SCPE_OK; /* no data? */
if (uptr->HOLD) { /* holdover byte? */
uptr->buf = ((uptr->HOLD & 0377) << 8) | (((int32) msg[0]) & 0377);
uptr->HOLD = 0; }
else if (nb == 1) uptr->HOLD = (((int32) msg[0]) & 0377) | IPL_HOLD;
else uptr->buf = ((((int32) msg[0]) & 0377) << 8) |
(((int32) msg[1]) & 0377);
u = uptr - ipl_unit; /* get link number */
dev = ipl_dib[u].devno; /* get device number */
clrCMD (dev); /* clr cmd, set flag */
setFLG (dev);
return SCPE_OK;
}
t_bool ipl_check_conn (UNIT *uptr)
{
SOCKET sock;
if (uptr->flags & UNIT_ESTB) return TRUE; /* established? */
if (uptr->flags & UNIT_ACTV) { /* active connect? */
if (sim_check_conn (uptr->DSOCKET, 0) <= 0) return FALSE; }
else { sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */
if (sock == INVALID_SOCKET) return FALSE; /* got a live one? */
uptr->DSOCKET = sock; } /* save data socket */
uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */
return TRUE;
}
/* Reset routine */
t_stat ipl_reset (DEVICE *dptr)
{
DIB *dibp = (DIB *) dptr->ctxt;
UNIT *uptr = dptr->units;
hp_enbdis_pair (&ipli_dev, &iplo_dev); /* make pair cons */
dibp->cmd = dibp->ctl = 0; /* clear cmd, ctl */
dibp->flg = dibp->fbf = 1; /* set flg, fbf */
uptr->buf = uptr->HOLD = 0;
if (uptr->flags & UNIT_ATT) sim_activate (uptr, ipl_ptime);
else sim_cancel (uptr); /* deactivate unit */
return SCPE_OK;
}
/* Attach routine
attach -l - listen for connection on port
attach -c - connect to ip address and port
*/
t_stat ipl_attach (UNIT *uptr, char *cptr)
{
extern int32 sim_switches;
SOCKET newsock;
uint32 i, t, ipa, ipp, oldf;
char *tptr;
t_stat r;
r = get_ipaddr (cptr, &ipa, &ipp);
if ((r != SCPE_OK) || (ipp == 0)) return SCPE_ARG;
oldf = uptr->flags;
if (oldf & UNIT_ATT) ipl_detach (uptr);
if ((sim_switches & SWMASK ('C')) ||
((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {
if (ipa == 0) ipa = 0x7F000001;
newsock = sim_connect_sock (ipa, ipp);
if (newsock == INVALID_SOCKET) return SCPE_IOERR;
printf ("Connecting to IP address %d.%d.%d.%d, port %d\n",
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
if (sim_log) fprintf (sim_log,
"Connecting to IP address %d.%d.%d.%d, port %d\n",
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
uptr->flags = uptr->flags | UNIT_ACTV;
uptr->LSOCKET = 0;
uptr->DSOCKET = newsock; }
else { if (ipa != 0) return SCPE_ARG;
newsock = sim_master_sock (ipp);
if (newsock == INVALID_SOCKET) return SCPE_IOERR;
printf ("Listening on port %d\n", ipp);
if (sim_log) fprintf (sim_log, "Listening on port %d\n", ipp);
uptr->flags = uptr->flags & ~UNIT_ACTV;
uptr->LSOCKET = newsock;
uptr->DSOCKET = 0; }
uptr->buf = uptr->HOLD = 0;
uptr->flags = (uptr->flags | UNIT_ATT) & ~UNIT_ESTB; /* no more errors */
tptr = malloc (strlen (cptr) + 1); /* get string buf */
if (tptr == NULL) { /* no memory? */
ipl_detach (uptr); /* close sockets */
return SCPE_MEM; }
strcpy (tptr, cptr); /* copy ipaddr:port */
uptr->filename = tptr; /* save */
sim_activate (uptr, ipl_ptime); /* activate poll */
if (sim_switches & SWMASK ('W')) { /* wait? */
for (i = 0; i < 30; i++) { /* check for 30 sec */
if (t = ipl_check_conn (uptr)) break; /* established? */
if ((i % 10) == 0) /* status every 10 sec */
printf ("Waiting for connnection\n");
sim_os_sleep (1); } /* sleep 1 sec */
if (t) printf ("Connection established\n"); }
return SCPE_OK;
}
/* Detach routine */
t_stat ipl_detach (UNIT *uptr)
{
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
if (uptr->flags & UNIT_ACTV) sim_close_sock (uptr->DSOCKET, 1);
else { if (uptr->flags & UNIT_ESTB) /* if established, */
sim_close_sock (uptr->DSOCKET, 0); /* close data socket */
sim_close_sock (uptr->LSOCKET, 1); } /* closen listen socket */
free (uptr->filename); /* free string */
uptr->filename = NULL;
uptr->LSOCKET = 0;
uptr->DSOCKET = 0;
uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_ACTV | UNIT_ESTB);
sim_cancel (uptr); /* don't poll */
return SCPE_OK;
}
/* Disconnect routine */
t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (cptr) return SCPE_ARG;
if (((uptr->flags & UNIT_ATT) == 0) || (uptr->flags & UNIT_ACTV) ||
((uptr->flags & UNIT_ESTB) == 0)) return SCPE_NOFNC;
sim_close_sock (uptr->DSOCKET, 0);
uptr->DSOCKET = 0;
uptr->flags = uptr->flags & ~UNIT_ESTB;
return SCPE_OK;
}
/* Diagnostic/normal mode routine */
t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (val) {
ipli_unit.flags = ipli_unit.flags | UNIT_DIAG;
iplo_unit.flags = iplo_unit.flags | UNIT_DIAG; }
else { ipli_unit.flags = ipli_unit.flags & ~UNIT_DIAG;
iplo_unit.flags = iplo_unit.flags & ~UNIT_DIAG; }
return SCPE_OK;
}
/* Interprocessor link bootstrap routine (HP Access Manual) */
#define LDR_BASE 073
#define IPL_PNTR 074
#define PTR_PNTR 075
#define IPL_DEVA 076
#define PTR_DEVA 077
static const int32 pboot[IBL_LNT] = {
0163774, /*BBL LDA ICK,I ; IPL sel code */
0027751, /* JMP CFG ; go configure */
0107700, /*ST CLC 0,C ; intr off */
0002702, /* CLA,CCE,SZA ; skip in */
0063772, /*CN LDA M26 ; feed frame */
0002307, /*EOC CCE,INA,SZA,RSS ; end of file? */
0027760, /* JMP EOT ; yes */
0017736, /* JSB READ ; get #char */
0007307, /* CMB,CCE,INB,SZB,RSS ; 2's comp; null? */
0027705, /* JMP EOC ; read next */
0077770, /* STB WC ; word in rec */
0017736, /* JSB READ ; get feed frame */
0017736, /* JSB READ ; get address */
0074000, /* STB 0 ; init csum */
0077771, /* STB AD ; save addr */
0067771, /*CK LDB AD ; check addr */
0047773, /* ADB MAXAD ; below loader */
0002040, /* SEZ ; E =0 => OK */
0102055, /* HLT 55 */
0017736, /* JSB READ ; get word */
0040001, /* ADA 1 ; cont checksum */
0177771, /* STB AD,I ; store word */
0037771, /* ISZ AD */
0000040, /* CLE ; force wd read */
0037770, /* ISZ WC ; block done? */
0027717, /* JMP CK ; no */
0017736, /* JSB READ ; get checksum */
0054000, /* CPB 0 ; ok? */
0027704, /* JMP CN ; next block */
0102011, /* HLT 11 ; bad csum */
0000000, /*RD 0 */
0006600, /* CLB,CME ; E reg byte ptr */
0103700, /*IO1 STC RDR,C ; start reader */
0102300, /*IO2 SFS RDR ; wait */
0027741, /* JMP *-1 */
0106400, /*IO3 MIB RDR ; get byte */
0002041, /* SEZ,RSS ; E set? */
0127736, /* JMP RD,I ; no, done */
0005767, /* BLF,CLE,BLF ; shift byte */
0027740, /* JMP IO1 ; again */
0163775, /* LDA PTR,I ; get ptr code */
0043765, /*CFG ADA SFS ; config IO */
0073741, /* STA IO2 */
0043766, /* ADA STC */
0073740, /* STA IO1 */
0043767, /* ADA MIB */
0073743, /* STA IO3 */
0027702, /* JMP ST */
0063777, /*EOT LDA PSC ; put select codes */
0067776, /* LDB ISC ; where xloader wants */
0102077, /* HLT 77 */
0027702, /* JMP ST */
0000000, /* NOP */
0102300, /*SFS SFS 0 */
0001400, /*STC 1400 */
0002500, /*MIB 2500 */
0000000, /*WC 0 */
0000000, /*AD 0 */
0177746, /*M26 -26 */
0000000, /*MAX -BBL */
0007776, /*ICK ISC */
0007777, /*PTR IPT */
0000000, /*ISC 0 */
0000000 /*IPT 0 */
};
t_stat ipl_boot (int32 unitno, DEVICE *dptr)
{
int32 i, devi, devp;
extern DIB ptr_dib;
extern UNIT cpu_unit;
extern uint32 SR;
extern uint16 *M;
devi = ipli_dib.devno; /* get device no */
devp = ptr_dib.devno;
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
SR = (devi << IBL_V_DEV) | devp; /* set SR */
for (i = 0; i < IBL_LNT; i++) M[PC + i] = pboot[i]; /* copy bootstrap */
M[PC + LDR_BASE] = (~PC + 1) & DMASK; /* fix ups */
M[PC + IPL_PNTR] = M[PC + IPL_PNTR] | PC;
M[PC + PTR_PNTR] = M[PC + PTR_PNTR] | PC;
M[PC + IPL_DEVA] = devi;
M[PC + PTR_DEVA] = devp;
return SCPE_OK;
}

View file

@ -42,8 +42,8 @@
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
#define UNIT_DIAG (1 << UNIT_V_DIAG)
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
int32 lps_ctime = 1000; /* char time */
int32 lps_stopioe = 0; /* stop on error */
int32 lps_sta = 0;
@ -80,8 +80,8 @@ REG lps_reg[] = {
{ NULL } };
MTAB lps_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "DIAG", "DIAG", NULL },
{ UNIT_DIAG, 0, "PRINTER", "PRINTER", NULL },
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
{ UNIT_DIAG, 0, "printer mode", "PRINTER", NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &lps_dev },
{ 0 } };
@ -117,23 +117,24 @@ case ioLIX: /* load */
dat = 0; /* default sta = 0 */
case ioMIX: /* merge */
if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */
lps_sta = 0; /* create status */
if ((lps_unit.flags & UNIT_ATT) == 0)
lps_sta = lps_sta | LPS_BUSY | LPS_NRDY;
else if (sim_is_active (&lps_unit))
lps_sta = lps_sta | LPS_BUSY; }
lps_sta = 0; /* create status */
if ((lps_unit.flags & UNIT_ATT) == 0)
lps_sta = lps_sta | LPS_BUSY | LPS_NRDY;
else if (sim_is_active (&lps_unit))
lps_sta = lps_sta | LPS_BUSY; }
dat = dat | lps_sta; /* diag, rtn status */
break;
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear ctl, cmd */
clrCTL (dev); }
else { setCMD (dev); /* STC */
setCTL (dev); /* set ctl, cmd */
if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */
sim_activate (&lps_unit, 1); /* loop back */
else sim_activate (&lps_unit, /* real lpt, sched */
(lps_unit.buf < 040)? lps_unit.wait: lps_ctime); }
clrCMD (dev); /* clear ctl, cmd */
clrCTL (dev); }
else { /* STC */
setCMD (dev); /* set ctl, cmd */
setCTL (dev);
if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */
sim_activate (&lps_unit, 1); /* loop back */
else sim_activate (&lps_unit, /* real lpt, sched */
(lps_unit.buf < 040)? lps_unit.wait: lps_ctime); }
break;
default:
break; }

View file

@ -41,8 +41,8 @@
#define LPT_SKIPM 0000077 /* line count mask */
#define LPT_CHANM 0000007 /* channel mask */
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
int32 lpt_ctime = 1000; /* char time */
int32 lpt_stopioe = 0; /* stop on error */
int32 lpt_lcnt = 0; /* line count */
@ -117,19 +117,20 @@ case ioLIX: /* load */
dat = 0; /* default sta = 0 */
case ioMIX: /* merge */
if (lpt_unit.flags & UNIT_ATT) {
dat = dat | LPT_RDY;
if (!sim_is_active (&lpt_unit))
dat = dat | LPT_NBSY; }
dat = dat | LPT_RDY;
if (!sim_is_active (&lpt_unit))
dat = dat | LPT_NBSY; }
else dat = dat | LPT_PAPO;
break;
case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */
clrCMD (dev); /* clear ctl, cmd */
clrCTL (dev); }
else { setCMD (dev); /* STC */
setCTL (dev); /* set ctl, cmd */
sim_activate (&lpt_unit, /* schedule op */
(lpt_unit.buf & LPT_CTL)? lpt_unit.wait: lpt_ctime); }
clrCMD (dev); /* clear ctl, cmd */
clrCTL (dev); }
else { /* STC */
setCMD (dev); /* set ctl, cmd */
setCTL (dev);
sim_activate (&lpt_unit, /* schedule op */
(lpt_unit.buf & LPT_CTL)? lpt_unit.wait: lpt_ctime); }
break;
default:
break; }

View file

@ -111,8 +111,8 @@
#define STA_DYN (STA_PE|STA_SEL|STA_TBSY|STA_WLK|STA_LOCAL)
extern uint16 *M;
extern int32 PC, SR;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC, SR;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern int32 sim_switches;
extern UNIT cpu_unit;

View file

@ -88,8 +88,8 @@
#define STA_PAR 0002 /* parity error */
#define STA_BUSY 0001 /* busy (d) */
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
int32 mtc_fnc = 0; /* function */
int32 mtc_sta = 0; /* status register */
int32 mtc_dtf = 0; /* data xfer flop */

View file

@ -87,7 +87,7 @@
#define LIU_SEEK 0100000 /* seeking NI */
#define LIU_DG 0000010 /* diagnose */
#define LIU_BRK 0000004 /* break NI */
#define LIU_BRK 0000004 /* break */
#define LIU_LOST 0000002 /* char lost */
#define LIU_TR 0000001 /* trans/rcv */
@ -129,8 +129,8 @@
((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \
<< LIC_V_I)
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
uint16 mux_sta[MUX_LINES]; /* line status */
uint16 mux_rpar[MUX_LINES + MUX_ILINES]; /* rcv param */
@ -482,19 +482,26 @@ tmxr_poll_rx (&mux_desc); /* poll for input */
for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */
if (mux_ldsc[ln].conn) { /* connected? */
if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */
if (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST;
if (muxl_unit[ln].flags & UNIT_UC) { /* cvt to UC? */
c = c & 0177;
if (islower (c)) c = toupper (c); }
else c = c & ((muxl_unit[ln].flags & UNIT_8B)? 0377: 0177);
if (mux_rpar[ln] & OTL_ECHO) { /* echo? */
TMLN *lp = &mux_ldsc[ln]; /* get line */
tmxr_putc_ln (lp, c); /* output char */
tmxr_poll_tx (&mux_desc); } /* poll xmt */
if (c & SCPE_BREAK) { /* break? */
mux_sta[ln] = mux_sta[ln] | LIU_BRK;
mux_rbuf[ln] = 0; } /* no char */
else { /* normal */
if (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST;
if (muxl_unit[ln].flags & UNIT_UC) { /* cvt to UC? */
c = c & 0177;
if (islower (c)) c = toupper (c); }
else c = c & ((muxl_unit[ln].flags & UNIT_8B)? 0377: 0177);
if (mux_rpar[ln] & OTL_ECHO) { /* echo? */
TMLN *lp = &mux_ldsc[ln]; /* get line */
tmxr_putc_ln (lp, c); /* output char */
tmxr_poll_tx (&mux_desc); } /* poll xmt */
mux_rbuf[ln] = c; /* save char */
mux_rchp[ln] = 1; } /* char pending */
if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */
mux_rbuf[ln] = c; /* save char */
mux_rchp[ln] = 1; } } /* char pending */
else muxc_lia[ln] = 0; } /* disconnected */ /* end for */
} /* end if char */
} /* end if connected */
else muxc_lia[ln] = 0; /* disconnected */
} /* end for */
if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for data int */
if (!FLG (muxc_dib.devno)) mux_ctrl_int (); /* scan modem */
return SCPE_OK;
@ -584,9 +591,13 @@ void mux_diag (int32 c)
int32 i;
for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) {
if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST;
mux_rchp[i] = 1;
mux_rbuf[i] = c; }
if (c & SCPE_BREAK) { /* break? */
mux_sta[i] = mux_sta[i] | LIU_BRK;
mux_rbuf[i] = 0; } /* no char */
else {
if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST;
mux_rchp[i] = 1;
mux_rbuf[i] = c; } }
return;
}

View file

@ -28,6 +28,7 @@
tty 12531C buffered teleprinter interface
clk 12539C time base generator
22-Dec-02 RMS Added break support
01-Nov-02 RMS Revised BOOT command for IBL ROMs
Fixed bug in TTY reset, TTY starts in input mode
Fixed bug in TTY mode OTA, stores data as well
@ -77,8 +78,8 @@
#define CLK_ERROR (1 << CLK_V_ERROR)
extern uint16 *M;
extern int32 PC, SR;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern uint32 PC, SR;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern UNIT cpu_unit;
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
@ -263,8 +264,8 @@ REG clk_reg[] = {
{ NULL } };
MTAB clk_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "DIAG", "DIAG", NULL },
{ UNIT_DIAG, 0, "CALIBRATED", "CALIBRATED", NULL },
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
{ UNIT_DIAG, 0, "calibrated", "CALIBRATED", NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &clk_dev },
{ 0 } };
@ -350,8 +351,8 @@ return SCPE_OK;
/* Paper tape reader bootstrap routine (HP 12992K ROM) */
#define LDR_BASE 077
#define CHANGE_DEV (1 << 24)
#define CHANGE_ADDR (1 << 23)
static const int32 pboot[IBL_LNT] = {
0107700, /*ST CLC 0,C ; intr off */
@ -403,7 +404,7 @@ static const int32 pboot[IBL_LNT] = {
0177765, /*M11 -11 ; feed count */
0, 0, 0, 0, 0, 0, 0, 0, /* unused */
0, 0, 0, 0, 0, 0, 0, /* unused */
CHANGE_ADDR }; /*MAXAD -ST ; max addr */
0000000 }; /*MAXAD -ST ; max addr */
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
@ -413,11 +414,10 @@ dev = ptr_dib.devno; /* get device no */
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
SR = IBL_PTR + (dev << IBL_V_DEV); /* set SR */
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
if (pboot[i] & CHANGE_ADDR) /* memory limit? */
M[PC + i] = (-PC) & DMASK;
else if (pboot[i] & CHANGE_DEV) /* IO instr? */
if (pboot[i] & CHANGE_DEV) /* IO instr? */
M[PC + i] = (pboot[i] + dev) & DMASK;
else M[PC + i] = pboot[i]; }
else M[PC + i] = pboot[i]; }
M[PC + LDR_BASE] = (~PC + 1) & DMASK;
return SCPE_OK;
}
@ -564,7 +564,8 @@ int32 c, dev;
dev = tty_dib.devno; /* get device no */
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
if (tty_unit[TTI].flags & UNIT_UC) { /* UC only? */
if (c & SCPE_BREAK) c = 0; /* break? */
else if (tty_unit[TTI].flags & UNIT_UC) { /* UC only? */
c = c & 0177;
if (islower (c)) c = toupper (c); }
else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177);
@ -572,7 +573,7 @@ if (tty_mode & TM_KBD) { /* keyboard enabled? */
tty_buf = c; /* put char in buf */
tty_unit[TTI].pos = tty_unit[TTI].pos + 1;
setFLG (dev); /* set flag */
return tto_out (c); } /* echo or punch? */
if (c) return tto_out (c); } /* echo or punch? */
return SCPE_OK;
}

View file

@ -51,6 +51,7 @@ extern DEVICE dpd_dev, dpc_dev;
extern DEVICE dqd_dev, dqc_dev;
extern DEVICE drd_dev, drc_dev;
extern DEVICE muxl_dev, muxu_dev, muxc_dev;
extern DEVICE ipli_dev, iplo_dev;
extern REG cpu_reg[];
extern uint16 *M;
@ -86,6 +87,7 @@ DEVICE *sim_devices[] = {
&mtd_dev, &mtc_dev,
&msd_dev, &msc_dev,
&muxl_dev, &muxu_dev, &muxc_dev,
&ipli_dev, &iplo_dev,
NULL };
const char *sim_stop_messages[] = {
@ -95,7 +97,8 @@ const char *sim_stop_messages[] = {
"HALT instruction",
"Breakpoint",
"Indirect address loop",
"Indirect address interrupt (should not happen!)" };
"Indirect address interrupt (should not happen!)",
"No connection on interprocessor link" };
/* Binary loader

View file

@ -521,7 +521,7 @@ unit = (t == BCD_ZERO)? 0: t; /* save char as unit */
xa = (AS >> V_INDEX) & M_INDEX; /* get index reg */
if (xa && (D != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */
AS = AS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] +
one_table[M[xa + 2] & CHAR];
one_table[M[xa + 2] & CHAR];
AS = (AS & INDEXMASK) % MAXMEMSIZE; }
if (!(flags & MLS)) BS = AS; /* not MLS? B = A */
PP (IS);
@ -544,8 +544,8 @@ if ((t = M[IS]) & WM) { /* WM? 6 char inst */
BS = BS + one_table[t]; /* finish B addr */
xa = (BS >> V_INDEX) & M_INDEX; /* get index reg */
if (xa && (cpu_unit.flags & XSA)) { /* indexed? */
BS = BS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR]
+ one_table[M[xa + 2] & CHAR];
BS = BS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] +
one_table[M[xa + 2] & CHAR];
BS = (BS & INDEXMASK) % MAXMEMSIZE; }
PP (IS);
@ -580,55 +580,65 @@ switch (op) { /* case on opcode */
case OP_MCW: /* move char */
if (ilnt >= 8) { /* I/O form? */
reason = iodisp (dev, unit, MD_NORM, D);
break; }
reason = iodisp (dev, unit, MD_NORM, D);
break; }
if (ADDR_ERR (AS)) { /* check A addr */
reason = STOP_INVA;
break; }
do { M[BS] = (M[BS] & WM) | (M[AS] & CHAR); /* move char */
wm = M[AS] | M[BS];
MM (AS); MM (BS); } /* decr pointers */
reason = STOP_INVA;
break; }
do {
M[BS] = (M[BS] & WM) | (M[AS] & CHAR); /* move char */
wm = M[AS] | M[BS];
MM (AS); MM (BS); } /* decr pointers */
while ((wm & WM) == 0); /* stop on A,B WM */
break;
case OP_LCA: /* load char */
if (ilnt >= 8) { /* I/O form? */
reason = iodisp (dev, unit, MD_WM, D);
break; }
reason = iodisp (dev, unit, MD_WM, D);
break; }
if (ADDR_ERR (AS)) { /* check A addr */
reason = STOP_INVA;
break; }
do { wm = M[BS] = M[AS]; /* move char + wmark */
MM (AS); MM (BS); } /* decr pointers */
reason = STOP_INVA;
break; }
do {
wm = M[BS] = M[AS]; /* move char + wmark */
MM (AS); MM (BS); } /* decr pointers */
while ((wm & WM) == 0); /* stop on A WM */
break;
case OP_MCM: /* move to rec/group */
do { M[BS] = (M[BS] & WM) | (M[AS] & CHAR); /* move char */
t = M[AS];
PP (AS); PP (BS); } /* incr pointers */
do {
M[BS] = (M[BS] & WM) | (M[AS] & CHAR); /* move char */
t = M[AS];
PP (AS); PP (BS); } /* incr pointers */
while (((t & CHAR) != BCD_RECMRK) && (t != (BCD_GRPMRK + WM)));
break;
case OP_MSZ: /* move suppress zero */
bsave = BS; /* save B start */
qzero = 1; /* set suppress */
do { M[BS] = M[AS] & ((BS != bsave)? CHAR: DIGIT); /* copy char */
wm = M[AS];
MM (AS); MM (BS); } /* decr pointers */
do {
M[BS] = M[AS] & ((BS != bsave)? CHAR: DIGIT); /* copy char */
wm = M[AS];
MM (AS); MM (BS); } /* decr pointers */
while ((wm & WM) == 0); /* stop on A WM */
if (reason) break; /* addr err? stop */
do { PP (BS); /* adv B */
t = M[BS]; /* get B, cant be WM */
if ((t == BCD_ZERO) || (t == BCD_COMMA)) {
if (qzero) M[BS] = 0; }
else if ((t == BCD_BLANK) || (t == BCD_MINUS)) ;
else if (((t == BCD_DECIMAL) && (cpu_unit.flags & EPE)) ||
(t <= BCD_NINE)) qzero = 0;
else qzero = 1; }
do {
PP (BS); /* adv B */
t = M[BS]; /* get B, cant be WM */
if ((t == BCD_ZERO) || (t == BCD_COMMA)) {
if (qzero) M[BS] = 0; }
else if ((t == BCD_BLANK) || (t == BCD_MINUS)) ;
else if (((t == BCD_DECIMAL) && (cpu_unit.flags & EPE)) ||
(t <= BCD_NINE)) qzero = 0;
else qzero = 1; }
while (BS <= bsave);
break;
case OP_MN: /* move numeric */
M[BS] = (M[BS] & ~DIGIT) | (M[AS] & DIGIT); /* move digit */
MM (AS); MM (BS); /* decr pointers */
break;
case OP_MZ: /* move zone */
M[BS] = (M[BS] & ~ZONE) | (M[AS] & ZONE); /* move high bits */
MM (AS); MM (BS); /* decr pointers */
@ -641,23 +651,24 @@ case OP_MZ: /* move zone */
case OP_C: /* compare */
if (ilnt != 1) { /* if not chained */
ind[IN_EQU] = 1; /* clear indicators */
ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0; }
do { a = M[AS]; /* get characters */
b = M[BS];
wm = a | b; /* get word marks */
if ((a & CHAR) != (b & CHAR)) { /* unequal? */
ind[IN_EQU] = 0; /* set indicators */
ind[IN_UNQ] = 1;
ind[IN_HGH] = col_table[b & CHAR] > col_table [a & CHAR];
ind[IN_LOW] = ind[IN_HGH] ^ 1; }
MM (AS); MM (BS); } /* decr pointers */
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; }
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;
ind[IN_EQU] = ind[IN_LOW] = ind[IN_HGH] = 0;
break;
/* Branch instructions A check B check
@ -673,23 +684,26 @@ case OP_C: /* compare */
case OP_B: /* branch */
if (ilnt == 4) { BRANCH; } /* uncond branch? */
else if (ilnt == 5) { /* branch on ind? */
if (ind[D]) { BRANCH; } /* test indicator */
if (ind_table[D]) ind[D] = 0; } /* reset if needed */
else { if (ADDR_ERR (BS)) { /* branch char eq */
reason = STOP_INVB; /* validate B addr */
break; }
if ((M[BS] & CHAR) == D) { BRANCH; } /* char equal? */
else { MM (BS); } }
if (ind[D]) { BRANCH; } /* test indicator */
if (ind_table[D]) ind[D] = 0; } /* reset if needed */
else {
if (ADDR_ERR (BS)) { /* branch char eq */
reason = STOP_INVB; /* validate B addr */
break; }
if ((M[BS] & CHAR) == D) { BRANCH; } /* char equal? */
else { MM (BS); } }
break;
case OP_BWZ: /* branch wm or zone */
if (((D & 1) && (M[BS] & WM)) || /* d1? test wm */
((D & 2) && ((M[BS] & ZONE) == (D & ZONE)))) /* d2? test zone */
{ BRANCH; }
else { MM (BS); } /* decr pointer */
else { MM (BS); } /* decr pointer */
break;
case OP_BBE: /* branch if bit eq */
if (M[BS] & D & CHAR) { BRANCH; } /* any bits set? */
else { MM (BS); } /* decr pointer */
else { MM (BS); } /* decr pointer */
break;
/* Arithmetic instructions A check B check
@ -704,16 +718,19 @@ case OP_BBE: /* branch if bit eq */
case OP_ZA: case OP_ZS: /* zero and add/sub */
a = i = 0; /* clear flags */
do { if (a & WM) wm = M[BS] = (M[BS] & WM) | BCD_ZERO;
else { a = M[AS]; /* get A char */
t = (a & CHAR)? bin_to_bcd[a & DIGIT]: 0;
wm = M[BS] = (M[BS] & WM) | t; /* move digit */
MM (AS); }
if (i == 0) i = M[BS] = M[BS] |
((((a & ZONE) == BBIT) ^ (op == OP_ZS))? BBIT: ZONE);
MM (BS); }
do {
if (a & WM) wm = M[BS] = (M[BS] & WM) | BCD_ZERO;
else {
a = M[AS]; /* get A char */
t = (a & CHAR)? bin_to_bcd[a & DIGIT]: 0;
wm = M[BS] = (M[BS] & WM) | t; /* move digit */
MM (AS); }
if (i == 0) i = M[BS] = M[BS] |
((((a & ZONE) == BBIT) ^ (op == OP_ZS))? BBIT: ZONE);
MM (BS); }
while ((wm & WM) == 0); /* stop on B WM */
break;
case OP_A: case OP_S: /* add/sub */
bsave = BS; /* save sign pos */
a = M[AS]; /* get A digit/sign */
@ -728,30 +745,32 @@ case OP_A: case OP_S: /* add/sub */
M[BS] = b; /* store result */
MM (BS);
if (b & WM) { /* b wm? done */
if (qsign && (carry == 0)) M[bsave] = /* compl, no carry? */
WM + ((b & ZONE) ^ ABIT) + sum_table[10 - t];
break; }
do { if (a & WM) a = WM; /* A WM? char = 0 */
else { a = M[AS]; /* else get A */
MM (AS); }
b = M[BS]; /* get B */
t = bcd_to_bin[a & DIGIT]; /* get A binary */
t = bcd_to_bin[b & DIGIT] + (qsign? 9 - t: t) + carry;
carry = (t >= 10); /* get carry */
if ((b & WM) && (qsign == 0)) { /* last, no recomp? */
M[BS] = WM + sum_table[t] + /* zone add */
(((a & ZONE) + b + (carry? ABIT: 0)) & ZONE);
ind[IN_OVF] = carry; } /* ovflo if carry */
else M[BS] = (b & WM) + sum_table[t]; /* normal add */
MM (BS); }
if (qsign && (carry == 0)) M[bsave] = /* compl, no carry? */
WM + ((b & ZONE) ^ ABIT) + sum_table[10 - t];
break; }
do {
if (a & WM) a = WM; /* A WM? char = 0 */
else {
a = M[AS]; /* else get A */
MM (AS); }
b = M[BS]; /* get B */
t = bcd_to_bin[a & DIGIT]; /* get A binary */
t = bcd_to_bin[b & DIGIT] + (qsign? 9 - t: t) + carry;
carry = (t >= 10); /* get carry */
if ((b & WM) && (qsign == 0)) { /* last, no recomp? */
M[BS] = WM + sum_table[t] + /* zone add */
(((a & ZONE) + b + (carry? ABIT: 0)) & ZONE);
ind[IN_OVF] = carry; } /* ovflo if carry */
else M[BS] = (b & WM) + sum_table[t]; /* normal add */
MM (BS); }
while ((b & WM) == 0); /* stop on B WM */
if (reason) break; /* address err? */
if (qsign && (carry == 0)) { /* recompl, no carry? */
M[bsave] = M[bsave] ^ ABIT; /* XOR sign */
for (carry = 1; bsave != BS; --bsave) { /* rescan */
t = 9 - bcd_to_bin[M[bsave] & DIGIT] + carry;
carry = (t >= 10);
M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t]; } }
M[bsave] = M[bsave] ^ ABIT; /* XOR sign */
for (carry = 1; bsave != BS; --bsave) { /* rescan */
t = 9 - bcd_to_bin[M[bsave] & DIGIT] + carry;
carry = (t >= 10);
M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t]; } }
break;
/* I/O instructions A check B check
@ -776,18 +795,21 @@ case OP_R: /* read */
BS = CDR_BUF + CDR_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
break;
case OP_W: /* write */
if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */
reason = write_line (ilnt, D); /* print line */
BS = LPT_BUF + LPT_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
break;
case OP_P: /* punch */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
reason = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH;
if (ilnt >= 4) { BRANCH; } /* check for branch */
break;
case OP_WR: /* write and read */
if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */
reason = write_line (ilnt, D); /* print line */
@ -796,6 +818,7 @@ case OP_WR: /* write and read */
if (ilnt >= 4) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = r1; /* merge errors */
break;
case OP_WP: /* write and punch */
if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */
reason = write_line (ilnt, D); /* print line */
@ -804,6 +827,7 @@ case OP_WP: /* write and punch */
if (ilnt >= 4) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = r1; /* merge errors */
break;
case OP_RP: /* read and punch */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
reason = read_card (ilnt, D); /* read card */
@ -812,6 +836,7 @@ case OP_RP: /* read and punch */
if (ilnt >= 4) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = r1; /* merge errors */
break;
case OP_WRP: /* write, read, punch */
if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */
reason = write_line (ilnt, D); /* print line */
@ -821,19 +846,23 @@ case OP_WRP: /* write, read, punch */
if (ilnt >= 4) { BRANCH; } /* check for branch */
if (reason == SCPE_OK) reason = (r1 == SCPE_OK)? r2: r1;
break;
case OP_SS: /* select stacker */
if (reason = iomod (ilnt, D, ss_mod)) break; /* valid modifier? */
if (reason = select_stack (D)) break; /* sel stack, error? */
if (ilnt >= 4) { BRANCH; } /* check for branch */
break;
case OP_CC: /* carriage control */
if (reason = carriage_control (D)) break; /* car ctrl, error? */
if (ilnt >= 4) { BRANCH; } /* check for branch */
break;
case OP_MTF: /* magtape function */
if (reason = iomod (ilnt, D, mtf_mod)) break; /* valid modifier? */
if (reason = mt_func (unit, D)) break; /* mt func, error? */
break; /* can't branch */
case OP_RF: case OP_PF: /* read, punch feed */
break; /* nop's */
@ -864,11 +893,11 @@ case OP_MCE: /* edit */
a = M[AS]; /* get A char */
b = M[BS]; /* get B char */
if (a & WM) { /* one char A field? */
reason = STOP_MCE1;
break; }
reason = STOP_MCE1;
break; }
if (b & WM) { /* one char B field? */
reason = STOP_MCE2;
break; }
reason = STOP_MCE2;
break; }
t = a & DIGIT; MM (AS); /* get A digit */
qsign = ((a & ZONE) == BBIT); /* get A field sign */
qawm = qzero = qbody = 0; /* clear other flags */
@ -886,78 +915,81 @@ case OP_MCE: /* edit */
& blank B
*/
do { b = M[BS]; /* get B char */
M[BS] = M[BS] & ~WM; /* clr WM */
switch (b & CHAR) { /* case on B char */
case BCD_ASTER: /* * */
if (!qbody || qdollar || !(cpu_unit.flags & EPE)) break;
qaster = 1; /* flag */
goto A_CYCLE; /* take A cycle */
case BCD_DOLLAR: /* $ */
if (!qbody || qaster || !(cpu_unit.flags & EPE)) break;
qdollar = 1; /* flag */
goto A_CYCLE; /* take A cycle */
case BCD_ZERO: /* 0 */
if (qawm && !qzero && !(b & WM)) {
M[BS] = BCD_ZERO + WM; /* mark with WM */
qzero = 1; /* flag supress */
break; }
if (!qzero) t = t | WM; /* first? set WM */
qzero = 1; /* flag supress */
do {
b = M[BS]; /* get B char */
M[BS] = M[BS] & ~WM; /* clr WM */
switch (b & CHAR) { /* case on B char */
case BCD_ASTER: /* * */
if (!qbody || qdollar || !(cpu_unit.flags & EPE)) break;
qaster = 1; /* flag */
goto A_CYCLE; /* take A cycle */
case BCD_DOLLAR: /* $ */
if (!qbody || qaster || !(cpu_unit.flags & EPE)) break;
qdollar = 1; /* flag */
goto A_CYCLE; /* take A cycle */
case BCD_ZERO: /* 0 */
if (qawm && !qzero && !(b & WM)) {
M[BS] = BCD_ZERO + WM; /* mark with WM */
qzero = 1; /* flag supress */
break; }
if (!qzero) t = t | WM; /* first? set WM */
qzero = 1; /* flag supress */
/* fall through */
case BCD_BLANK: /* blank */
if (qawm) break; /* any A left? */
A_CYCLE:
M[BS] = t; /* copy char */
if (a & WM) { /* end of A field? */
qbody = 0; /* end body */
qawm = 1; }
else { qbody = 1; /* in body */
a = M[AS]; MM (AS); /* next A */
t = a & CHAR; }
break;
case BCD_C: case BCD_R: case BCD_MINUS: /* C, R, - */
if (!qsign && !qbody) M[BS] = BCD_BLANK;
break;
case BCD_COMMA: /* , */
if (!qbody) M[BS] = BCD_BLANK; /* bl if status */
break;
case BCD_AMPER: /* & */
M[BS] = BCD_BLANK; /* blank B field */
break; } /* end switch */
MM (BS); } /* decr B pointer */
case BCD_BLANK: /* blank */
if (qawm) break; /* any A left? */
A_CYCLE:
M[BS] = t; /* copy char */
if (a & WM) { /* end of A field? */
qbody = 0; /* end body */
qawm = 1; }
else {
qbody = 1; /* in body */
a = M[AS]; MM (AS); /* next A */
t = a & CHAR; }
break;
case BCD_C: case BCD_R: case BCD_MINUS: /* C, R, - */
if (!qsign && !qbody) M[BS] = BCD_BLANK;
break;
case BCD_COMMA: /* , */
if (!qbody) M[BS] = BCD_BLANK; /* bl if status */
break;
case BCD_AMPER: /* & */
M[BS] = BCD_BLANK; /* blank B field */
break; } /* end switch */
MM (BS); } /* decr B pointer */
while ((b & WM) == 0); /* stop on B WM */
if (reason) break; /* address err? */
if (!qawm || !qzero) { /* rescan? */
if (qdollar) reason = STOP_MCE3; /* error if $ */
break; }
if (qdollar) reason = STOP_MCE3; /* error if $ */
break; }
/* Edit pass 2 - from left to right, supressing zeroes */
do { b = M[++BS]; /* get B char */
switch (b & CHAR) { /* case on B char */
case BCD_ONE: case BCD_TWO: case BCD_THREE:
case BCD_FOUR: case BCD_FIVE: case BCD_SIX:
case BCD_SEVEN: case BCD_EIGHT: case BCD_NINE:
qzero = 0; /* turn off supr */
break;
case BCD_ZERO: case BCD_COMMA: /* 0 or , */
if (qzero && !qdecimal) /* if supr, blank */
M[BS] = qaster? BCD_ASTER: BCD_BLANK;
break;
case BCD_BLANK: /* blank */
if (qaster) M[BS] = BCD_ASTER; /* if EPE *, repl */
break;
case BCD_DECIMAL: /* . */
if (qzero && (cpu_unit.flags & EPE))
qdecimal = 1; /* flag for EPE */
case BCD_PERCNT: case BCD_WM: case BCD_BS:
case BCD_TS: case BCD_MINUS:
break; /* ignore */
default: /* other */
qzero = 1; /* restart supr */
break; } } /* end case, do */
do {
b = M[++BS]; /* get B char */
switch (b & CHAR) { /* case on B char */
case BCD_ONE: case BCD_TWO: case BCD_THREE:
case BCD_FOUR: case BCD_FIVE: case BCD_SIX:
case BCD_SEVEN: case BCD_EIGHT: case BCD_NINE:
qzero = 0; /* turn off supr */
break;
case BCD_ZERO: case BCD_COMMA: /* 0 or , */
if (qzero && !qdecimal) /* if supr, blank */
M[BS] = qaster? BCD_ASTER: BCD_BLANK;
break;
case BCD_BLANK: /* blank */
if (qaster) M[BS] = BCD_ASTER; /* if EPE *, repl */
break;
case BCD_DECIMAL: /* . */
if (qzero && (cpu_unit.flags & EPE))
qdecimal = 1; /* flag for EPE */
case BCD_PERCNT: case BCD_WM: case BCD_BS:
case BCD_TS: case BCD_MINUS:
break; /* ignore */
default: /* other */
qzero = 1; /* restart supr */
break; } } /* end case, do */
while ((b & WM) == 0);
M[BS] = M[BS] & ~WM; /* clear B WM */
@ -967,16 +999,16 @@ case OP_MCE: /* edit */
/* Edit pass 3 (extended print only) - from right to left */
for (;; ) { /* until chars */
b = M[BS]; /* get B char */
if ((b == BCD_BLANK) && qdollar) { /* blank & flt $? */
M[BS] = BCD_DOLLAR; /* insert $ */
break; } /* exit for */
if (b == BCD_DECIMAL) { /* decimal? */
M[BS] = qaster? BCD_ASTER: BCD_BLANK;
break; } /* exit for */
if ((b == BCD_ZERO) && !qdollar) /* 0 & ~flt $ */
M[BS] = qaster? BCD_ASTER: BCD_BLANK;
BS--; } /* end for */
b = M[BS]; /* get B char */
if ((b == BCD_BLANK) && qdollar) { /* blank & flt $? */
M[BS] = BCD_DOLLAR; /* insert $ */
break; } /* exit for */
if (b == BCD_DECIMAL) { /* decimal? */
M[BS] = qaster? BCD_ASTER: BCD_BLANK;
break; } /* exit for */
if ((b == BCD_ZERO) && !qdollar) /* 0 & ~flt $ */
M[BS] = qaster? BCD_ASTER: BCD_BLANK;
BS--; } /* end for */
break; /* done at last! */
/* Multiply. Comments from the PDP-10 based simulator by Len Fehskens.
@ -995,9 +1027,10 @@ case OP_MCE: /* edit */
case OP_MUL:
asave = AS; bsave = lowprd = BS; /* save AS, BS */
do { a = M[AS]; /* get mpcd char */
M[BS] = BCD_ZERO; /* zero prod */
MM (AS); MM (BS); } /* decr pointers */
do {
a = M[AS]; /* get mpcd char */
M[BS] = BCD_ZERO; /* zero prod */
MM (AS); MM (BS); } /* decr pointers */
while ((a & WM) == 0); /* until A WM */
if (reason) break; /* address err? */
M[BS] = BCD_ZERO; /* zero hi prod */
@ -1009,23 +1042,25 @@ case OP_MUL:
AS and ps cannot produce an address error.
*/
do { ps = bsave; /* ptr to prod */
AS = asave; /* ptr to mpcd */
carry = 0; /* init carry */
b = M[BS]; /* get mpyr char */
do { a = M[AS]; /* get mpcd char */
t = (bcd_to_bin[a & DIGIT] * /* mpyr * mpcd */
bcd_to_bin[b & DIGIT]) + /* + c + partial prod */
carry + bcd_to_bin[M[ps] & DIGIT];
carry = cry_table[t];
M[ps] = (M[ps] & WM) | sum_table[t];
MM (AS); ps--; }
while ((a & WM) == 0); /* until mpcd done */
M[BS] = (M[BS] & WM) | BCD_ZERO; /* zero mpyr just used */
t = bcd_to_bin[M[ps] & DIGIT] + carry; /* add carry to prod */
M[ps] = (M[ps] & WM) | sum_table[t]; /* store */
bsave--; /* adv prod ptr */
MM (BS); } /* adv mpyr ptr */
do {
ps = bsave; /* ptr to prod */
AS = asave; /* ptr to mpcd */
carry = 0; /* init carry */
b = M[BS]; /* get mpyr char */
do {
a = M[AS]; /* get mpcd char */
t = (bcd_to_bin[a & DIGIT] * /* mpyr * mpcd */
bcd_to_bin[b & DIGIT]) + /* + c + partial prod */
carry + bcd_to_bin[M[ps] & DIGIT];
carry = cry_table[t];
M[ps] = (M[ps] & WM) | sum_table[t];
MM (AS); ps--; }
while ((a & WM) == 0); /* until mpcd done */
M[BS] = (M[BS] & WM) | BCD_ZERO; /* zero mpyr just used */
t = bcd_to_bin[M[ps] & DIGIT] + carry; /* add carry to prod */
M[ps] = (M[ps] & WM) | sum_table[t]; /* store */
bsave--; /* adv prod ptr */
MM (BS); } /* adv mpyr ptr */
while ((b & WM) == 0); /* until mpyr done */
M[lowprd] = M[lowprd] | ZONE; /* assume + */
if (sign) M[lowprd] = M[lowprd] & ~ABIT; /* if minus, B only */
@ -1058,24 +1093,26 @@ case OP_MUL:
case OP_DIV:
asave = AS; ahigh = -1;
do { a = M[AS]; /* get dvr char */
if ((a & CHAR) != BCD_ZERO) ahigh = AS; /* mark non-zero */
MM (AS); }
do {
a = M[AS]; /* get dvr char */
if ((a & CHAR) != BCD_ZERO) ahigh = AS; /* mark non-zero */
MM (AS); }
while ((a & WM) == 0);
if (reason) break; /* address err? */
if (ahigh < 0) { /* div? by zero */
ind[IN_OVF] = 1; /* set ovf indic */
qs = bsave = BS; /* quo, dividend */
do { b = M[bsave]; /* find end divd */
PP (bsave); } /* marked by zone */
while ((b & ZONE) == 0);
if (reason) break; /* address err? */
if (ADDR_ERR (qs)) { /* address err? */
reason = STOP_WRAP; /* address wrap? */
break; }
div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */
BS = (BS - 2) - (asave - (AS + 1)); /* final bs */
break; }
ind[IN_OVF] = 1; /* set ovf indic */
qs = bsave = BS; /* quo, dividend */
do {
b = M[bsave]; /* find end divd */
PP (bsave); } /* marked by zone */
while ((b & ZONE) == 0);
if (reason) break; /* address err? */
if (ADDR_ERR (qs)) { /* address err? */
reason = STOP_WRAP; /* address wrap? */
break; }
div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */
BS = (BS - 2) - (asave - (AS + 1)); /* final bs */
break; }
bsave = BS + (asave - ahigh); /* end subdivd */
qs = (BS - 2) - (ahigh - (AS + 1)); /* quo start */
@ -1087,17 +1124,19 @@ case OP_DIV:
qs = current quotient digit
*/
do { quo = 0; /* clear quo digit */
if (ADDR_ERR (qs) || ADDR_ERR (bsave)) {
reason = STOP_WRAP; /* address wrap? */
break; }
b = M[bsave]; /* save low divd */
do { t = div_sub (asave, bsave, ahigh); /* subtract */
quo++; } /* incr quo digit */
while (t == 0); /* until borrow */
div_add (asave, bsave, ahigh); quo--; /* restore */
M[qs] = (M[qs] & WM) | sum_table[quo]; /* store quo digit */
bsave++; qs++; } /* adv divd, quo */
do {
quo = 0; /* clear quo digit */
if (ADDR_ERR (qs) || ADDR_ERR (bsave)) {
reason = STOP_WRAP; /* address wrap? */
break; }
b = M[bsave]; /* save low divd */
do {
t = div_sub (asave, bsave, ahigh); /* subtract */
quo++; } /* incr quo digit */
while (t == 0); /* until borrow */
div_add (asave, bsave, ahigh); quo--; /* restore */
M[qs] = (M[qs] & WM) | sum_table[quo]; /* store quo digit */
bsave++; qs++; } /* adv divd, quo */
while ((b & ZONE) == 0); /* until B sign */
if (reason) break; /* address err? */
@ -1131,17 +1170,20 @@ case OP_SWM: /* set word mark */
M[AS] = M[AS] | WM; /* set B field mark */
MM (AS); MM (BS); /* decr pointers */
break;
case OP_CWM: /* clear word mark */
M[BS] = M[BS] & ~WM; /* clear A field mark */
M[AS] = M[AS] & ~WM; /* clear B field mark */
MM (AS); MM (BS); /* decr pointers */
break;
case OP_CS: /* clear storage */
t = (BS / 100) * 100; /* lower bound */
while (BS >= t) M[BS--] = 0; /* clear region */
if (BS < 0) BS = BS + MEMSIZE; /* wrap if needed */
if (ilnt >= 7) { BRANCH; } /* branch variant? */
break;
case OP_MA: /* modify address */
a = one_table[M[AS] & CHAR]; MM (AS); /* get A address */
a = a + ten_table[M[AS] & CHAR]; MM (AS);
@ -1155,18 +1197,22 @@ case OP_MA: /* modify address */
M[BS + 1] = (M[BS + 1] & WM) | store_addr_h (t);
if (((a % 4000) + (b % 4000)) >= 4000) BS = BS + 2; /* carry? */
break;
case OP_SAR: case OP_SBR: /* store A, B reg */
M[AS] = (M[AS] & WM) | store_addr_u (BS); MM (AS);
M[AS] = (M[AS] & WM) | store_addr_t (BS); MM (AS);
M[AS] = (M[AS] & WM) | store_addr_h (BS); MM (AS);
break;
case OP_NOP: /* nop */
break;
case OP_H: /* halt */
if (ilnt >= 4) { BRANCH; } /* branch if called */
reason = STOP_HALT; /* stop simulator */
saved_IS = IS; /* commit instruction */
break;
default:
reason = STOP_NXI; /* unimplemented */
break; } /* end switch */

View file

@ -203,12 +203,12 @@ if ((fnc == FNC_SEEK) && /* seek and */
if (diff < 0) return STOP_INVDSC; /* error? */
diff = diff >> 1; /* diff is *2 */
if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT)
diff = -diff; /* get sign */
diff = -diff; /* get sign */
uptr->CYL = uptr->CYL + diff; /* bound seek */
if (uptr->CYL < 0) uptr->CYL = 0;
else if (uptr->CYL >= DP_NUMCY) { /* too big? */
uptr->CYL = 0; /* system hangs */
return STOP_INVDCY; }
uptr->CYL = 0; /* system hangs */
return STOP_INVDCY; }
sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */
return SCPE_OK; } /* done! */
@ -217,7 +217,7 @@ if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */
return STOP_INVDSC;
if (fnc == FNC_SEEK) { /* seek? */
uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */
DP_NUMCY;
DP_NUMCY;
sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */
return SCPE_OK; } /* done! */
@ -229,10 +229,11 @@ if (cnt < 0) return STOP_INVDCN; /* bad count? */
if (fnc >= FNC_WOFF) return STOP_INVDFN; /* invalid func */
if (mod == BCD_W) { /* write? */
if (fnc == FNC_CHECK) { /* write check? */
qwc = 1; /* special read */
fnc = dp_lastf; } /* use last func */
else { dp_lastf = fnc; /* save func */
fnc = fnc + FNC_WOFF; } } /* change to write */
qwc = 1; /* special read */
fnc = dp_lastf; } /* use last func */
else {
dp_lastf = fnc; /* save func */
fnc = fnc + FNC_WOFF; } } /* change to write */
else if (mod == BCD_R) dp_lastf = fnc; /* read? save func */
else return STOP_INVM; /* other? error */
@ -311,8 +312,8 @@ if (r == SCPE_OK) { /* normal so far? */
BS++; /* advance BS */
if (ADDR_ERR (BS)) return STOP_WRAP; /* address error? */
if (M[BS - 1] != (WM + BCD_GRPMRK)) { /* GM + WM at end? */
ind[IN_LNG] = ind[IN_DSK] = 1; /* no, error */
r = STOP_INVDLN; } }
ind[IN_LNG] = ind[IN_DSK] = 1; /* no, error */
r = STOP_INVDLN; } }
CRETIOE (iochk || !ind[IN_DSK], r); /* return status */
}
@ -330,18 +331,18 @@ static const int32 dec_tab[DP_ADDR] = /* powers of 10 */
for (i = 0; i < DP_ADDR; i++) { /* copy address */
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
if (zad) { /* addr zero? */
ac = sec / dec_tab[i]; /* get addr digit */
sec = sec % dec_tab[i]; /* get remainder */
ac = bcd_to_bin[ac]; } /* cvt to BCD */
ac = sec / dec_tab[i]; /* get addr digit */
sec = sec % dec_tab[i]; /* get remainder */
ac = bcd_to_bin[ac]; } /* cvt to BCD */
else ac = *ap; /* addr char */
if (qwc) { /* wr chk? skip if zad */
if (!zad && (flg? (M[BS] != ac): /* L? cmp with WM */
((M[BS] & CHAR) != (ac & CHAR)))) { /* M? cmp w/o WM */
ind[IN_DPW] = ind[IN_DSK] = 1;
return STOP_WRCHKE; } }
if (!zad && (flg? (M[BS] != ac): /* L? cmp with WM */
((M[BS] & CHAR) != (ac & CHAR)))) { /* M? cmp w/o WM */
ind[IN_DPW] = ind[IN_DSK] = 1;
return STOP_WRCHKE; } }
else if (flg) M[BS] = ac & CHAR; /* load mode */
else M[BS] = (M[BS] & WM) | (ac & CHAR); /* move mode */
ap++; BS++; /* adv ptrs */
@ -360,13 +361,13 @@ uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */
lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */
for (i = 0; i < lim; i++) { /* copy data */
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
if (qwc) { /* write check? */
if (flg? (M[BS] != *ap): /* load mode cmp */
((M[BS] & CHAR) != (*ap & CHAR))) { /* move mode cmp */
ind[IN_DPW] = ind[IN_DSK] = 1; /* error */
return STOP_WRCHKE; } }
if (flg? (M[BS] != *ap): /* load mode cmp */
((M[BS] & CHAR) != (*ap & CHAR))) { /* move mode cmp */
ind[IN_DPW] = ind[IN_DSK] = 1; /* error */
return STOP_WRCHKE; } }
else if (flg) M[BS] = *ap & (WM | CHAR); /* load mode */
else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* word mode */
ap++; BS++; /* adv ptrs */
@ -384,9 +385,9 @@ uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
for (i = 0; i < DP_ADDR; i++) { /* copy address */
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
dp_fill (uptr, da, DP_NUMCH - i); /* fill, set err */
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
dp_fill (uptr, da, DP_NUMCH - i); /* fill, set err */
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
if (flg) *ap = M[BS] & (WM | CHAR); /* L? copy WM */
else *ap = M[BS] & CHAR; /* M? strip WM */
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
@ -406,9 +407,9 @@ uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */
for (i = 0; i < lim; i++) { /* copy data */
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
dp_fill (uptr, da, DP_DATA - i); /* fill, set err */
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
dp_fill (uptr, da, DP_DATA - i); /* fill, set err */
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
return STOP_INVDLN; }
if (flg) *ap = M[BS] & (WM | CHAR); /* load, copy WM */
else *ap = M[BS] & CHAR; /* move, strip WM */
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
@ -475,7 +476,7 @@ uint8 c;
for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
c = M[dcf + DCF_SEC + i]; /* sector addr char */
if ((c & CHAR) != (*ap & CHAR)) /* cmp w/o WM */
return FALSE; }
return FALSE; }
return TRUE; /* compare ok */
}

View file

@ -25,6 +25,7 @@
inq 1407 inquiry terminal
22-Dec-02 RMS Added break support
07-Sep-01 RMS Moved function prototypes
14-Apr-99 RMS Changed t_addr to unsigned
*/
@ -82,39 +83,41 @@ case BCD_R: /* input */
ind[IN_INR] = 0; /* clear req */
puts_tty ("[Enter]\r\n"); /* prompt */
for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */
while ((t = sim_poll_kbd ()) == SCPE_OK)
if (stop_cpu) return SCPE_STOP; /* interrupt? */
if (t < SCPE_KFLAG) return t; /* if not char, err */
t = t & 0177;
if ((t == '\r') || (t == '\n')) break;
if (t == inq_char) { /* cancel? */
ind[IN_INC] = 1; /* set indicator */
puts_tty ("\r\n[Canceled]\r\n");
return SCPE_OK; }
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
sim_putchar (t); /* echo */
if (flag == MD_WM) { /* word mark mode? */
if ((t == '~') && (wm_seen == 0)) wm_seen = WM;
else { M[BS] = wm_seen | ascii_to_bcd[t];
wm_seen = 0; } }
else M[BS] = (M[BS] & WM) | ascii_to_bcd[t];
if (!wm_seen) BS++;
if (ADDR_ERR (BS)) {
BS = BA | (BS % MAXMEMSIZE);
return STOP_NXM; } }
while (((t = sim_poll_kbd ()) == SCPE_OK) ||
(t & SCPE_BREAK)) {
if (stop_cpu) return SCPE_STOP; } /* interrupt? */
if (t < SCPE_KFLAG) return t; /* if not char, err */
t = t & 0177;
if ((t == '\r') || (t == '\n')) break;
if (t == inq_char) { /* cancel? */
ind[IN_INC] = 1; /* set indicator */
puts_tty ("\r\n[Canceled]\r\n");
return SCPE_OK; }
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
sim_putchar (t); /* echo */
if (flag == MD_WM) { /* word mark mode? */
if ((t == '~') && (wm_seen == 0)) wm_seen = WM;
else {
M[BS] = wm_seen | ascii_to_bcd[t];
wm_seen = 0; } }
else M[BS] = (M[BS] & WM) | ascii_to_bcd[t];
if (!wm_seen) BS++;
if (ADDR_ERR (BS)) {
BS = BA | (BS % MAXMEMSIZE);
return STOP_NXM; } }
puts_tty ("\r\n");
M[BS++] = BCD_GRPMRK + WM;
return SCPE_OK;
case BCD_W: /* output */
for (i = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); i++) {
if ((flag == MD_WM) && (t & WM)) {
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
sim_putchar ('~'); }
if ((flag == MD_WM) && (t & WM)) {
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
sim_putchar (bcd_to_ascii[t & CHAR]);
if (ADDR_ERR (BS)) {
BS = BA | (BS % MAXMEMSIZE);
return STOP_NXM; } }
sim_putchar ('~'); }
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
sim_putchar (bcd_to_ascii[t & CHAR]);
if (ADDR_ERR (BS)) {
BS = BA | (BS % MAXMEMSIZE);
return STOP_NXM; } }
puts_tty ("\r\n");
return SCPE_OK;
default:

View file

@ -164,14 +164,14 @@ switch (action) {
case 0: /* to channel now */
if ((mod == 0) || (mod > 12) || CHP (mod, cct[cctptr])) return SCPE_OK;
for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */
if (CHP (mod, cct[(cctptr + i) % cctlnt]))
return space (i, TRUE); }
if (CHP (mod, cct[(cctptr + i) % cctlnt]))
return space (i, TRUE); }
return STOP_CCT; /* runaway channel */
case 1: /* space after */
if (mod <= 3) {
lines = mod; /* save # lines */
lflag = FALSE; /* flag spacing */
ind[IN_CC9] = ind[IN_CC12] = 0; }
lines = mod; /* save # lines */
lflag = FALSE; /* flag spacing */
ind[IN_CC9] = ind[IN_CC12] = 0; }
return SCPE_OK;
case 2: /* space now */
if (mod <= 3) return space (mod, FALSE);
@ -180,10 +180,10 @@ case 3: /* to channel after */
if ((mod == 0) || (mod > 12)) return SCPE_OK; /* check channel */
ind[IN_CC9] = ind[IN_CC12] = 0;
for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */
if (CHP (mod, cct[(cctptr + i) % cctlnt])) {
lines = i; /* save # lines */
lflag = TRUE; /* flag skipping */
return SCPE_OK; } }
if (CHP (mod, cct[(cctptr + i) % cctlnt])) {
lines = i; /* save # lines */
lflag = TRUE; /* flag skipping */
return SCPE_OK; } }
return STOP_CCT; } /* runaway channel */
return SCPE_OK;
}
@ -203,7 +203,8 @@ if ((lpt_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT;
cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */
if (sflag && CHP (0, cct[cctptr])) /* skip, top of form? */
fputs ("\n\f", lpt_unit.fileref); /* nl, ff */
else { for (i = 0; i < count; i++) fputc ('\n', lpt_unit.fileref); }
else { for (i = 0; i < count; i++)
fputc ('\n', lpt_unit.fileref); }
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
ind[IN_CC9] = CHP (9, cct[cctptr]) != 0; /* set indicators */
ind[IN_CC12] = CHP (12, cct[cctptr]) != 0;

View file

@ -147,16 +147,15 @@ switch (mod) { /* case on modifier */
case BCD_B: /* backspace */
ind[IN_END] = 0; /* clear end of reel */
if (pnu || (uptr->pos < sizeof (t_mtrlnt))) /* bot or pnu? */
return SCPE_OK;
fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt),
SEEK_SET);
return SCPE_OK;
fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
if ((err = ferror (uptr->fileref)) || /* err or eof? */
feof (uptr->fileref)) break;
if ((tbc == MTR_TMK) || (tbc == MTR_EOM)) /* tmk or eom? */
uptr->pos = uptr->pos - sizeof (t_mtrlnt);
uptr->pos = uptr->pos - sizeof (t_mtrlnt);
else uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) -
(2 * sizeof (t_mtrlnt));
(2 * sizeof (t_mtrlnt));
break; /* end case */
case BCD_E: /* erase = nop */
@ -218,13 +217,13 @@ case BCD_R: /* read */
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
if (err = ferror (uptr->fileref)) break; /* error? */
if (feof (uptr->fileref) || (tbc == MTR_EOM)) { /* eom or eof? */
ind[IN_TAP] = 1; /* pretend error */
MT_SET_PNU (uptr); /* pos not upd */
break; }
ind[IN_TAP] = 1; /* pretend error */
MT_SET_PNU (uptr); /* pos not upd */
break; }
if (tbc == MTR_TMK) { /* tape mark? */
ind[IN_END] = 1; /* set end mark */
uptr->pos = uptr->pos + sizeof (t_mtrlnt);
break; }
ind[IN_END] = 1; /* set end mark */
uptr->pos = uptr->pos + sizeof (t_mtrlnt);
break; }
if (MTRF (tbc)) ind[IN_TAP] = 1; /* error? set flag */
tbc = MTRL (tbc); /* clear error flag */
if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */
@ -232,31 +231,32 @@ case BCD_R: /* read */
if (err = ferror (uptr->fileref)) break; /* I/O error? */
for ( ; i < tbc; i++) dbuf[i] = 0; /* fill with 0's */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt));
(2 * sizeof (t_mtrlnt));
for (i = 0; i < tbc; i++) { /* loop thru buf */
if (M[BS] == (BCD_GRPMRK + WM)) { /* GWM in memory? */
BS++; /* incr BS */
if (ADDR_ERR (BS)) { /* test for wrap */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; }
return SCPE_OK; } /* done */
t = dbuf[i]; /* get char */
if ((flag != MD_BIN) && (t == BCD_ALT)) t = BCD_BLANK;
if (flag == MD_WM) { /* word mk mode? */
if ((t == BCD_WM) && (wm_seen == 0)) wm_seen = WM;
else { M[BS] = wm_seen | (t & CHAR);
wm_seen = 0; } }
else M[BS] = (M[BS] & WM) | (t & CHAR);
if (!wm_seen) BS++;
if (ADDR_ERR (BS)) { /* check next BS */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; } }
if (M[BS] == (BCD_GRPMRK + WM)) { /* GWM in memory? */
BS++; /* incr BS */
if (ADDR_ERR (BS)) { /* test for wrap */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; }
return SCPE_OK; } /* done */
t = dbuf[i]; /* get char */
if ((flag != MD_BIN) && (t == BCD_ALT)) t = BCD_BLANK;
if (flag == MD_WM) { /* word mk mode? */
if ((t == BCD_WM) && (wm_seen == 0)) wm_seen = WM;
else {
M[BS] = wm_seen | (t & CHAR);
wm_seen = 0; } }
else M[BS] = (M[BS] & WM) | (t & CHAR);
if (!wm_seen) BS++;
if (ADDR_ERR (BS)) { /* check next BS */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; } }
if (flag == MD_WM) M[BS] = WM | BCD_GRPMRK; /* load? set WM */
else M[BS] = (M[BS] & WM) | BCD_GRPMRK; /* move? save WM */
BS++; /* adv BS */
if (ADDR_ERR (BS)) { /* check final BS */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; }
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; }
break;
case BCD_W:
@ -264,13 +264,13 @@ case BCD_W:
if (M[BS] == (BCD_GRPMRK + WM)) return STOP_MTZ; /* eor? */
ind[IN_TAP] = ind[IN_END] = 0; /* clear error */
for (tbc = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); ) {
if ((t & WM) && (flag == MD_WM)) dbuf[tbc++] = BCD_WM;
if (((t & CHAR) == BCD_BLANK) && (flag != MD_BIN))
dbuf[tbc++] = BCD_ALT;
else dbuf[tbc++] = t & CHAR;
if (ADDR_ERR (BS)) { /* check next BS */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; } }
if ((t & WM) && (flag == MD_WM)) dbuf[tbc++] = BCD_WM;
if (((t & CHAR) == BCD_BLANK) && (flag != MD_BIN))
dbuf[tbc++] = BCD_ALT;
else dbuf[tbc++] = t & CHAR;
if (ADDR_ERR (BS)) { /* check next BS */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; } }
ebc = (tbc + 1) & ~1; /* force even */
fseek (uptr->fileref, uptr->pos, SEEK_SET);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
@ -279,8 +279,8 @@ case BCD_W:
if (err = ferror (uptr->fileref)) break; /* I/O error? */
uptr->pos = uptr->pos + ebc + (2 * sizeof (t_mtrlnt));
if (ADDR_ERR (BS)) { /* check final BS */
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; }
BS = BA | (BS % MAXMEMSIZE);
return STOP_WRAP; }
break;
default:
return STOP_INVM; }

View file

@ -133,18 +133,18 @@ ptr = 0;
for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
mask = 0;
if (*cptr == '(') { /* repeat count? */
cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
if (r != SCPE_OK) return SCPE_FMT; }
cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
if (r != SCPE_OK) return SCPE_FMT; }
else rpt = 1;
while (*cptr != 0) { /* get col no's */
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
col = get_uint (gbuf, 10, 12, &r); /* column number */
if (r != SCPE_OK) return SCPE_FMT;
mask = mask | (1 << col); } /* set bit */
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
col = get_uint (gbuf, 10, 12, &r); /* column number */
if (r != SCPE_OK) return SCPE_FMT;
mask = mask | (1 << col); } /* set bit */
for ( ; rpt > 0; rpt--) { /* store vals */
if (ptr >= CCT_LNT) return SCPE_FMT;
cctbuf[ptr++] = mask; } }
if (ptr >= CCT_LNT) return SCPE_FMT;
cctbuf[ptr++] = mask; } }
if (ptr == 0) return SCPE_FMT;
cctlnt = ptr;
cctptr = 0;
@ -203,7 +203,7 @@ extern int32 op_table[64], len_table[9];
if (sw & SWMASK ('C')) { /* character? */
t = val[0];
if (uptr->flags & UNIT_BCD)
fprintf (of, (t & WM)? "~%c": "%c", bcd_to_ascii[t & CHAR]);
fprintf (of, (t & WM)? "~%c": "%c", bcd_to_ascii[t & CHAR]);
else fprintf (of, FMTASC (t & 0177));
return SCPE_OK; }
if ((uptr != NULL) && (uptr != &cpu_unit)) return SCPE_ARG; /* CPU? */
@ -214,8 +214,9 @@ if (sw & SWMASK ('D')) { /* dump? */
return -(i - 1); }
if (sw & SWMASK ('S')) { /* string? */
i = 0;
do { t = val[i++];
fprintf (of, (t & WM)? "~%c": "%c", bcd_to_ascii[t & CHAR]); }
do {
t = val[i++];
fprintf (of, (t & WM)? "~%c": "%c", bcd_to_ascii[t & CHAR]); }
while ((i < LINE_LNT) && ((val[i] & WM) == 0));
return -(i - 1); }
if ((sw & SWMASK ('M')) == 0) return SCPE_ARG;
@ -300,13 +301,13 @@ if ((sw & SWMASK ('C')) || (sw & SWMASK ('S')) || (*cptr == '~') ||
((*cptr == '\'') && cptr++) || ((*cptr == '"') && cptr++)) {
wm_seen = 0;
for (i = 0; (i < sim_emax) && (*cptr != 0); ) {
t = *cptr++; /* get character */
if (cflag && (wm_seen == 0) && (t == '~')) wm_seen = WM;
else if (uptr->flags & UNIT_BCD) {
if (t < 040) return SCPE_ARG;
val[i++] = ascii_to_bcd[t] | wm_seen;
wm_seen = 0; }
else val[i++] = t; }
t = *cptr++; /* get character */
if (cflag && (wm_seen == 0) && (t == '~')) wm_seen = WM;
else if (uptr->flags & UNIT_BCD) {
if (t < 040) return SCPE_ARG;
val[i++] = ascii_to_bcd[t] | wm_seen;
wm_seen = 0; }
else val[i++] = t; }
if ((i == 0) || wm_seen) return SCPE_ARG;
return -(i-1); }
@ -321,14 +322,14 @@ if (((op_table[op] && IO) && (get_io (gbuf, &val[1]) == SCPE_OK)) ||
(get_addr (gbuf, &val[1]) == SCPE_OK)) {
cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */
if (get_addr (gbuf, &val[4]) == SCPE_OK) {
cptr = get_glyph (cptr, gbuf, ','); /* get d */
ilnt = 7; } /* a and b addresses */
cptr = get_glyph (cptr, gbuf, ','); /* get d */
ilnt = 7; } /* a and b addresses */
else ilnt = 4; } /* a address */
else ilnt = 1; /* no addresses */
if ((gbuf[0] == '\'') || (gbuf[0] == '"')) { /* d character? */
t = gbuf[1];
if ((gbuf[2] != 0) || (*cptr != 0) || (t < 040))
return SCPE_ARG; /* end and legal? */
return SCPE_ARG; /* end and legal? */
val[ilnt] = ascii_to_bcd[t]; /* save D char */
ilnt = ilnt + 1; }
else if (gbuf[0] != 0) return SCPE_ARG; /* not done? */

View file

@ -222,26 +222,26 @@ case OP_RN: /* read numeric */
r = cdr_read (); /* fill reader buf */
if (r != SCPE_OK) return r; /* error? */
for (i = 0; i < CD_LEN; i++) { /* transfer to mem */
cdc = cdr_to_num[cdr_buf[i]]; /* translate */
if (cdc < 0) { /* invalid? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
cdc = 0; }
M[pa] = cdc; /* store digit */
PP (pa); } /* incr mem addr */
cdc = cdr_to_num[cdr_buf[i]]; /* translate */
if (cdc < 0) { /* invalid? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
cdc = 0; }
M[pa] = cdc; /* store digit */
PP (pa); } /* incr mem addr */
break;
case OP_RA: /* read alphameric */
r = cdr_read (); /* fill reader buf */
if (r != SCPE_OK) return r; /* error? */
for (i = 0; i < CD_LEN; i++) { /* transfer to mem */
cdc = cdr_to_alp[cdr_buf[i]]; /* translate */
if (cdc < 0) { /* invalid? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
cdc = 0; };
M[pa] = (M[pa] & FLAG) | (cdc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((cdc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
cdc = cdr_to_alp[cdr_buf[i]]; /* translate */
if (cdc < 0) { /* invalid? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
cdc = 0; };
M[pa] = (M[pa] & FLAG) | (cdc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((cdc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
@ -333,14 +333,14 @@ case OP_WN:
return cdp_num (pa, CD_LEN, FALSE); /* write numeric */
case OP_WA:
for (i = 0; i < CD_LEN; i++) { /* one card */
d = M[pa] & DIGIT; /* get digit pair */
z = M[pa - 1] & DIGIT;
cdc = alp_to_cdp[(z << 4) | d]; /* translate */
if (cdc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
CRETIOE (io_stop, STOP_INVCHR); }
cdp_buf[i] = cdc; /* store in buf */
pa = ADDR_A (pa, 2); } /* incr mem addr */
d = M[pa] & DIGIT; /* get digit pair */
z = M[pa - 1] & DIGIT;
cdc = alp_to_cdp[(z << 4) | d]; /* translate */
if (cdc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
CRETIOE (io_stop, STOP_INVCHR); }
cdp_buf[i] = cdc; /* store in buf */
pa = ADDR_A (pa, 2); } /* incr mem addr */
return cdp_write (CD_LEN); /* punch buffer */
default: /* invalid function */
return STOP_INVFNC; }

View file

@ -561,7 +561,7 @@ case OP_BB:
PR1 = 1; } /* invalidate */
else if (IR2 != 1) { /* IR2 valid? */
BRANCH (IR2); /* return to IR2 */
IR2 = 1; } /* invalidate */
IR2 = 1; } /* invalidate */
else reason = STOP_INVRTN; /* MAR check */
break;
@ -770,23 +770,23 @@ case OP_BS:
t = M[ADDR_A (saved_PC, I_SEL)] & DIGIT; /* get select */
switch (t) { /* case on select */
case 0:
idxe = idxb = 0; /* indexing off */
break;
idxe = idxb = 0; /* indexing off */
break;
case 1:
idxe = 1; idxb = 0; /* index band A */
break;
idxe = 1; idxb = 0; /* index band A */
break;
case 2:
idxe = idxb = 1; /* index band B */
break;
idxe = idxb = 1; /* index band B */
break;
case 8:
iae = 0; /* indirect off */
break;
iae = 0; /* indirect off */
break;
case 9:
iae = 1; /* indirect on */
break;
iae = 1; /* indirect on */
break;
default:
reason = STOP_INVSEL; /* undefined */
break; }
reason = STOP_INVSEL; /* undefined */
break; }
BRANCH (PAR);
break;
@ -1683,9 +1683,10 @@ do { sd = M[s] & DIGIT; /* src digit */
MM (s); /* decr src addr */
MM (tbl); /* skip 1st tbl dig */
tblc = 0; /* count */
do { tf = M[tbl] & FLAG; /* get next */
MM (tbl); /* decr ptr */
if (tblc++ > MEMSIZE) return STOP_FWRAP; }
do {
tf = M[tbl] & FLAG; /* get next */
MM (tbl); /* decr ptr */
if (tblc++ > MEMSIZE) return STOP_FWRAP; }
while (tf == 0); /* until flag */
if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */
while (sf == 0);

View file

@ -160,18 +160,18 @@ case OP_WN:
return lpt_num (pa, 0, f1); /* write numeric */
case OP_WA:
for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) break; /* 8-2 char? */
lpc = alp_to_lpt[(z << 4) | d]; /* translate pair */
if (lpc < 0) { /* bad char? */
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
inv = STOP_INVCHR; } /* set return status */
lpt_buf[lpt_bptr] = lpc & 0x7F; /* fill buffer */
pa = ADDR_A (pa, 2); } /* incr mem addr */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) break; /* 8-2 char? */
lpc = alp_to_lpt[(z << 4) | d]; /* translate pair */
if (lpc < 0) { /* bad char? */
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
inv = STOP_INVCHR; } /* set return status */
lpt_buf[lpt_bptr] = lpc & 0x7F; /* fill buffer */
pa = ADDR_A (pa, 2); } /* incr mem addr */
if ((f1 & 1) == 0) { ; /* print now? */
r = lpt_print (); /* print line */
if (r != SCPE_OK) return r; }
r = lpt_print (); /* print line */
if (r != SCPE_OK) return r; }
CRETIOE (io_stop, inv);
default: /* invalid function */
return STOP_INVFNC; }
@ -191,11 +191,11 @@ end = pa + len;
for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */
d = M[pa]; /* get digit */
if (len? (pa >= end): /* end reached? */
((d & REC_MARK) == REC_MARK)) break;
((d & REC_MARK) == REC_MARK)) break;
lpc = num_to_lpt[d]; /* translate */
if (lpc < 0) { /* bad char? */
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
inv = STOP_INVCHR; } /* set return status */
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
inv = STOP_INVCHR; } /* set return status */
lpt_buf[lpt_bptr++] = lpc & 0x7F; /* fill buffer */
PP (pa); } /* incr mem addr */
if ((f1 & 1) == 0) { /* print now? */
@ -226,10 +226,10 @@ if (lpt_bptr) { /* any line? */
lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */
lpt_buf_init (); /* reinit buf */
if (ferror (lpt_unit.fileref)) { /* error? */
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; } }
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; } }
lpt_savctrl = 0x61; /* reset ctrl */
if ((ctrl & K_LIN) == ((ctrl & K_IMM)? 0: K_LIN)) /* space lines? */

View file

@ -205,34 +205,34 @@ t_stat r, inv = SCPE_OK;
switch (op) { /* case on op */
case OP_RN: /* read numeric */
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
CRETIOE (io_stop, inv); } /* done */
if (bad_par[ptc]) { /* bad parity? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
M[pa] = 0; } /* store zero */
else M[pa] = ptr_to_num[ptc]; /* translate, store */
PP (pa); } /* incr mem addr */
r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
CRETIOE (io_stop, inv); } /* done */
if (bad_par[ptc]) { /* bad parity? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
M[pa] = 0; } /* store zero */
else M[pa] = ptr_to_num[ptc]; /* translate, store */
PP (pa); } /* incr mem addr */
break;
case OP_RA: /* read alphameric */
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
M[pa - 1] = 0;
CRETIOE (io_stop, inv); } /* done */
mc = ptr_to_alp[ptc]; /* translate */
if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
mc = 0; } /* store blank */
M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
M[pa - 1] = 0;
CRETIOE (io_stop, inv); } /* done */
mc = ptr_to_alp[ptc]; /* translate */
if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
mc = 0; } /* store blank */
M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
@ -251,19 +251,19 @@ if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
switch (op) { /* case on op */
case OP_RA: /* read alphameric */
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = ptr_read (&ptc, FALSE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
M[pa - 1] = 0;
CRETIOE (io_stop, inv); } /* done */
if (bad_par[ptc]) { /* bad parity? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; } /* set return status */
M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) |
(((ptc >> 5) & 06) | ((ptc >> 3) & 1));
pa = ADDR_A (pa, 2); } /* incr mem addr */
r = ptr_read (&ptc, FALSE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
M[pa - 1] = 0;
CRETIOE (io_stop, inv); } /* done */
if (bad_par[ptc]) { /* bad parity? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; } /* set return status */
M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) |
(((ptc >> 5) & 06) | ((ptc >> 3) & 1));
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
@ -281,12 +281,12 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
return SCPE_UNATT; }
do { if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */
ind[IN_RDCHK] = 1; /* err, rd chk */
if (feof (ptr_unit.fileref))
printf ("PTR end of file\n");
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
ind[IN_RDCHK] = 1; /* err, rd chk */
if (feof (ptr_unit.fileref))
printf ("PTR end of file\n");
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
*c = temp & 0377; /* save char */
ptr_unit.pos = ptr_unit.pos + 1; } /* incr file addr */
while (ignfeed && (*c == PT_FD)); /* until not feed */
@ -345,17 +345,17 @@ case OP_WN:
return ptp_num (pa, 0); /* punch numeric */
case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */
ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */
if (ptc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* write check */
CRETIOE (io_stop, STOP_INVCHR); }
r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) return r; /* error? */
pa = ADDR_A (pa, 2); } /* incr mem addr */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */
ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */
if (ptc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* write check */
CRETIOE (io_stop, STOP_INVCHR); }
r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) return r; /* error? */
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
@ -374,15 +374,15 @@ if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
switch (op) { /* decode op */
case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */
ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07);
if (bad_par[ptc]) ptc = ptc | PT_C; /* set parity */
r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) return r; /* error? */
pa = ADDR_A (pa, 2); } /* incr mem addr */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */
ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07);
if (bad_par[ptc]) ptc = ptc | PT_C; /* set parity */
r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) return r; /* error? */
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
@ -402,7 +402,7 @@ for (i = 0; i < MEMSIZE; i++) { /* stop runaway */
d = M[pa] & (FLAG | DIGIT); /* get char */
if (len? (pa >= end): /* dump: end reached? */
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
return ptp_write (PT_EL); /* end record */
return ptp_write (PT_EL); /* end record */
r = ptp_write (num_to_ptp[d]); /* write */
if (r != SCPE_OK) return r; /* error? */
PP (pa); } /* incr mem addr */

View file

@ -24,6 +24,8 @@
in this Software without prior written authorization from Robert M Supnik.
tty console typewriter
22-Dec-02 RMS Added break test
*/
#include "i1620_defs.h"
@ -153,43 +155,43 @@ switch (op) { /* case on op */
case OP_K: /* control */
switch (f1) { /* case on control */
case 1: /* space */
tto_write (' ');
break;
tto_write (' ');
break;
case 2: /* return */
tto_write ('\r');
break;
tto_write ('\r');
break;
case 3: /* backspace */
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
tto_write ('\b');
break;
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
tto_write ('\b');
break;
case 4: /* index */
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
tto_write ('\n');
break;
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
tto_write ('\n');
break;
case 8: /* tab */
tto_write ('\t');
break;
tto_write ('\t');
break;
default:
return STOP_INVFNC; }
return STOP_INVFNC; }
return SCPE_OK;
case OP_RN: /* read numeric */
tti_unlock (); /* unlock keyboard */
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
r = tti_rnum (&ttc); /* read char */
if (r != SCPE_OK) return r; /* error? */
if (ttc == 0x7F) return SCPE_OK; /* end record? */
M[pa] = ttc & (FLAG | DIGIT); /* store char */
PP (pa); } /* incr mem addr */
r = tti_rnum (&ttc); /* read char */
if (r != SCPE_OK) return r; /* error? */
if (ttc == 0x7F) return SCPE_OK; /* end record? */
M[pa] = ttc & (FLAG | DIGIT); /* store char */
PP (pa); } /* incr mem addr */
break;
case OP_RA: /* read alphameric */
tti_unlock ();
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = tti_ralp (&ttc); /* read char */
if (r != SCPE_OK) return r; /* error? */
if (ttc == 0x7F) return SCPE_OK; /* end record? */
M[pa] = (M[pa] & FLAG) | (ttc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((ttc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
r = tti_ralp (&ttc); /* read char */
if (r != SCPE_OK) return r; /* error? */
if (ttc == 0x7F) return SCPE_OK; /* end record? */
M[pa] = (M[pa] & FLAG) | (ttc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((ttc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
case OP_DN:
return tto_num (pa, 20000 - (pa % 20000)); /* dump numeric */
@ -197,16 +199,16 @@ case OP_WN:
return tto_num (pa, 0); /* type numeric */
case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
d = M[pa] & DIGIT; /* get digit */
if ((d & 0xA) == REC_MARK) /* 8-2 char? */
CRETIOE (io_stop, inv); /* end record */
d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */
ttc = alp_to_tto[d]; /* translate */
if (ttc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
inv = STOP_INVCHR; } /* set return status */
tto_write (ttc & 0x7F); /* write */
pa = ADDR_A (pa, 2); } /* incr mem addr */
d = M[pa] & DIGIT; /* get digit */
if ((d & 0xA) == REC_MARK) /* 8-2 char? */
CRETIOE (io_stop, inv); /* end record */
d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */
ttc = alp_to_tto[d]; /* translate */
if (ttc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
inv = STOP_INVCHR; } /* set return status */
tto_write (ttc & 0x7F); /* write */
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
@ -260,7 +262,7 @@ t_stat tti_read (int8 *c)
int32 t;
do { t = sim_poll_kbd (); } /* get character */
while (t == SCPE_OK);
while ((t == SCPE_OK) || (t & SCPE_BREAK)); /* ignore break */
if (t < SCPE_KFLAG) return t; /* error? */
*c = t & 0177; /* store character */
return SCPE_OK;
@ -279,7 +281,7 @@ for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
d = M[pa]; /* get char */
if (len? (pa >= end): /* dump: end reached? */
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
return SCPE_OK; /* end operation */
return SCPE_OK; /* end operation */
if (d & FLAG) tto_write ('~'); /* flag? */
r = tto_write (num_to_tto[d & DIGIT]); /* write */
if (r != SCPE_OK) return r; /* error? */

View file

@ -190,7 +190,7 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc);
void calc_ints (void);
extern t_stat ts_wr (int32 data, int32 addr, int32 access);
@ -1182,7 +1182,7 @@ t_stat cpu_svc (UNIT *uptr)
* Memory allocation
* ------------------------------------------------------------------------ */
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc)
{
t_bool used;
int32 i;

View file

@ -149,12 +149,12 @@ extern int32 sim_switches;
static t_stat cr_svc (UNIT *uptr);
static t_stat cr_reset (DEVICE *dptr);
static t_stat cr_set_code (UNIT *uptr, int32 match);
static t_stat cr_set_code (UNIT *uptr, int32 match, char *cptr, void *desc);
static t_stat cr_attach (UNIT *uptr, char *cptr);
static t_stat cr_detach (UNIT *uptr);
static t_stat cp_reset (DEVICE *dptr);
static t_stat cp_set_code (UNIT *uptr, int32 match);
static t_stat cp_set_code (UNIT *uptr, int32 match, char *cptr, void *desc);
static t_stat cp_detach (UNIT *uptr);
static int16 cr_dsw = 0; /* device status word */
@ -497,12 +497,12 @@ t_stat set_active_cr_code (int match)
return SCPE_OK;
}
t_stat cr_set_code (UNIT *uptr, int32 match)
t_stat cr_set_code (UNIT *uptr, int32 match, char *cptr, void *desc)
{
return set_active_cr_code(match);
}
t_stat cp_set_code (UNIT *uptr, int32 match)
t_stat cp_set_code (UNIT *uptr, int32 match, char *cptr, void *desc)
{
CPCODE *code;
int ncode;
@ -550,7 +550,7 @@ t_stat load_cr_boot (int drvno)
return SCPE_OK;
}
t_stat cr_boot (int unitno)
t_stat cr_boot (int unitno, DEVICE *dptr)
{
t_stat rval;
short buf[80];
@ -917,7 +917,7 @@ static t_bool nextdeck (void)
static t_stat cr_reset (DEVICE *dptr)
{
cr_set_code(&cr_unit, active_cr_code & UNIT_CODE); /* reset to specified code table */
cr_set_code(&cr_unit, active_cr_code & UNIT_CODE, NULL, NULL); /* reset to specified code table */
readstate = STATION_EMPTY;
@ -948,7 +948,7 @@ static t_stat cr_reset (DEVICE *dptr)
static t_stat cp_reset (DEVICE *dptr)
{
cp_set_code(&cp_unit, cp_unit.flags & UNIT_CODE);
cp_set_code(&cp_unit, cp_unit.flags & UNIT_CODE, NULL, NULL);
punchstate = STATION_EMPTY;
cp_unit.COLUMN = -1;

View file

@ -259,7 +259,7 @@ void xio_error (char *msg);
void bail (char *msg);
t_stat load_cr_boot (int drv);
t_stat cr_boot (int unitno);
t_stat cr_boot (int unitno, DEVICE *dptr);
void calc_ints (void); /* recalculate interrupt bitmask */
void trace_io (char *fmt, ...); /* debugging printout */
void scp_panic (char *msg); /* bail out of simulator */

View file

@ -80,7 +80,7 @@ static t_stat dsk_svc (UNIT *uptr);
static t_stat dsk_reset (DEVICE *dptr);
static t_stat dsk_attach (UNIT *uptr, char *cptr);
static t_stat dsk_detach (UNIT *uptr);
static t_stat dsk_boot (int unitno);
static t_stat dsk_boot (int unitno, DEVICE *dptr);
static void diskfail (UNIT *uptr, int errflag);
@ -511,7 +511,7 @@ static t_stat dsk_detach (UNIT *uptr)
// boot routine - if they type BOOT DSK, load the standard boot card.
static t_stat dsk_boot (int unitno)
static t_stat dsk_boot (int unitno, DEVICE *dptr)
{
t_stat rval;

View file

@ -984,7 +984,7 @@ void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam)
if (! running) { /* if card reader is attached to a file, do cold start read of one card */
IAR = 0; /* reset IAR */
// stuff_cmd("boot cr");
if (cr_boot(0) != SCPE_OK) /* load boot card */
if (cr_boot(0, NULL) != SCPE_OK) /* load boot card */
remark_cmd("IPL failed");
}
break;

View file

@ -13,6 +13,7 @@
// ASM1130 - IBM 1130 Cross Assembler
//
// Version
// 1.07 - 2003Jan05 - Filenames are now left in lower case. SYMBOLS.SYS stays all upper case
// 1.06 - 2002May02 - Fixed bug in ebdic constants (data goes into low byte)
// First stab at adding ISS level # info, this is iffy
// 1.05 - 2002Apr24 - Made negative BSS size a warning not an error, as it
@ -155,7 +156,7 @@
#define TRUE 1
#define FALSE 0
#define VERSION "ASM1130 CROSS ASSEMBLER V1.06"
#define VERSION "ASM1130 CROSS ASSEMBLER V1.07"
#define ISTV 0x33 // magic number from DMS R2V12 monitorm symbol @ISTV
@ -1880,9 +1881,10 @@ void proc (char *fname)
else
strcpy(curfn, fname); // otherwise use extension specified
#if (defined(WIN32) || defined(VMS))
upcase(curfn); // only force uppercase of name on Windows and VMS
#endif
// let's leave filename case alone even if it doesn't matter
//#if (defined(WIN32) || defined(VMS))
// upcase(curfn); // only force uppercase of name on Windows and VMS
//#endif
if (progname[0] == '\0') { // pick up primary filename
if ((c = strrchr(curfn, '\\')) == NULL)

1718
Interdata/id16_cpu.c Normal file

File diff suppressed because it is too large Load diff

346
Interdata/id16_dboot.c Normal file
View file

@ -0,0 +1,346 @@
/* id16_dboot.c: Interdata 16b simulator disk bootstrap
Copyright (c) 2000-2002, 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.
*/
#include "id_defs.h"
#define DBOOT_BEG 0x1000
#define DBOOT_START 0x100e
#define DBOOT_LEN (sizeof (dboot_rom) / sizeof (uint8))
/* Boot ROM: transcription of OS/16 MT2 ALO Direct Access Loader */
static uint8 dboot_rom[] = {
0xca, 0xf0, 0x00, 0x30,
0xc5, 0xf0, 0x00, 0x3a,
0x02, 0x8e,
0x26, 0xf7,
0x03, 0x0e,
0xd1, 0xc0, 0x00, 0x78,
0xd0, 0xc0, 0x13, 0xf6,
0x07, 0xdd,
0xc8, 0x10, 0x10, 0x00,
0xd3, 0xf0, 0x00, 0x7e,
0xc4, 0xf0, 0x00, 0x0f,
0x01, 0xe1,
0xd2, 0xf0, 0x12, 0xe2,
0xd3, 0xf0, 0x00, 0x7f,
0x90, 0xf4,
0x01, 0xe1,
0xd2, 0xf0, 0x12, 0xe3,
0xd3, 0xf0, 0x00, 0x7f,
0xc4, 0xf0, 0x00, 0x0f,
0x01, 0xe1,
0xd2, 0xf0, 0x12, 0xe4,
0xd3, 0x20, 0x00, 0x7d,
0xd3, 0x30, 0x00, 0x7c,
0xd3, 0x40, 0x00, 0x7a,
0xd3, 0x50, 0x00, 0x7b,
0xc8, 0x70, 0x12, 0xf6,
0xc8, 0x80, 0x13, 0xf5,
0x07, 0xaa,
0x07, 0xcc,
0x41, 0xe0, 0x11, 0x88,
0x48, 0xa0, 0x12, 0xfe,
0x48, 0xc0, 0x13, 0x00,
0x43, 0x00, 0x10, 0x98,
0xc8, 0x70, 0x12, 0xf6,
0x41, 0xe0, 0x11, 0x88,
0xc8, 0xe0, 0x12, 0xfa,
0x24, 0x15,
0xd3, 0x0e, 0x00, 0x24,
0xc3, 0x00, 0x00, 0x10,
0x21, 0x3f,
0xca, 0xe0, 0x00, 0x30,
0x27, 0x11,
0x20, 0x38,
0x48, 0xa0, 0x12, 0xf6,
0x48, 0xc0, 0x12, 0xf8,
0x42, 0x30, 0x10, 0x70,
0x08, 0xaa,
0x20, 0x33,
0x43, 0x00, 0x12, 0xb2,
0x90, 0x05,
0x42, 0x30, 0x10, 0x88,
0xc8, 0x60, 0x4f, 0x53,
0x45, 0x63, 0x00, 0x00,
0x20, 0x36,
0xc8, 0x60, 0x31, 0x36,
0x45, 0x6e, 0x00, 0x02,
0x20, 0x3b,
0x48, 0x6e, 0x00, 0x08,
0x45, 0x60, 0x12, 0xe2,
0x20, 0x35,
0xd3, 0x6e, 0x00, 0x0a,
0xd4, 0x60, 0x12, 0xe4,
0x20, 0x3a,
0x08, 0x0e,
0x07, 0x66,
0xca, 0x60, 0x20, 0x00,
0x23, 0x36,
0x40, 0x06, 0x00, 0x00,
0x45, 0x06, 0x00, 0x00,
0x22, 0x37,
0x48, 0xae, 0x00, 0x0c,
0x48, 0xce, 0x00, 0x0e,
0x48, 0x0e, 0x00, 0x10,
0x48, 0x1e, 0x00, 0x12,
0x0b, 0x1c,
0x0f, 0x0a, 0x07, 0xff,
0x26, 0x11,
0x0e, 0x0f,
0xed, 0x00, 0x00, 0x08,
0xcb, 0x60, 0x02, 0xbe,
0x08, 0x00,
0x23, 0x34,
0x08, 0x86,
0x08, 0x16,
0x23, 0x04,
0x05, 0x16,
0x22, 0x84,
0x08, 0x81,
0x07, 0x77,
0x27, 0x81,
0xc8, 0xd1, 0xee, 0xc0,
0xc8, 0xf0, 0x11, 0x40,
0x48, 0x0f, 0x00, 0x00,
0x40, 0x01, 0x00, 0x00,
0x26, 0xf2,
0x26, 0x12,
0xc5, 0xf0, 0x13, 0xfe,
0x20, 0x88,
0x0a, 0xed,
0x40, 0xed, 0x12, 0xf4,
0x43, 0x0d, 0x11, 0x40,
0x41, 0xed, 0x11, 0x88,
0xd1, 0xed, 0x13, 0xf6,
0xd0, 0xe0, 0x00, 0x78,
0xd1, 0xed, 0x13, 0xfa,
0xd0, 0xe0, 0x00, 0x7c,
0x48, 0x10, 0x00, 0x62,
0x48, 0x6d, 0x12, 0xf4,
0xd1, 0xa6, 0x00, 0x00,
0xd0, 0xa1, 0x00, 0x30,
0xd1, 0xe6, 0x00, 0x0c,
0xd0, 0xe1, 0x00, 0x28,
0x43, 0x00, 0x00, 0x60,
0x07, 0x00,
0x07, 0xbb,
0x0b, 0xcf,
0x0f, 0xab,
0x21, 0x13,
0x26, 0x01,
0x22, 0x04,
0x0a, 0xcf,
0x0e, 0xab,
0x08, 0xac,
0x08, 0xc0,
0x03, 0x0e,
0xde, 0x2d, 0x12, 0x1e,
0xc5, 0x50, 0x00, 0x33,
0x42, 0x2d, 0x11, 0xec,
0xde, 0x3d, 0x12, 0x1e,
0x9d, 0x3f,
0x22, 0x21,
0x9d, 0x4f,
0x42, 0x1d, 0x12, 0xb8,
0xc3, 0xf0, 0x00, 0x10,
0x20, 0x35,
0xd0, 0xad, 0x13, 0xea,
0xc8, 0xf0, 0x00, 0x30,
0x41, 0xed, 0x11, 0x70,
0x08, 0x9c,
0x08, 0xba,
0x48, 0xad, 0x13, 0xea,
0x48, 0xcd, 0x13, 0xee,
0xd1, 0xed, 0x13, 0xf2,
0xc5, 0xb0, 0x00, 0x18,
0x21, 0x82,
0x26, 0xb8,
0x98, 0x49,
0xde, 0x4d, 0x12, 0xe7,
0x9d, 0x3f,
0x22, 0x21,
0x9d, 0x4f,
0x42, 0x7d, 0x12, 0xb8,
0x20, 0x83,
0x98, 0x27,
0x98, 0x28,
0x98, 0x49,
0x9a, 0x3b,
0x41, 0x6d, 0x12, 0x7a,
0x22, 0x0f,
0x9d, 0x4f,
0xc3, 0xf0, 0x00, 0x19,
0x42, 0x3d, 0x12, 0xb8,
0xd0, 0xad, 0x13, 0xea,
0xc8, 0xf5, 0xff, 0xcc,
0x0a, 0xff,
0x48, 0xff, 0x12, 0xec,
0x41, 0xed, 0x11, 0x70,
0x08, 0x9c,
0x08, 0xca,
0x07, 0xaa,
0xc8, 0xf5, 0xff, 0xcc,
0xd3, 0xff, 0x12, 0xe8,
0x41, 0xed, 0x11, 0x70,
0x40, 0xcd, 0x12, 0xf2,
0x08, 0xba,
0x48, 0xad, 0x13, 0xea,
0x48, 0xcd, 0x13, 0xee,
0xd1, 0xed, 0x13, 0xf2,
0xde, 0x4d, 0x12, 0x6e,
0x9d, 0x3f,
0x22, 0x21,
0x98, 0x49,
0xde, 0x4d, 0x12, 0xd0,
0x9d, 0x3f,
0x22, 0x21,
0xde, 0x4d, 0x12, 0xa2,
0x9d, 0x3f,
0x22, 0x21,
0xd8, 0x4d, 0x12, 0xf2,
0xde, 0x4d, 0x12, 0xd1,
0x9d, 0x3f,
0x22, 0x21,
0xde, 0x4d, 0x12, 0xe7,
0x9d, 0x3f,
0x22, 0x21,
0x9d, 0x4f,
0x20, 0x81,
0xc3, 0xf0, 0x00, 0x53,
0x42, 0x3d, 0x12, 0xb8,
0x48, 0xfd, 0x12, 0xf2,
0x91, 0xfa,
0x06, 0xf9,
0xc8, 0x6d, 0x12, 0x2c,
0x98, 0x27,
0x98, 0x28,
0x9a, 0x3b,
0x98, 0x3f,
0xde, 0x3d, 0x12, 0xe6,
0xde, 0x2d, 0x11, 0xaf,
0x9d, 0x2f,
0x20, 0x81,
0xde, 0x2d, 0x12, 0x1e,
0x99, 0x20,
0xde, 0x2d, 0x12, 0x1e,
0x9d, 0x3f,
0x22, 0x21,
0x42, 0x1d, 0x12, 0xbc,
0xc3, 0xf0, 0x00, 0x10,
0x03, 0x3e,
0x0b, 0x07,
0x26, 0x02,
0xc4, 0x00, 0xff, 0x00,
0x0a, 0x70,
0x26, 0x91,
0x07, 0xbb,
0x40, 0xbd, 0x12, 0xf2,
0x03, 0x06,
0x24, 0xf1,
0x24, 0x10,
0x23, 0x04,
0x08, 0x14,
0x23, 0x02,
0x08, 0x13,
0x24, 0x01,
0xde, 0x0d, 0x10, 0xdc,
0x9a, 0x0f,
0x9a, 0x01,
0xde, 0x0d, 0x12, 0xe5,
0xd1, 0xed, 0x13, 0xf6,
0xd0, 0xe0, 0x00, 0x78,
0xd1, 0xed, 0x13, 0xfa,
0xd0, 0xe0, 0x00, 0x7c,
0x91, 0x0f,
0x95, 0x10,
0x22, 0x01,
0x00, 0x00, 0x00,
0x80,
0xc1,
0xc2,
0x14, 0x40, 0x40, 0x00,
0x01, 0x90,
0x01, 0x40,
0x04, 0xc0,
0x00, 0x00,
0x00, 0x00
};
/* Lower memory setup
78 = binary input device address
79 = binary device input command
7A = disk device number
7B = device code
7C = disk controller address
7D = selector channel address
7E:7F = operating system extension (user specified)
*/
struct dboot_id {
char *name;
uint32 cap;
uint32 dtype;
uint32 offset;
};
static struct dboot_id dboot_tab[] = {
{ "DP", 2, 0x31, o_DP0 },
{ "DP", 9, 0x33, o_DP0 },
{ "DM", 64, 0x35, o_ID0 },
{ "DM", 244, 0x36, o_ID0 },
{ NULL } };
t_stat id_dboot (int32 u, DEVICE *dptr)
{
extern DIB pt_dib, sch_dib;
extern uint32 PC;
uint32 i, typ, ctlno, off, cap, sch_dev;
UNIT *uptr;
DIB *ddib = (DIB *) dptr->ctxt; /* get disk DIB */
ctlno = ddib->dno; /* get ctrl devno */
sch_dev = sch_dib.dno + ddib->sch; /* sch dev # */
uptr = dptr->units + u; /* get capacity */
cap = uptr->capac >> 20;
for (i = typ = 0; dboot_tab[i].name != NULL; i++) {
if ((strcmp (dboot_tab[i].name, dptr->name) == 0) &&
(dboot_tab[i].cap == cap)) {
typ = dboot_tab[i].dtype;
off = dboot_tab[i].offset; } }
if (typ == 0) return SCPE_NOFNC;
IOWriteBlk (DBOOT_BEG, DBOOT_LEN, dboot_rom); /* copy boot */
IOWriteB (AL_DEV, pt_dib.dno); /* bin input dev */
IOWriteB (AL_IOC, 0x99);
IOWriteB (AL_DSKU, ctlno + ((u + 1) * off)); /* disk param */
IOWriteB (AL_DSKT, typ);
IOWriteB (AL_DSKC, ctlno);
IOWriteB (AL_SCH, sch_dev);
PC = DBOOT_START;
return SCPE_OK;
}

521
Interdata/id16_sys.c Normal file
View file

@ -0,0 +1,521 @@
/* id16_sys.c: Interdata 16b simulator interface
Copyright (c) 2000-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.
*/
#include "id_defs.h"
#include <ctype.h>
#define MSK_SBF 0x0100
extern DEVICE cpu_dev;
extern DEVICE sch_dev;
extern DEVICE pt_dev;
extern DEVICE tt_dev, ttp_dev;
extern DEVICE pas_dev, pasl_dev;
extern DEVICE lpt_dev;
extern DEVICE pic_dev, lfc_dev;
extern DEVICE dp_dev, idc_dev;
extern DEVICE fd_dev, mt_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern uint16 *M;
t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val);
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val);
extern t_stat lp_load (FILE *fileref, char *cptr, char *fnam);
extern pt_dump (FILE *of, char *cptr, char *fnam);
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "Interdata 16b";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 8;
DEVICE *sim_devices[] = {
&cpu_dev,
&sch_dev,
&pt_dev,
&tt_dev,
&ttp_dev,
&pas_dev,
&pasl_dev,
&pic_dev,
&lfc_dev,
&lpt_dev,
&dp_dev,
&idc_dev,
&fd_dev,
&mt_dev,
NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"Reserved instruction",
"HALT instruction",
"Breakpoint",
"Wait state",
"Runaway VFU" };
/* Binary loader -- load carriage control tape
Binary dump -- paper tape dump */
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
if (flag) return pt_dump (fileref, cptr, fnam);
return lp_load (fileref, cptr, fnam);
}
/* Symbol tables */
#define I_V_FL 16 /* class bits */
#define I_M_FL 0xF /* class mask */
#define I_V_MR 0x0 /* mask-register */
#define I_V_RR 0x1 /* register-register */
#define I_V_R 0x2 /* register */
#define I_V_MX 0x3 /* mask-memory */
#define I_V_RX 0x4 /* register-memory */
#define I_V_X 0x5 /* memory */
#define I_V_FF 0x6 /* float reg-reg */
#define I_V_FX 0x7 /* float reg-mem */
#define I_V_SI 0x8 /* short immed */
#define I_V_SB 0x9 /* short branch */
#define I_V_SX 0xA /* short ext branch */
#define I_MR (I_V_MR << I_V_FL)
#define I_RR (I_V_RR << I_V_FL)
#define I_R (I_V_R << I_V_FL)
#define I_MX (I_V_MX << I_V_FL)
#define I_RX (I_V_RX << I_V_FL)
#define I_X (I_V_X << I_V_FL)
#define I_FF (I_V_FF << I_V_FL)
#define I_FX (I_V_FX << I_V_FL)
#define I_SI (I_V_SI << I_V_FL)
#define I_SB (I_V_SB << I_V_FL)
#define I_SX (I_V_SX << I_V_FL)
#define R_X 0 /* no reg */
#define R_M 1 /* reg mask */
#define R_R 2 /* reg int reg */
#define R_F 3 /* reg flt reg */
static const int32 masks[] = {
0xFF00, 0xFF00, 0xFFF0, 0xFF00,
0xFF00, 0xFFF0, 0xFF00, 0xFF00,
0xFF00, 0xFE00, 0xFEF0 };
static const uint32 r1_type[] = {
R_M, R_R, R_X, R_M,
R_R, R_X, R_F, R_F,
R_R, R_M, R_X };
static const uint32 r2_type[] = {
R_X, R_R, R_R, R_X,
R_X, R_X, R_F, R_X,
R_M, R_X, R_X };
static const char *opcode[] = {
"BER", "BNER","BZR", "BNZR",
"BPR", "BNPR","BLR", "BNLR",
"BMR", "BNMR","BOR", "BNOR",
"BCR", "BNCR","BR",
"BES", "BNES","BZS", "BNZS",
"BPS", "BNPS","BLS", "BNLS",
"BMS", "BNMS","BOS", "BNOS",
"BCS", "BNCS","BS",
"BE", "BNE", "BZ", "BNZ",
"BP", "BNP", "BL", "BNL",
"BM", "BNM", "BO", "BNO",
"BC", "BNC", "B",
"BALR","BTCR","BFCR",
"NHR", "CLHR","OHR", "XHR",
"LHR", "CHR", "AHR", "SHR",
"MHR", "DHR", "ACHR","SCHR",
"SETMR",
"BTBS","BTFS","BFBS","BFFS",
"LIS", "LCS", "AIS", "SIS",
"LER", "CER", "AER", "SER",
"MER", "DER", "FXR", "FLR",
"LPSR",
"LDR", "CDR", "ADR", "SDR",
"MDR", "DDR", "FXDR","FLDR",
"STH", "BAL", "BTC", "BFC",
"NH", "CLH", "OH", "XH",
"LH", "CH", "AH", "SH",
"MH", "DH", "ACH", "SCH",
"SETM",
"STE", "AHM",
"ATL", "ABL", "RTL", "RBL",
"LE", "CE", "AE", "SE",
"ME", "DE",
"STD", "STME","LME", "LPS",
"LD", "CD", "AD", "SD",
"MD", "DD", "STMD","LMD",
"SRLS","SLLS","STBR","LBR",
"EXBR","EPSR","WBR", "RBR",
"WHR", "RHR", "WDR", "RDR",
"MHUR","SSR", "OCR", "AIR",
"BXH", "BXLE","LPSW","THI",
"NHI", "CLHI","OHI", "XHI",
"LHI", "CHI", "AHI", "SHI",
"SRHL","SLHL","SRHA","SLHA",
"STM", "LM", "STB", "LB",
"CLB", "AL", "WB", "RB",
"WH", "RH", "WD", "RD",
"MHU", "SS", "OC", "AI",
"SVC", "SINT",
"RRL", "RLL",
"SRL", "SLL", "SRA", "SLA",
NULL };
static const uint32 opc_val[] = {
0x0330+I_R, 0x0230+I_R, 0x0330+I_R, 0x0230+I_R,
0x0220+I_R, 0x0320+I_R, 0x0280+I_R, 0x0380+I_R,
0x0210+I_R, 0x0310+I_R, 0x0240+I_R, 0x0340+I_R,
0x0280+I_R, 0x0380+I_R, 0x0300+I_R,
0x2230+I_SX, 0x2030+I_SX, 0x2230+I_SX, 0x2030+I_SX,
0x2020+I_SX, 0x2220+I_SX, 0x2080+I_SX, 0x2280+I_SX,
0x2010+I_SX, 0x2210+I_SX, 0x2040+I_SX, 0x2240+I_SX,
0x2080+I_SX, 0x2280+I_SX, 0x2200+I_SX,
0x4330+I_X, 0x4230+I_X, 0x4330+I_X, 0x4230+I_X,
0x4220+I_X, 0x4320+I_X, 0x4280+I_X, 0x4380+I_X,
0x4210+I_X, 0x4310+I_X, 0x4240+I_X, 0x4340+I_X,
0x4280+I_X, 0x4380+I_X, 0x4300+I_X,
0x0100+I_RR, 0x0200+I_MR, 0x0300+I_MR,
0x0400+I_RR, 0x0500+I_RR, 0x0600+I_RR, 0x0700+I_RR,
0x0800+I_RR, 0x0900+I_RR, 0x0A00+I_RR, 0x0B00+I_RR,
0x0C00+I_RR, 0x0D00+I_RR, 0x0E00+I_RR, 0x0F00+I_RR,
0x1300+I_RR,
0x2000+I_SB, 0x2100+I_SB, 0x2200+I_SB, 0x2300+I_SB,
0x2400+I_SI, 0x2500+I_SI, 0x2600+I_SI, 0x2700+I_SI,
0x2800+I_FF, 0x2900+I_FF, 0x2A00+I_FF, 0x2B00+I_FF,
0x2C00+I_FF, 0x2D00+I_FF, 0x2E00+I_RR, 0x2F00+I_RR,
0x3300+I_R,
0x3800+I_FF, 0x3900+I_FF, 0x3A00+I_FF, 0x3B00+I_FF,
0x3C00+I_FF, 0x3D00+I_FF, 0x3E00+I_RR, 0x3F00+I_RR,
0x4000+I_RX, 0x4100+I_RX, 0x4200+I_MX, 0x4300+I_MX,
0x4400+I_RX, 0x4500+I_RX, 0x4600+I_RX, 0x4700+I_RX,
0x4800+I_RX, 0x4900+I_RX, 0x4A00+I_RX, 0x4B00+I_RX,
0x4C00+I_RX, 0x4D00+I_RX, 0x4E00+I_RX, 0x4F00+I_RX,
0x5300+I_RX,
0x6000+I_RX, 0x6100+I_RX,
0x6400+I_RX, 0x6500+I_RX, 0x6600+I_RX, 0x6700+I_RX,
0x6800+I_FX, 0x6900+I_FX, 0x6A00+I_FX, 0x6B00+I_FX,
0x6C00+I_FX, 0x6D00+I_FX,
0x7000+I_FX, 0x7100+I_FX, 0x7200+I_FX, 0x7300+I_X,
0x7800+I_FX, 0x7900+I_FX, 0x7A00+I_FX, 0x7B00+I_FX,
0x7C00+I_FX, 0x7D00+I_FX, 0x7E00+I_FX, 0x7F00+I_FX,
0x9000+I_SI, 0x9100+I_SI, 0x9200+I_RR, 0x9300+I_RR,
0x9400+I_RR, 0x9500+I_RR, 0x9600+I_RR, 0x9700+I_RR,
0x9800+I_RR, 0x9900+I_RR, 0x9A00+I_RR, 0x9B00+I_RR,
0x9C00+I_RR, 0x9D00+I_RR, 0x9E00+I_RR, 0x9F00+I_RR,
0xC000+I_RX, 0xC100+I_RX, 0xC200+I_X, 0xC300+I_RX,
0xC400+I_RX, 0xC500+I_RX, 0xC600+I_RX, 0xC700+I_RX,
0xC800+I_RX, 0xC900+I_RX, 0xCA00+I_RX, 0xCB00+I_RX,
0xCC00+I_RX, 0xCD00+I_RX, 0xCE00+I_RX, 0xCF00+I_RX,
0xD000+I_RX, 0xD100+I_RX, 0xD200+I_RX, 0xD300+I_RX,
0xD400+I_RX, 0xD500+I_X, 0xD600+I_RX, 0xD700+I_RX,
0xD800+I_RX, 0xD900+I_RX, 0xDA00+I_RX, 0xDB00+I_RX,
0xDC00+I_RX, 0xDD00+I_RX, 0xDE00+I_RX, 0xDF00+I_RX,
0xE100+I_RX, 0xE200+I_RX,
0xEA00+I_RX, 0xEB00+I_RX,
0xEC00+I_RX, 0xED00+I_RX, 0xEE00+I_RX, 0xEF00+I_RX,
0xFFFF };
#define GETNUM(d,n) for (k = d = 0; k < n; k++) \
d = (d << 8) | (((uint32) val[vp++]) & 0xFF)
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = values to decode
*uptr = pointer to unit
sw = switches
Outputs:
return = if >= 0, error code
if < 0, number of extra bytes retired
*/
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
int32 c, k, num, rdx, vp, lnt;
t_stat r;
DEVICE *dptr;
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL) return SCPE_IERR;
if (dptr->dwidth != 8) return SCPE_ARG; /* byte dev only */
if (sw & SWMASK ('B')) lnt = 1; /* get length */
else if (sw & SWMASK ('W')) lnt = 2;
else if (sw & SWMASK ('F')) lnt = 4;
else lnt = (uptr == &cpu_unit)? 2: 1;
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
else if (sw & SWMASK ('O')) rdx = 8;
else if (sw & SWMASK ('H')) rdx = 16;
else rdx = dptr->dradix;
vp = 0; /* init ptr */
if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */
if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */
if ((val[0] & 0x7F) == 0) return SCPE_ARG;
while (vp < lnt) { /* print string */
if ((c = (uint32) val[vp++] & 0x7F) == 0) break;
fprintf (of, (c < 0x20)? "<%02X>": "%c", c); }
return -(vp - 1); } /* return # chars */
if (sw & SWMASK ('M')) { /* inst format? */
r = fprint_sym_m (of, addr, val); /* decode inst */
if (r <= 0) return r; }
GETNUM (num, lnt); /* get number */
fprint_val (of, num, rdx, lnt * 8, PV_RZRO);
return -(vp - 1);
}
/* Symbolic decode for -m
Inputs:
of = output stream
addr = current PC
*val = values to decode
Outputs:
return = if >= 0, error code
if < 0, number of extra bytes retired
*/
t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val)
{
uint32 i, j, k, inst, r1, r2, ea, tgt, vp;
vp = 0;
GETNUM (inst, 2); /* first 16b */
GETNUM (ea, 2); /* second 16b */
for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((opc_val[i] & 0xFFFF) == (inst & masks[j])) { /* match? */
r1 = (inst >> 4) & 0xF;
r2 = inst & 0xF;
switch (j) { /* case on class */
case I_V_MR: /* mask-register */
fprintf (of, "%s %-X,R%d", opcode[i], r1, r2);
return -1;
case I_V_RR: /* register-register */
case I_V_FF: /* floating-floating */
fprintf (of, "%s R%d,R%d", opcode[i], r1, r2);
return -1;
case I_V_SI: /* short immediate */
fprintf (of, "%s R%d,%-X", opcode[i], r1, r2);
return -1;
case I_V_SB: /* short branch */
if (inst & MSK_SBF) tgt = addr + r2 + r2;
else tgt = addr - r2 - r2;
fprintf (of, "%s %-X,%-X", opcode[i], r1, tgt);
return -1;
case I_V_SX: /* ext short branch */
if (inst & MSK_SBF) tgt = addr + r2 + r2;
else tgt = addr - r2 - r2;
fprintf (of, "%s %-X", opcode[i], tgt);
return -1;
case I_V_R: /* register */
fprintf (of, "%s R%d", opcode[i], r2);
return -1;
case I_V_MX: /* mask-memory */
fprintf (of, "%s %-X,%-X", opcode[i], r1, ea);
break;
case I_V_RX: /* register-memory */
case I_V_FX: /* floating-memory */
fprintf (of, "%s R%d,%-X", opcode[i], r1, ea);
break;
case I_V_X: /* memory */
fprintf (of, "%s %-X", opcode[i], ea);
break; } /* end case */
if (r2) fprintf (of, "(R%d)", r2);
return -3; } /* end if */
} /* end for */
return SCPE_ARG; /* no match */
}
/* Register number
Inputs:
*cptr = pointer to input string
**optr = pointer to pointer to next char
rtype = mask, integer, or float
Outputs:
rnum = output register number, -1 if error
*/
int32 get_reg (char *cptr, char **optr, int32 rtype)
{
int32 reg;
if ((*cptr == 'R') || (*cptr == 'r')) { /* R? */
cptr++; /* skip */
if (rtype == R_M) return -1; } /* cant be mask */
if ((*cptr >= '0') && (*cptr <= '9')) {
reg = *cptr++ - '0';
if ((*cptr >= '0') && (*cptr <= '9'))
reg = (reg * 10) + (*cptr - '0');
else --cptr;
if (reg > 0xF) return -1; }
else if ((*cptr >= 'a') && (*cptr <= 'f')) reg = (*cptr - 'a') + 10;
else if ((*cptr >= 'A') && (*cptr <= 'F')) reg = (*cptr - 'A') + 10;
else return -1;
if ((rtype == R_F) && (reg & 1)) return -1;
*optr = cptr + 1;
return reg;
}
#define PUTNUM(d,n) for (k = n; k > 0; k--) \
val[vp++] = (d >> ((k - 1) * 8)) & 0xFF
/* Symbolic input */
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 k, rdx, lnt, num, vp;
t_stat r;
DEVICE *dptr;
static const uint32 maxv[5] = { 0, 0xFF, 0xFFFF, 0, 0xFFFFFFFF };
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL) return SCPE_IERR;
if (dptr->dwidth != 8) return SCPE_ARG; /* byte dev only */
if (sw & SWMASK ('B')) lnt = 1; /* get length */
else if (sw & SWMASK ('W')) lnt = 2;
else if (sw & SWMASK ('F')) lnt = 4;
else lnt = (uptr == &cpu_unit)? 2: 1;
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
else if (sw & SWMASK ('O')) rdx = 8;
else if (sw & SWMASK ('H')) rdx = 16;
else rdx = dptr->dradix;
vp = 0;
if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */
if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */
if (*cptr == 0) return SCPE_ARG;
while ((vp < lnt) && *cptr) { /* get chars */
val[vp++] = *cptr++; }
return -(vp - 1); } /* return # chars */
if (uptr == &cpu_unit) { /* cpu only */
r = parse_sym_m (cptr, addr, val); /* try to parse inst */
if (r <= 0) return r; }
num = (int32) get_uint (cptr, rdx, maxv[lnt], &r); /* get number */
if (r != SCPE_OK) return r;
PUTNUM (num, lnt); /* store */
return -(lnt - 1);
}
/* Symbolic input for -m
Inputs:
*cptr = pointer to input string
addr = current PC
*val = pointer to output values
Outputs:
status = > 0 error code
<= 0 -number of extra words
*/
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val)
{
uint32 i, j, k, t, df, db, inst, ea, vp;
int32 r1, r2;
t_stat r;
char *tptr, gbuf[CBUFSIZE];
vp = 0;
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
inst = opc_val[i] & 0xFFFF; /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if (r1_type[j]) { /* any R1 field? */
cptr = get_glyph (cptr, gbuf, ','); /* get R1 field */
if ((r1 = get_reg (gbuf, &tptr, r1_type[j])) < 0)
return SCPE_ARG;
if (*tptr != 0) return SCPE_ARG; /* all done? */
inst = inst | (r1 << 4); } /* or in R1 */
cptr = get_glyph (cptr, gbuf, 0); /* get operand */
if (*cptr) return SCPE_ARG; /* should be end */
switch (j) { /* case on class */
case I_V_FF: case I_V_SI: /* flt-flt, sh imm */
case I_V_MR: case I_V_RR: /* mask/reg-reg */
case I_V_R: /* register */
if ((r2 = get_reg (gbuf, &tptr, r2_type[j])) < 0)
return SCPE_ARG;
if (*tptr != 0) return SCPE_ARG; /* all done? */
inst = inst | r2; /* or in R2 */
break;
case I_V_FX: /* float-memory */
case I_V_MX: case I_V_RX: /* mask/reg-mem */
case I_V_X: /* memory */
errno = 0;
ea = strtoul (gbuf, &tptr, 16); /* get address */
if (errno || (gbuf == tptr)) return SCPE_ARG; /* error? */
if (*tptr == '(') { /* index? */
if ((r2 = get_reg (tptr + 1, &tptr, R_R)) < 0)
return SCPE_ARG;
if (*tptr++ != ')') return SCPE_ARG;
inst = inst | r2; } /* or in R2 */
if (*tptr != 0) return SCPE_ARG;
PUTNUM (inst, 2);
PUTNUM (ea, 2);
return -3;
case I_V_SB: case I_V_SX: /* short branches */
t = get_uint (gbuf, 16, DMASK16, &r); /* get addr */
if ((r != SCPE_OK) || (t & 1)) return r; /* error if odd */
db = (addr - t) & 0x1F; /* back displ */
df = (t - addr) & 0x1F; /* fwd displ */
if ((t == ((addr - db) & VAMASK16)) && /* back work and */
((j == I_V_SX) || !(inst & MSK_SBF))) { /* ext or back br? */
inst = inst | (db >> 1); /* or in back displ */
break; }
if ((t == ((addr + df) & VAMASK16)) && /* fwd work and */
((j == I_V_SX) || (inst & MSK_SBF))) { /* ext or fwd br? */
inst = inst | (df >> 1) | MSK_SBF; /* or in fwd displ */
break; }
return SCPE_ARG; } /* end case */
PUTNUM (inst, 2);
return -1;
}

2025
Interdata/id32_cpu.c Normal file

File diff suppressed because it is too large Load diff

308
Interdata/id32_dboot.c Normal file
View file

@ -0,0 +1,308 @@
/* id32_dboot.c: Interdata 32b simulator disk bootstrap
Copyright (c) 2000-2002, 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.
*/
#include "id_defs.h"
#define DBOOT_BEG 0x1000
#define DBOOT_START 0x100E
#define DBOOT_LEN (sizeof (dboot_rom) / sizeof (uint8))
/* Transcribed from 32b Bootstrap Loader, 03-074N81R03A13 */
static uint8 dboot_rom[] = {
0xca, 0xf0, 0x00, 0x30,
0xc5, 0xf0, 0x00, 0x3a,
0x02, 0x8e,
0x26, 0xf7,
0x03, 0x0e,
0xe6, 0xd0, 0x0f, 0x30,
0xd1, 0xe0, 0x00, 0x78,
0xd0, 0xed, 0x03, 0x40,
0xd3, 0xf0, 0x00, 0x7e,
0xc4, 0xf0, 0x00, 0x0f,
0x41, 0xed, 0x00, 0xd0,
0xd2, 0xfd, 0x03, 0x25,
0xd3, 0xf0, 0x00, 0x7f,
0x10, 0xf4,
0x41, 0xed, 0x00, 0xd0,
0xd2, 0xfd, 0x03, 0x26,
0xd3, 0xf0, 0x00, 0x7f,
0xc4, 0xf0, 0x00, 0x0f,
0x41, 0xed, 0x00, 0xd0,
0xd2, 0xfd, 0x03, 0x27,
0xd3, 0x20, 0x00, 0x7d,
0xd3, 0x30, 0x00, 0x7c,
0xd3, 0x40, 0x00, 0x7a,
0x24, 0x50,
0xd3, 0xf0, 0x00, 0x7b,
0xcb, 0xf0, 0x00, 0x33,
0x23, 0x23,
0x11, 0xf1,
0x08, 0x5f,
0xe6, 0x7d, 0x03, 0x50,
0xe6, 0x8d, 0x04, 0x4f,
0x07, 0xcc,
0x41, 0xed, 0x01, 0xfc,
0xd1, 0xed, 0x03, 0x5c,
0xd0, 0xed, 0x03, 0x48,
0x58, 0xcd, 0x03, 0x58,
0x43, 0x3d, 0x01, 0x9c,
0xe6, 0x7d, 0x03, 0x50,
0x41, 0xed, 0x01, 0xfc,
0xe6, 0xed, 0x03, 0x54,
0x24, 0x15,
0xf8, 0xf0, 0x4f, 0x53, 0x33, 0x32,
0xd3, 0x7e, 0x00, 0x24,
0xc3, 0x70, 0x00, 0x10,
0x23, 0x3e,
0xce, 0x70, 0x00, 0xe0,
0x21, 0xeb,
0x55, 0xfe, 0x00, 0x00,
0x21, 0x38,
0x58, 0x6e, 0x00, 0x08,
0x10, 0x68,
0x55, 0x6d, 0x03, 0x24,
0x44, 0x3d, 0x01, 0xb2,
0xca, 0xe0, 0x00, 0x30,
0x27, 0x11,
0x42, 0x3d, 0x01, 0x66,
0x58, 0xcd, 0x03, 0x50,
0x42, 0x3d, 0x01, 0x52,
0x48, 0x10, 0x00, 0x7e,
0x42, 0x3d, 0x02, 0xf0,
0x58, 0xcd, 0x03, 0x48,
0x43, 0x3d, 0x02, 0xf0,
0x58, 0x8d, 0x03, 0x4c,
0x23, 0x07,
0x58, 0xce, 0x00, 0x0c,
0x58, 0x8e, 0x00, 0x10,
0x0b, 0x8c,
0x26, 0xc1,
0x11, 0x88,
0x08, 0x18,
0xe6, 0xf0, 0x11, 0x18,
0x58, 0x0f, 0x00, 0x00,
0x50, 0x01, 0x00, 0x00,
0x59, 0x01, 0x00, 0x00,
0x42, 0x3d, 0x03, 0x08,
0x26, 0xf4,
0x26, 0x14,
0xc5, 0xf0, 0x12, 0x78,
0x20, 0x8c,
0x08, 0xd8,
0xcb, 0xd0, 0x01, 0xe8,
0x03, 0x08,
0x27, 0x81,
0x07, 0x77,
0x41, 0xed, 0x01, 0xfc,
0xd1, 0xed, 0x03, 0x40,
0xd0, 0xe0, 0x00, 0x78,
0x43, 0x00, 0x00, 0x60,
0xde, 0x2d, 0x03, 0x28,
0x08, 0x0c,
0x4d, 0x0d, 0x45, 0x00, 0x03, 0x30,
0x08, 0x91,
0x4d, 0x0d, 0x45, 0x00, 0x03, 0x38,
0x08, 0xa1,
0x08, 0xb0,
0x08, 0x55,
0x42, 0x2d, 0x02, 0x4a,
0xde, 0x3d, 0x03, 0x28,
0x9d, 0x3f,
0x22, 0x21,
0x9d, 0x4f,
0x42, 0x1d, 0x02, 0xf4,
0xc3, 0xf0, 0x00, 0x10,
0x20, 0x35,
0x11, 0xa5,
0x06, 0xba,
0x98, 0x49,
0xde, 0x4d, 0x03, 0x28,
0x9d, 0x3f,
0x22, 0x21,
0x9d, 0x4f,
0x42, 0x7d, 0x02, 0xf8,
0x20, 0x83,
0x41, 0x6d, 0x02, 0x96,
0x22, 0x0b,
0x9d, 0x4f,
0xc3, 0xf0, 0x00, 0x19,
0x42, 0x3d, 0x02, 0xfc,
0xde, 0x4d, 0x03, 0x2c,
0x9d, 0x3f,
0x22, 0x21,
0x98, 0x49,
0xde, 0x4d, 0x03, 0x2e,
0x9d, 0x3f,
0x22, 0x21,
0xde, 0x4d, 0x03, 0x2d,
0x9d, 0x3f,
0x22, 0x21,
0x98, 0x4a,
0xde, 0x4d, 0x03, 0x2f,
0x0d, 0x3f,
0x22, 0x21,
0xde, 0x4d, 0x03, 0x2b,
0x9d, 0x3f,
0x22, 0x21,
0x9d, 0x4f,
0x20, 0x81,
0xc3, 0xf0, 0x00, 0x53,
0x42, 0x3d, 0x03, 0x00,
0x08, 0xfa,
0x11, 0xfa,
0x06, 0xf9,
0xe6, 0x6d, 0x02, 0x54,
0x34, 0x77,
0x9a, 0x27,
0x34, 0x77,
0x98, 0x27,
0x34, 0x88,
0x9a, 0x28,
0x34, 0x88,
0x98, 0x28,
0x08, 0x55,
0x21, 0x24,
0x98, 0x49,
0x9a, 0x3b,
0x23, 0x03,
0x9a, 0x3b,
0x98, 0x3f,
0xde, 0x3d, 0x03, 0x2a,
0xde, 0x2d, 0x03, 0x29,
0x9d, 0x2f,
0x20, 0x81,
0xde, 0x2d, 0x03, 0x28,
0x9b, 0x20,
0x99, 0x21,
0x34, 0x00,
0x06, 0x01,
0xde, 0x2d, 0x03, 0x28,
0x9d, 0x3f,
0x22, 0x21,
0x42, 0x1d, 0x03, 0x04,
0xc3, 0xf0, 0x00, 0x10,
0x03, 0x3e,
0x0b, 0x07,
0x26, 0x04,
0xc4, 0x00, 0xff, 0x00,
0x0a, 0x70,
0x26, 0x91,
0x07, 0xaa,
0x07, 0xbb,
0x03, 0x06,
0x24, 0x11,
0x23, 0x0c,
0x24, 0x12,
0x23, 0x0a,
0x24, 0x13,
0x23, 0x08,
0x24, 0x14,
0x23, 0x06,
0x24, 0x15,
0x23, 0x04,
0x24, 0x16,
0x23, 0x02,
0x24, 0x17,
0x24, 0x01,
0xde, 0x0d, 0x03, 0x28,
0x9a, 0x01,
0xde, 0x0d, 0x03, 0x28,
0xd1, 0xed, 0x03, 0x40,
0xd0, 0xe0, 0x00, 0x78,
0x11, 0x0f,
0x95, 0x10,
0x22, 0x01,
0x00, 0x00, 0x00, 0x00,
0x48, 0x30,
0xc1, 0xc2,
0xc8, 0xc4,
0xd0, 0xe0,
0x00, 0x30,
0x01, 0x90,
0x01, 0x40,
0x04, 0xc0,
0x00, 0x18,
0x00, 0x14,
0x00, 0x40,
0x00, 0x40,
0x00
};
/* Lower memory setup
78 = binary input device address
79 = binary device input command
7A = disk device number
7B = device code
7C = disk controller address
7D = selector channel address
7E:7F = operating system extension (user specified)
*/
struct dboot_id {
char *name;
uint32 cap;
uint32 dtype;
uint32 offset;
};
static struct dboot_id dboot_tab[] = {
{ "DP", 2, 0x31, o_DP0 },
{ "DP", 9, 0x33, o_DP0 },
{ "DM", 64, 0x35, o_ID0 },
{ "DM", 244, 0x36, o_ID0 },
{ NULL } };
t_stat id_dboot (int32 u, DEVICE *dptr)
{
extern DIB pt_dib, sch_dib;
extern uint32 PC;
uint32 i, typ, ctlno, off, cap, sch_dev;
UNIT *uptr;
DIB *ddib = (DIB *) dptr->ctxt; /* get disk DIB */
ctlno = ddib->dno; /* get ctrl devno */
sch_dev = sch_dib.dno + ddib->sch; /* sch dev # */
uptr = dptr->units + u; /* get capacity */
cap = uptr->capac >> 20;
for (i = typ = 0; dboot_tab[i].name != NULL; i++) {
if ((strcmp (dboot_tab[i].name, dptr->name) == 0) &&
(dboot_tab[i].cap == cap)) {
typ = dboot_tab[i].dtype;
off = dboot_tab[i].offset; } }
if (typ == 0) return SCPE_NOFNC;
IOWriteBlk (DBOOT_BEG, DBOOT_LEN, dboot_rom); /* copy boot */
IOWriteB (AL_DEV, pt_dib.dno); /* bin input dev */
IOWriteB (AL_IOC, 0x99);
IOWriteB (AL_DSKU, ctlno + ((u + 1) * off)); /* disk param */
IOWriteB (AL_DSKT, typ);
IOWriteB (AL_DSKC, ctlno);
IOWriteB (AL_SCH, sch_dev);
PC = DBOOT_START;
return SCPE_OK;
}

641
Interdata/id32_sys.c Normal file
View file

@ -0,0 +1,641 @@
/* id32_sys.c: Interdata 32b simulator interface
Copyright (c) 2000-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.
23-Dec-01 RMS Cloned from ID4 sources
*/
#include "id_defs.h"
#include <ctype.h>
#define MSK_SBF 0x0100
#define SEXT15(x) (((x) & 0x4000)? ((x) | 0xFFFF8000): ((x) & 0x7FFF))
extern DEVICE cpu_dev;
extern DEVICE sch_dev;
extern DEVICE pt_dev;
extern DEVICE tt_dev, ttp_dev;
extern DEVICE pas_dev, pasl_dev;
extern DEVICE lpt_dev;
extern DEVICE pic_dev, lfc_dev;
extern DEVICE dp_dev, idc_dev;
extern DEVICE fd_dev, mt_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern uint32 *M;
t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val);
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val);
extern t_stat lp_load (FILE *fileref, char *cptr, char *fnam);
extern pt_dump (FILE *of, char *cptr, char *fnam);
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "Interdata 32b";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 6;
DEVICE *sim_devices[] = {
&cpu_dev,
&sch_dev,
&pt_dev,
&tt_dev,
&ttp_dev,
&pas_dev,
&pasl_dev,
&pic_dev,
&lfc_dev,
&lpt_dev,
&dp_dev,
&idc_dev,
&fd_dev,
&mt_dev,
NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"Reserved instruction",
"HALT instruction",
"Breakpoint",
"Wait state",
"Runaway VFU" };
/* Binary loader -- load carriage control tape
Binary dump -- paper tape dump */
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
if (flag) return pt_dump (fileref, cptr, fnam);
return lp_load (fileref, cptr, fnam);
}
/* Symbol tables */
#define I_V_FL 16 /* class bits */
#define I_M_FL 0xF /* class mask */
#define I_V_MR 0x0 /* mask-register */
#define I_V_RR 0x1 /* register-register */
#define I_V_R 0x2 /* register */
#define I_V_MX 0x3 /* mask-memory */
#define I_V_RX 0x4 /* register-memory */
#define I_V_X 0x5 /* memory */
#define I_V_FF 0x6 /* float reg-reg */
#define I_V_FX 0x7 /* float reg-mem */
#define I_V_SI 0x8 /* short immed */
#define I_V_SB 0x9 /* short branch */
#define I_V_SX 0xA /* short ext branch */
#define I_V_RI 0xB /* halfword imm */
#define I_V_RF 0xC /* fullword imm */
#define I_MR (I_V_MR << I_V_FL)
#define I_RR (I_V_RR << I_V_FL)
#define I_R (I_V_R << I_V_FL)
#define I_MX (I_V_MX << I_V_FL)
#define I_RX (I_V_RX << I_V_FL)
#define I_X (I_V_X << I_V_FL)
#define I_FF (I_V_FF << I_V_FL)
#define I_FX (I_V_FX << I_V_FL)
#define I_SI (I_V_SI << I_V_FL)
#define I_SB (I_V_SB << I_V_FL)
#define I_SX (I_V_SX << I_V_FL)
#define I_RI (I_V_RI << I_V_FL)
#define I_RF (I_V_RF << I_V_FL)
#define R_X 0 /* no R1 */
#define R_M 1 /* R1 mask */
#define R_R 2 /* R1 int reg */
#define R_F 3 /* R1 flt reg */
static const int32 masks[] = {
0xFF00, 0xFF00, 0xFFF0, 0xFF00,
0xFF00, 0xFFF0, 0xFF00, 0xFF00,
0xFF00, 0xFE00, 0xFEF0, 0xFF00,
0xFF00 };
static const uint32 r1_type[] = {
R_M, R_R, R_X, R_M,
R_R, R_X, R_F, R_F,
R_R, R_M, R_X, R_R,
R_R };
static const uint32 r2_type[] = {
R_X, R_R, R_R, R_X,
R_X, R_X, R_F, R_X,
R_M, R_X, R_X, R_X,
R_X };
static const char *opcode[] = {
"BER", "BNER","BZR", "BNZR",
"BPR", "BNPR","BLR", "BNLR",
"BMR", "BNMR","BOR", "BNOR",
"BCR", "BNCR","BR",
"BES", "BNES","BZS", "BNZS",
"BPS", "BNPS","BLS", "BNLS",
"BMS", "BNMS","BOS", "BNOS",
"BCS", "BNCS","BS",
"BE", "BNE", "BZ", "BNZ",
"BP", "BNP", "BL", "BNL",
"BM", "BNM", "BO", "BNO",
"BC", "BNC", "B",
"BALR","BTCR","BFCR",
"NR", "CLR", "OR", "XR",
"LR", "CHR", "AR", "SR",
"MHR", "DHR",
"SRLS","SLLS","CHVR",
"LPSWR",
"MR", "DR",
"BTBS","BTFS","BFBS","BFFS",
"LIS", "LCS", "AIS", "SIS",
"LER", "CER", "AER", "SER",
"MER", "DER", "FXR", "FLR",
"MPBSR", "PBR",
"EXHR",
"LDR", "CDR", "ADR", "SDR",
"MDR", "DDR", "FXDR","FLDR",
"STH", "BAL", "BTC", "BFC",
"NH", "CLH", "OH", "XH",
"LH", "CH", "AH", "SH",
"MH", "DH",
"ST", "AM",
"N", "CL", "O", "X",
"L", "C", "A", "S",
"M", "D", "CRC12","CRC16",
"STE", "AHM", "PB", "LRA",
"ATL", "ABL", "RTL", "RBL",
"LE", "CE", "AE", "SE",
"ME", "DE",
"STD", "STME","LME", "LHL",
"TBT", "SBT", "RBT", "CBT",
"LD", "CD", "AD", "SD",
"MD", "DD", "STMD","LMD",
"SRHLS","SLHLS","STBR","LBR",
"EXBR","EPSR","WBR", "RBR",
"WHR", "RHR", "WDR", "RDR",
"SSR", "OCR",
"BXH", "BXLE","LPSW","THI",
"NHI", "CLHI","OHI", "XHI",
"LHI", "CHI", "AHI", "SHI",
"SRHL","SLHL","SRHA","SLHA",
"STM", "LM", "STB", "LB",
"CLB", "AL", "WB", "RB",
"WH", "RH", "WD", "RD",
"SS", "OC",
"TS", "SVC", "SINT","SCP",
"LA", "TLATE",
"RRL", "RLL",
"SRL", "SLL", "SRA", "SLA",
"TI",
"NI", "CLI", "OI", "XI",
"LI", "CI", "AI", "SI",
NULL };
static const uint32 opc_val[] = {
0x0330+I_R, 0x0230+I_R, 0x0330+I_R, 0x0230+I_R,
0x0220+I_R, 0x0320+I_R, 0x0280+I_R, 0x0380+I_R,
0x0210+I_R, 0x0310+I_R, 0x0240+I_R, 0x0340+I_R,
0x0280+I_R, 0x0380+I_R, 0x0300+I_R,
0x2230+I_SX, 0x2030+I_SX, 0x2230+I_SX, 0x2030+I_SX,
0x2020+I_SX, 0x2220+I_SX, 0x2080+I_SX, 0x2280+I_SX,
0x2010+I_SX, 0x2210+I_SX, 0x2040+I_SX, 0x2240+I_SX,
0x2080+I_SX, 0x2280+I_SX, 0x2200+I_SX,
0x4330+I_X, 0x4230+I_X, 0x4330+I_X, 0x4230+I_X,
0x4220+I_X, 0x4320+I_X, 0x4280+I_X, 0x4380+I_X,
0x4210+I_X, 0x4310+I_X, 0x4240+I_X, 0x4340+I_X,
0x4280+I_X, 0x4380+I_X, 0x4300+I_X,
0x0100+I_RR, 0x0200+I_MR, 0x0300+I_MR,
0x0400+I_RR, 0x0500+I_RR, 0x0600+I_RR, 0x0700+I_RR,
0x0800+I_RR, 0x0900+I_RR, 0x0A00+I_RR, 0x0B00+I_RR,
0x0C00+I_RR, 0x0D00+I_RR,
0x1000+I_SI, 0x1100+I_SI, 0x1200+I_RR,
0x1800+I_RR,
0x1C00+I_RR, 0x1D00+I_RR,
0x2000+I_SB, 0x2100+I_SB, 0x2200+I_SB, 0x2300+I_SB,
0x2400+I_SI, 0x2500+I_SI, 0x2600+I_SI, 0x2700+I_SI,
0x2800+I_FF, 0x2900+I_FF, 0x2A00+I_FF, 0x2B00+I_FF,
0x2C00+I_FF, 0x2D00+I_FF, 0x2E00+I_RR, 0x2F00+I_RR,
0x3000+I_RR, 0x3200+I_RR,
0x3400+I_RR,
0x3800+I_FF, 0x3900+I_FF, 0x3A00+I_FF, 0x3B00+I_FF,
0x3C00+I_FF, 0x3D00+I_FF, 0x3E00+I_RR, 0x3F00+I_RR,
0x4000+I_RX, 0x4100+I_RX, 0x4200+I_MX, 0x4300+I_MX,
0x4400+I_RX, 0x4500+I_RX, 0x4600+I_RX, 0x4700+I_RX,
0x4800+I_RX, 0x4900+I_RX, 0x4A00+I_RX, 0x4B00+I_RX,
0x4C00+I_RX, 0x4D00+I_RX,
0x5000+I_RX, 0x5100+I_RX,
0x5400+I_RX, 0x5500+I_RX, 0x5600+I_RX, 0x5700+I_RX,
0x5800+I_RX, 0x5900+I_RX, 0x5A00+I_RX, 0x5B00+I_RX,
0x5C00+I_RX, 0x5D00+I_RX, 0x5E00+I_RX, 0x5F00+I_RX,
0x6000+I_RX, 0x6100+I_RX, 0x6200+I_RX, 0x6300+I_RX,
0x6400+I_RX, 0x6500+I_RX, 0x6600+I_RX, 0x6700+I_RX,
0x6800+I_FX, 0x6900+I_FX, 0x6A00+I_FX, 0x6B00+I_FX,
0x6C00+I_FX, 0x6D00+I_FX,
0x7000+I_FX, 0x7100+I_FX, 0x7200+I_FX, 0x7300+I_RX,
0x7400+I_RX, 0x7500+I_RX, 0x7600+I_RX, 0x7700+I_RX,
0x7800+I_FX, 0x7900+I_FX, 0x7A00+I_FX, 0x7B00+I_FX,
0x7C00+I_FX, 0x7D00+I_FX, 0x7E00+I_FX, 0x7F00+I_FX,
0x9000+I_SI, 0x9100+I_SI, 0x9200+I_RR, 0x9300+I_RR,
0x9400+I_RR, 0x9500+I_RR, 0x9600+I_RR, 0x9700+I_RR,
0x9800+I_RR, 0x9900+I_RR, 0x9A00+I_RR, 0x9B00+I_RR,
0x9D00+I_RR, 0x9E00+I_RR,
0xC000+I_RX, 0xC100+I_RX, 0xC200+I_RX, 0xC300+I_RI,
0xC400+I_RI, 0xC500+I_RI, 0xC600+I_RI, 0xC700+I_RI,
0xC800+I_RI, 0xC900+I_RI, 0xCA00+I_RI, 0xCB00+I_RI,
0xCC00+I_RI, 0xCD00+I_RI, 0xCE00+I_RI, 0xCF00+I_RI,
0xD000+I_RX, 0xD100+I_RX, 0xD200+I_RX, 0xD300+I_RX,
0xD400+I_RX, 0xD500+I_X, 0xD600+I_RX, 0xD700+I_RX,
0xD800+I_RX, 0xD900+I_RX, 0xDA00+I_RX, 0xDB00+I_RX,
0xDD00+I_RX, 0xDE00+I_RX,
0xE000+I_RX, 0xE100+I_RX, 0xE200+I_RI, 0xE300+I_RX,
0xE600+I_RX, 0xE700+I_RX,
0xEA00+I_RI, 0xEB00+I_RI,
0xEC00+I_RI, 0xED00+I_RI, 0xEE00+I_RI, 0xEF00+I_RI,
0xF300+I_RF,
0xF400+I_RF, 0xF500+I_RF, 0xF600+I_RF, 0xF700+I_RF,
0xF800+I_RF, 0xF900+I_RF, 0xFA00+I_RF, 0xFB00+I_RF,
0xFFFF };
/* Print an RX specifier */
t_stat fprint_addr (FILE *of, t_addr addr, uint32 rx, uint32 ea1, uint32 ea2)
{
uint32 rx2;
if ((ea1 & 0xC000) == 0) { /* RX1 */
fprintf (of, "%-X", ea1);
if (rx) fprintf (of, "(R%d)", rx);
return -3; }
if (ea1 & 0x8000) { /* RX2 */
ea1 = addr + 4 + SEXT15 (ea1);
fprintf (of, "%-X", ea1 & VAMASK32);
if (rx) fprintf (of, "(R%d)", rx);
return -3; }
rx2 = (ea1 >> 8) & 0xF;
fprintf (of, "%-X", ((ea1 << 16) | ea2) & VAMASK32);
if (rx && !rx2) fprintf (of, "(R%d)", rx);
if (rx2) fprintf (of, "(R%d,R%d)", rx, rx2);
return -5;
}
#define GETNUM(d,n) for (k = d = 0; k < n; k++) \
d = (d << 8) | (((uint32) val[vp++]) & 0xFF)
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = values to decode
*uptr = pointer to unit
sw = switches
Outputs:
return = if >= 0, error code
if < 0, number of extra bytes retired
*/
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
int32 c, k, num, rdx, vp, lnt;
t_stat r;
DEVICE *dptr;
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL) return SCPE_IERR;
if (dptr->dwidth != 8) return SCPE_ARG; /* byte dev only */
if (sw & SWMASK ('B')) lnt = 1; /* get length */
else if (sw & SWMASK ('W')) lnt = 2;
else if (sw & SWMASK ('F')) lnt = 4;
else lnt = (uptr == &cpu_unit)? 4: 1;
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
else if (sw & SWMASK ('O')) rdx = 8;
else if (sw & SWMASK ('H')) rdx = 16;
else rdx = dptr->dradix;
vp = 0; /* init ptr */
if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */
if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */
if ((val[0] & 0x7F) == 0) return SCPE_ARG;
while (vp < lnt) { /* print string */
if ((c = (uint32) val[vp++] & 0x7F) == 0) break;
fprintf (of, (c < 0x20)? "<%02X>": "%c", c); }
return -(vp - 1); } /* return # chars */
if (sw & SWMASK ('M')) { /* inst format? */
r = fprint_sym_m (of, addr, val); /* decode inst */
if (r <= 0) return r; /* success? */
lnt = 2; } /* no, skip 16b */
GETNUM (num, lnt); /* get number */
fprint_val (of, num, rdx, lnt * 8, PV_RZRO);
return -(vp - 1);
}
/* Symbolic decode for -m
Inputs:
of = output stream
addr = current PC
*val = values to decode
Outputs:
return = if >= 0, error code
if < 0, number of extra bytes retired
*/
t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val)
{
uint32 i, j, k, inst, r1, r2, ea1, ea2, tgt, vp;
vp = 0;
GETNUM (inst,2); /* high 16b */
GETNUM (ea1, 2); /* next 16b */
GETNUM (ea2, 2); /* next 16b */
for (i = 0; opc_val[i] != 0xFFFF; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((opc_val[i] & 0xFFFF) == (inst & masks[j])) { /* match? */
r1 = (inst >> 4) & 0xF;
r2 = inst & 0xF;
switch (j) { /* case on class */
case I_V_MR: /* mask-register */
fprintf (of, "%s %-X,R%d", opcode[i], r1, r2);
return -1;
case I_V_RR: /* register-register */
case I_V_FF: /* floating-floating */
fprintf (of, "%s R%d,R%d", opcode[i], r1, r2);
return -1;
case I_V_SI: /* short immediate */
fprintf (of, "%s R%d,%-X", opcode[i], r1, r2);
return -1;
case I_V_SB: /* short branch */
if (inst & MSK_SBF) tgt = addr + r2 + r2;
else tgt = addr - r2 - r2;
fprintf (of, "%s %-X,%-X", opcode[i], r1, tgt);
return -1;
case I_V_SX: /* ext short branch */
if (inst & MSK_SBF) tgt = addr + r2 + r2;
else tgt = addr - r2 - r2;
fprintf (of, "%s %-X", opcode[i], tgt);
return -1;
case I_V_R: /* register */
fprintf (of, "%s R%d", opcode[i], r2);
return -1;
case I_V_RI: /* reg-immed */
fprintf (of, "%s R%d,%-X", opcode[i], r1, ea1);
if (r2) fprintf (of, "(R%d)", r2);
return -3;
case I_V_RF: /* reg-full imm */
fprintf (of, "%s R%d,%-X", opcode[i], r1,
(ea1 << 16) | ea2);
if (r2) fprintf (of, "(R%d)", r2);
return -5;
case I_V_MX: /* mask-memory */
fprintf (of, "%s %-X,", opcode[i], r1);
return fprint_addr (of, addr, r2, ea1, ea2);
case I_V_RX: /* register-memory */
case I_V_FX: /* floating-memory */
fprintf (of, "%s R%d,", opcode[i], r1);
return fprint_addr (of, addr, r2, ea1, ea2);
case I_V_X: /* memory */
fprintf (of, "%s ", opcode[i]);
return fprint_addr (of, addr, r2, ea1, ea2); }
return SCPE_IERR; } /* end if */
} /* end for */
return SCPE_ARG; /* no match */
}
/* Register number
Inputs:
*cptr = pointer to input string
**optr = pointer to pointer to next char
rtype = mask, integer, or float
Outputs:
rnum = output register number, -1 if error
*/
int32 get_reg (char *cptr, char **optr, int32 rtype)
{
int32 reg;
if ((*cptr == 'R') || (*cptr == 'r')) { /* R? */
cptr++; /* skip */
if (rtype == R_M) return -1; } /* cant be mask */
if ((*cptr >= '0') && (*cptr <= '9')) {
reg = *cptr++ - '0';
if ((*cptr >= '0') && (*cptr <= '9'))
reg = (reg * 10) + (*cptr - '0');
else --cptr;
if (reg > 0xF) return -1; }
else if ((*cptr >= 'a') && (*cptr <= 'f')) reg = (*cptr - 'a') + 10;
else if ((*cptr >= 'A') && (*cptr <= 'F')) reg = (*cptr - 'A') + 10;
else return -1;
if ((rtype == R_F) && (reg & 1)) return -1;
*optr = cptr + 1;
return reg;
}
/* Immediate
Inputs:
*cptr = pointer to input string
*imm = pointer to output value
*inst = pointer to instruction
max = max value
Outputs:
sta = status
*/
t_stat get_imm (char *cptr, uint32 *imm, uint32 *inst, uint32 max)
{
char *tptr;
uint32 idx;
errno = 0;
*imm = strtoul (cptr, &tptr, 16); /* get immed */
if (errno || (*imm > max) || (cptr == tptr)) return SCPE_ARG;
if (*tptr == '(') { /* index? */
if ((idx = get_reg (tptr + 1, &tptr, R_R)) < 0)
return SCPE_ARG;
if (*tptr++ != ')') return SCPE_ARG;
*inst = *inst | idx; }
if (*tptr != 0) return SCPE_ARG;
return SCPE_OK;
}
#define PUTNUM(d,n) for (k = n; k > 0; k--) \
val[vp++] = (d >> ((k - 1) * 8)) & 0xFF
/* Symbolic input */
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 k, rdx, lnt, num, vp;
t_stat r;
DEVICE *dptr;
static const uint32 maxv[5] = { 0, 0xFF, 0xFFFF, 0, 0xFFFFFFFF };
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL) return SCPE_IERR;
if (dptr->dwidth != 8) return SCPE_ARG; /* byte dev only */
if (sw & SWMASK ('B')) lnt = 1; /* get length */
else if (sw & SWMASK ('W')) lnt = 2;
else if (sw & SWMASK ('F')) lnt = 4;
else lnt = (uptr == &cpu_unit)? 4: 1;
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
else if (sw & SWMASK ('O')) rdx = 8;
else if (sw & SWMASK ('H')) rdx = 16;
else rdx = dptr->dradix;
vp = 0;
if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */
if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */
if (*cptr == 0) return SCPE_ARG;
while ((vp < lnt) && *cptr) { /* get chars */
val[vp++] = *cptr++; }
return -(vp - 1); } /* return # chars */
if (uptr == &cpu_unit) { /* cpu only */
r = parse_sym_m (cptr, addr, val); /* try to parse inst */
if (r <= 0) return r; }
num = (int32) get_uint (cptr, rdx, maxv[lnt], &r); /* get number */
if (r != SCPE_OK) return r;
PUTNUM (num, lnt); /* store */
return -(lnt - 1);
}
/* Symbolic input for -m
Inputs:
*cptr = pointer to input string
addr = current PC
*val = pointer to output values
Outputs:
status = > 0 error code
<= 0 -number of extra words
*/
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val)
{
uint32 i, j, k, t, df, db, inst, ea, vp;
int32 st, r1, r2, rx2;
t_stat r;
char *tptr, gbuf[CBUFSIZE];
vp = 0;
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
inst = opc_val[i] & 0xFFFF; /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if (r1_type[j]) { /* any R1 field? */
cptr = get_glyph (cptr, gbuf, ','); /* get R1 field */
if ((r1 = get_reg (gbuf, &tptr, r1_type[j])) < 0)
return SCPE_ARG;
if (*tptr != 0) return SCPE_ARG;
inst = inst | (r1 << 4); } /* or in R1 */
cptr = get_glyph (cptr, gbuf, 0); /* get operand */
if (*cptr) return SCPE_ARG; /* should be end */
switch (j) { /* case on class */
case I_V_FF: case I_V_SI: /* flt-flt, sh imm */
case I_V_MR: case I_V_RR: /* mask/reg-register */
case I_V_R: /* register */
if ((r2 = get_reg (gbuf, &tptr, r2_type[j])) < 0)
return SCPE_ARG;
if (*tptr != 0) return SCPE_ARG;
inst = inst | r2; /* or in R2 */
break;
case I_V_FX: /* float-memory */
case I_V_MX: case I_V_RX: /* mask/reg-memory */
case I_V_X: /* memory */
errno = 0;
ea = strtoul (gbuf, &tptr, 16); /* get address */
if (errno || (gbuf == tptr)) return SCPE_ARG; /* error? */
rx2 = 0; /* assume no 2nd */
if (*tptr == '(') { /* index? */
if ((r2 = get_reg (tptr + 1, &tptr, R_R)) < 0)
return SCPE_ARG;
inst = inst | r2; /* or in R2 */
if (*tptr == ',') { /* 2nd index? */
if ((rx2 = get_reg (tptr + 1, &tptr, R_R)) < 0)
return SCPE_ARG; }
if (*tptr++ != ')') return SCPE_ARG; } /* all done? */
if (*tptr != 0) return SCPE_ARG;
PUTNUM (inst, 2); /* store inst */
if (rx2 == 0) { /* no 2nd? */
if (ea < 0x4000) { /* RX1? */
PUTNUM (ea, 2); /* store ea */
return -3; }
st = (ea - (addr + 4)); /* displ */
if ((st <= 0x3FFF) && (st >= -0x4000)) { /* RX2? */
t = (st & 0x7FFF) | 0x8000;
PUTNUM (t, 2); /* store displ */
return -3; } }
ea = (ea & VAMASK32) | 0x40000000 | (rx2 << 24);
PUTNUM (ea, 4); /* RX3 */
return -5;
case I_V_RI: /* 16b immediate */
r = get_imm (gbuf, &ea, &inst, DMASK16); /* process imm */
if (r != SCPE_OK) return r;
PUTNUM (inst, 2); /* store inst */
PUTNUM (ea, 2); /* store 16b imm */
return -3;
case I_V_RF:
r = get_imm (gbuf, &ea, &inst, DMASK32); /* process imm */
if (r != SCPE_OK) return r;
PUTNUM (inst, 2); /* store inst */
PUTNUM (ea, 4); /* store 32b imm */
return -5;
case I_V_SB: case I_V_SX: /* short branches */
t = get_uint (gbuf, 16, DMASK16, &r); /* get addr */
if ((r != SCPE_OK) || (t & 1)) return r; /* error if odd */
db = (addr - t) & 0x1F; /* back displ */
df = (t - addr) & 0x1F; /* fwd displ */
if ((t == ((addr - db) & VAMASK16)) && /* back work and */
((j == I_V_SX) || !(inst & MSK_SBF))) { /* ext or back br? */
inst = inst | (db >> 1); /* or in back displ */
break; }
if ((t == ((addr + df) & VAMASK16)) && /* fwd work and */
((j == I_V_SX) || (inst & MSK_SBF))) { /* ext or fwd br? */
inst = inst | (df >> 1) | MSK_SBF; /* or in fwd displ */
break; }
return SCPE_ARG; } /* end case */
PUTNUM (inst, 2);
return -1;
}

483
Interdata/id_defs.h Normal file
View file

@ -0,0 +1,483 @@
/* id_defs.h: Interdata 16b/32b simulator definitions
Copyright (c) 2000-2002, 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.
The author gratefully acknowledges the help of Carl Friend and Al Kossow,
who provided key documents about the Interdata product line.
*/
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_RSRV 1 /* undef instr */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_WAIT 4 /* wait */
#define STOP_VFU 5 /* runaway VFU */
/* Memory */
#define PAWIDTH16 16
#define PAWIDTH16E 18
#define PAWIDTH32 20
#define MAXMEMSIZE16 (1u << PAWIDTH16) /* max mem size, 16b */
#define MAXMEMSIZE16E (1u << PAWIDTH16E) /* max mem size, 16b E */
#define MAXMEMSIZE32 (1u << PAWIDTH32) /* max mem size, 32b */
#define PAMASK16 (MAXMEMSIZE16 - 1) /* phys mem mask */
#define PAMASK16E (MAXMEMSIZE16E - 1)
#define PAMASK32 (MAXMEMSIZE32 - 1)
#define MEMSIZE (cpu_unit.capac) /* act memory size */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
/* Single precision floating point registers */
#if defined (IFP_IN_MEM)
#define ReadFReg(r) (fp_in_hwre? \
F[(r) >> 1]: ReadF (((r) << 1) & ~3, P))
#define WriteFReg(r,v) if (fp_in_hwre) F[(r) >> 1] = (v); \
else WriteF (((r) << 1) & ~3, (v), P)
#else
#define ReadFReg(r) (F[(r) >> 1])
#define WriteFReg(r,v) F[(r) >> 1] = (v)
#endif
/* Double precision floating point registers */
struct dpr {
unsigned int32 h; /* high 32b */
unsigned int32 l; /* low 32b */
};
typedef struct dpr dpr_t;
/* Architectural constants */
#define VAMASK16 (0xFFFF) /* 16b virt addr */
#define VAMASK32 (0x000FFFFF) /* 32b virt addr */
#define SIGN8 0x80 /* 8b sign bit */
#define DMASK8 0xFF /* 8b data mask */
#define MMASK8 0x7F /* 8b magnitude mask */
#define SIGN16 0x8000 /* 16b sign bit */
#define DMASK16 0xFFFF /* 16b data mask */
#define MMASK16 0x7FFF /* 16b magnitude mask */
#define SIGN32 0x80000000 /* 32b sign bit */
#define DMASK32 0xFFFFFFFF /* 32b data mask */
#define MMASK32 0x7FFFFFFF /* 32b magn mask */
#define CC_C 0x8 /* carry */
#define CC_V 0x4 /* overflow */
#define CC_G 0x2 /* greater than */
#define CC_L 0x1 /* less than */
#define CC_MASK (CC_C | CC_V | CC_G | CC_L)
#define PSW_WAIT 0x8000 /* wait */
#define PSW_EXI 0x4000 /* ext intr enable */
#define PSW_MCI 0x2000 /* machine check enable */
#define PSW_AFI 0x1000 /* arith fault enb */
#define PSW_AIO 0x0800 /* auto I/O int enable */
#define PSW_FPF 0x0400 /* flt fault enb, 16b */
#define PSW_REL 0x0400 /* reloc enb, 32b */
#define PSW_SQI 0x0200 /* sys q int enable */
#define PSW_PRO 0x0100 /* protect mode */
#define PSW_V_MAP 4 /* mem map, 16b */
#define PSW_M_MAP 0xF
#define PSW_MAP (PSW_M_MAP << PSW_V_MAP)
#define PSW_V_REG 4 /* reg set, 32b */
#define PSW_M_REG 0x1
#define PSW_ID4 0xF40F /* I3, I4 PSW */
#define PSW_x16 0xFF0F /* 7/16, 8/16 PSW */
#define PSW_816E 0xFFFF /* 8/16E PSW */
#define PSW_x32 0xFFFF /* 7/32, 8/32 PSW */
#define PSW_GETMAP(x) (((x) >> PSW_V_MAP) & PSW_M_MAP)
#define PSW_GETREG(x) (((x) >> PSW_V_REG) & PSW_M_REG)
#define MCKOPSW 0x20 /* mchk old PSW, 32b */
#define FPFPSW 0x28 /* flt fault PSW, 16b */
#define ILOPSW 0x30 /* ill op PSW */
#define MCKPSW 0x38 /* mach chk PSW */
#define EXIPSW 0x40 /* ext intr PSW, 16b */
#define AFIPSW 0x48 /* arith flt PSW */
#define SQP 0x80 /* system queue ptr */
#define SQIPSW 0x82 /* sys q int PSW, 16b */
#define SQOP 0x8A /* sys q ovf ptr, 16b */
#define SQVPSW 0x8C /* sys q ovf PSW, 16b */
#define SQTPSW 0x88 /* sys q int PSW, 32b */
#define MPRPSW 0x90 /* mprot int PSW, 32b */
#define SVCAP 0x94 /* svc arg ptr, 16b */
#define SVOPS 0x96 /* svc old PS, 16b */
#define SVOPC 0x98 /* svc old PC, 16b */
#define SVNPS32 0x98 /* svc new PS, 32b */
#define SVNPS 0x9A /* svc new PS, 16b */
#define SVNPC 0x9C /* svc new PC */
#define INTSVT 0xD0 /* int service table */
#define AL_DEV 0x78 /* autoload: dev */
#define AL_IOC 0x79 /* command */
#define AL_DSKU 0x7A /* disk unit */
#define AL_DSKT 0x7B /* disk type */
#define AL_DSKC 0x7C /* disk ctrl */
#define AL_SCH 0x7D /* sel chan */
#define AL_EXT 0x7E /* OS extension */
#define AL_BUF 0x80 /* buffer start */
#define Q16_SLT 0 /* list: # slots */
#define Q16_USD 1 /* # in use */
#define Q16_TOP 2 /* current top */
#define Q16_BOT 3 /* next bottom */
#define Q16_BASE 4 /* base of q */
#define Q16_SLNT 2 /* slot length */
#define Q32_SLT 0 /* list: # slots */
#define Q32_USD 2 /* # in use */
#define Q32_TOP 4 /* current top */
#define Q32_BOT 6 /* next bottom */
#define Q32_BASE 8 /* base of q */
#define Q32_SLNT 4 /* slot length */
/* CPU event flags */
#define EV_MAC 0x01 /* MAC interrupt */
#define EV_BLK 0x02 /* block I/O in prog */
#define EV_INT 0x04 /* interrupt pending */
#define EV_WAIT 0x08 /* wait state pending */
/* Block I/O state */
struct BlockIO {
uint32 dfl; /* devno, flags */
t_addr cur; /* current addr */
t_addr end; /* end addr */
};
#define BL_RD 0x8000 /* block read */
#define BL_LZ 0x4000 /* skip 0's */
/* Instruction decode ROM, for all, 16b, 32b */
#define OP_UNDEF 0x0000 /* undefined */
#define OP_NO 0x0001 /* all: short or fp rr */
#define OP_RR 0x0002 /* all: reg-reg */
#define OP_RS 0x0003 /* 16b: reg-storage */
#define OP_RI1 0x0003 /* 32b: reg-imm 16b */
#define OP_RX 0x0004 /* all: reg-mem */
#define OP_RXH 0x0005 /* all: reg-mem, rd HW */
#define OP_RXF 0x0006 /* 32b: reg-mem, rd FW */
#define OP_RI2 0x0007 /* 32b: reg-imm 32b */
#define OP_MASK 0x000F
#define OP_ID4 0x0010 /* 16b: ID4 */
#define OP_716 0x0020 /* 16b: 7/16 */
#define OP_816 0x0040 /* 16b: 8/16 */
#define OP_816E 0x0080 /* 16b: 8/16E */
#define OP_DPF 0x4000 /* all: hwre FP */
#define OP_PRV 0x8000 /* all: privileged */
#define OP_TYPE(x) (decrom[(x)] & OP_MASK)
#define OP_DPFP(x) (decrom[(x)] & OP_DPF)
/* Device information block */
struct interdib {
uint32 dno; /* device number */
int32 sch; /* sch */
uint32 irq; /* interrupt */
uint8 *tplte; /* template */
uint32 (*iot)(uint32 d, uint32 o, uint32 dat);
void (*ini)(t_bool f); };
typedef struct interdib DIB;
#define TPL_END 0xFF /* template end */
/* Device select return codes */
#define BY 0 /* 8b only */
#define HW 1 /* 8b/16b */
/* I/O operations */
#define IO_ADR 0x0 /* address select */
#define IO_RD 0x1 /* read byte */
#define IO_RH 0x2 /* read halfword */
#define IO_WD 0x3 /* write byte */
#define IO_WH 0x4 /* write halfword */
#define IO_OC 0x5 /* output command */
#define IO_SS 0x6 /* sense status */
/* Device command byte */
#define CMD_V_INT 6 /* interrupt control */
#define CMD_M_INT 0x3
#define CMD_IENB 1 /* enable */
#define CMD_IDIS 2 /* disable */
#define CMD_IDSA 3 /* disarm */
#define CMD_GETINT(x) (((x) >> CMD_V_INT) & CMD_M_INT)
/* Device status byte */
#define STA_BSY 0x8 /* busy */
#define STA_EX 0x4 /* examine status */
#define STA_EOM 0x2 /* end of medium */
#define STA_DU 0x1 /* device unavailable */
/* Default device numbers */
#define DEV_LOW 0x01 /* lowest intr dev */
#define DEV_MAX 0xFF /* highest intr dev */
#define DEVNO (DEV_MAX + 1) /* number of devices */
#define d_DS 0x01 /* display, switches */
#define d_TT 0x02 /* teletype */
#define d_PT 0x03 /* reader */
#define d_CD 0x04 /* card reader */
#define d_TTP 0x10 /* PAS as console */
#define d_PAS 0x10 /* first PAS */
#define o_PASX 0x01 /* offset to xmt */
#define d_LPT 0x62 /* line printer */
#define d_PIC 0x6C /* interval timer */
#define d_LFC 0x6D /* line freq clk */
#define d_DPC 0xB6 /* disk controller */
#define o_DP0 0x10
#define o_DPF 0x01 /* offset to fixed */
#define d_FD 0xC1 /* floppy disk */
#define d_MT 0xC5 /* magtape */
#define o_MT0 0x10
#define d_SCH 0xF0 /* selector chan */
#define d_IDC 0xFB /* MSM disk ctrl */
#define o_ID0 0x01
/* Interrupts
To make interrupt flags independent of device numbers, each device is
assigned an interrupt flag in one of four interrupt words
word 0 DMA devices
word 1 programmed I/O devices
word 2-3 PAS devices
Devices are identified by a level and a bit within a level. Priorities
run low to high in the array, right to left within words
*/
#define INTSZ 4 /* interrupt words */
#define SCH_NUMCH 4 /* #channels */
#define ID_NUMDR 4 /* # MSM drives */
#define DP_NUMDR 4 /* # DPC drives */
#define MT_NUMDR 4 /* # MT drives */
/* Word 0, DMA devices */
#define i_SCH 0 /* highest priority */
#define i_IDC (i_SCH + SCH_NUMCH) /* MSM disk ctrl */
#define i_DPC (i_IDC + ID_NUMDR + 1) /* cartridge disk ctrl */
#define i_MT (i_DPC + DP_NUMDR + 1) /* magtape */
#define l_SCH 0
#define l_IDC 0
#define l_DPC 0
#define l_MT 0
#define v_SCH (l_SCH * 32) + i_SCH
#define v_IDC (l_IDC * 32) + i_IDC
#define v_DPC (l_DPC * 32) + i_DPC
#define v_MT (l_MT * 32) + i_MT
/* Word 1, programmed I/O devices */
#define i_PIC 0 /* precision clock */
#define i_LFC 1 /* line clock */
#define i_FD 2 /* floppy disk */
#define i_CD 3 /* card reader */
#define i_LPT 4 /* line printer */
#define i_PT 5 /* paper tape */
#define i_TT 6 /* teletype */
#define i_DS 7 /* display */
#define i_TTP 10 /* PAS console */
#define l_PIC 1
#define l_LFC 1
#define l_FD 1
#define l_CD 1
#define l_LPT 1
#define l_PT 1
#define l_TT 1
#define l_DS 1
#define l_TTP 1
#define v_PIC (l_PIC * 32) + i_PIC
#define v_LFC (l_LFC * 32) + i_LFC
#define v_FD (l_FD * 32) + i_FD
#define v_CD (l_CD * 32) + i_CD
#define v_LPT (l_LPT * 32) + i_LPT
#define v_PT (l_PT * 32) + i_PT
#define v_TT (l_TT * 32) + i_TT
#define v_DS (l_DS * 32) + i_DS
#define v_TTP (l_TTP * 32) + i_TTP
/* Word 2-3, PAS devices */
#define i_PAS 0
#define l_PAS 2
#define v_PAS (l_PAS * 32) + i_PAS
#define v_PASX (v_PAS + 1) /* offset to xmt */
/* I/O macros */
#define SET_INT(v) int_req[(v) >> 5] = int_req[(v) >> 5] | (1u << ((v) & 0x1F))
#define CLR_INT(v) int_req[(v) >> 5] = int_req[(v) >> 5] & ~(1u << ((v) & 0x1F))
#define SET_ENB(v) int_enb[(v) >> 5] = int_enb[(v) >> 5] | (1u << ((v) & 0x1F))
#define CLR_ENB(v) int_enb[(v) >> 5] = int_enb[(v) >> 5] & ~(1u << ((v) & 0x1F))
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* Device accessible macro */
#define DEV_ACC(d) (dev_tab[d] && !sch_blk (d))
/* Automatic I/O channel programs, 16b */
#define CCB16_CHN -4 /* chain */
#define CCB16_DEV -2 /* dev no */
#define CCB16_STS -1 /* status */
#define CCB16_CCW 0 /* cmd wd */
#define CCB16_STR 2 /* start */
#define CCB16_END 4 /* end */
#define CCB16_IOC 6 /* OC byte */
#define CCB16_TRM 7 /* term byte */
#define CCW16_INIT 0x8000 /* init */
#define CCW16_NOP 0x4000 /* nop */
#define CCW16_V_FNC 12 /* function */
#define CCW16_M_FNC 0x3
#define CCW16_FNC(x) (((x) >> CCW16_V_FNC) & CCW16_M_FNC)
#define CCW16_RD 0 /* read */
#define CCW16_WR 1 /* write */
#define CCW16_DMT 2 /* dec mem */
#define CCW16_NUL 3 /* null */
#define CCW16_TRM 0x0400 /* term char */
#define CCW16_Q 0x0200 /* queue */
#define CCW16_HI 0x0100 /* queue hi */
#define CCW16_OC 0x0080 /* OC */
#define CCW16_CHN 0x0020 /* chain */
#define CCW16_CON 0x0010 /* continue */
#define CCW16_V_BPI 0 /* bytes per int */
#define CCW16_M_BPI 0xF
#define CCW16_BPI(x) (((x) >> CCW16_V_BPI) & CCW16_M_BPI)
/* Automatic I/O channel programs, 32b */
#define CCB32_CCW 0 /* cmd wd */
#define CCB32_B0C 2 /* buf 0 cnt */
#define CCB32_B0E 4 /* buf 0 end */
#define CCB32_CHK 8 /* check word */
#define CCB32_B1C 10 /* buf 1 cnt */
#define CCB32_B1E 12 /* buf 1 end */
#define CCB32_TAB 16 /* trans table */
#define CCB32_SUB 20 /* subroutine */
#define CCW32_V_STA 8 /* status */
#define CCW32_M_STA 0xFF
#define CCW32_STA(x) (((x) >> CCW32_V_STA) & CCW32_M_STA)
#define CCW32_EXE 0x80 /* execute */
#define CCW32_CRC 0x10
#define CCW32_B1 0x08 /* buffer 1 */
#define CCW32_WR 0x04 /* write */
#define CCW32_TL 0x02 /* translate */
#define CCW32_FST 0x01 /* fast mode */
/* MAC, 32b */
#define P 0 /* physical */
#define VE 1 /* virtual inst */
#define VR 2 /* virtual read */
#define VW 3 /* virtual write */
#define MAC_BASE 0x300 /* MAC base */
#define MAC_STA 0x340 /* MAC status */
#define MAC_LNT 16
#define VA_V_OFF 0 /* offset */
#define VA_M_OFF 0xFFFF
#define VA_GETOFF(x) (((x) >> VA_V_OFF) & VA_M_OFF)
#define VA_V_SEG 16 /* segment */
#define VA_M_SEG 0xF
#define VA_GETSEG(x) (((x) >> VA_V_SEG) & VA_M_SEG)
#define SRF_MASK 0x000FFF00 /* base mask */
#define SRL_MASK 0x0FF00000 /* limit mask */
#define GET_SRL(x) ((((x) & SRL_MASK) >> 12) + 0x100)
#define SR_EXP 0x80 /* execute prot */
#define SR_WPI 0x40 /* wr prot int */
#define SR_WRP 0x20 /* wr prot */
#define SR_PRS 0x10 /* present */
#define SR_MASK (SRF_MASK|SRL_MASK|SR_EXP|SR_WPI|SR_WRP|SR_PRS)
#define MACS_L 0x10 /* limit viol */
#define MACS_NP 0x08 /* not present */
#define MACS_WP 0x04 /* write prot */
#define MACS_WI 0x02 /* write int */
#define MACS_EX 0x01 /* exec prot */
/* Miscellaneous */
#define TMR_LFC 0 /* LFC = timer 0 */
#define TMR_PIC 1 /* PIC = timer 1 */
#define TMR_PAS 2 /* PAS = timer 2 */
#define LPT_WIDTH 132
#define VFU_LNT 132
#define MIN(x,y) (((x) < (y))? (x): (y))
#define MAX(x,y) (((x) > (y))? (x): (y))
/* Logging */
#define LOG_CPU_I 0x0001 /* instructions */
#define LOG_CPU_C 0x0002 /* context change */
#define LOG_DP 0x0010
#define LOG_IDC 0x0020
#define LOG_MT 0x0040
#define LOG_FD 0x0080
#define DBG_LOG(x) (sim_log && (cpu_log & (x)))
/* Function prototypes */
int32 int_chg (uint32 irq, int32 dat, int32 arm);
int32 io_2b (int32 val, int32 pos, int32 old);
uint32 IOReadB (uint32 loc);
void IOWriteB (uint32 loc, uint32 val);
uint32 ReadF (uint32 loc, uint32 rel);
void WriteF (uint32 loc, uint32 val, uint32 rel);
uint32 IOReadBlk (uint32 loc, uint32 cnt, uint8 *buf);
uint32 IOWriteBlk (uint32 loc, uint32 cnt, uint8 *buf);
void sch_adr (uint32 ch, uint32 dev);
t_bool sch_actv (uint32 sch, uint32 devno);
void sch_stop (uint32 sch);
uint32 sch_wrmem (uint32 sch, uint8 *buf, uint32 cnt);
uint32 sch_rdmem (uint32 sch, uint8 *buf, uint32 cnt);
t_stat set_sch (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_sch (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc);

908
Interdata/id_diag.txt Normal file
View file

@ -0,0 +1,908 @@
Interdata Diagnostics
Summary
816E CPU diagnostic, part 1 passed 16b n/a
816E CPU diagnostic, part 2 partial 16b n/a
Series 16 CPU diagnostic, part 1 passed 16b n/a
16b memory diagnostic, part 1 passed 16b n/a
16b memory diagnostic, part 2 passed 16b n/a
816e extended memory diagnostic passed 16b n/a
Series 16 selector channel diagnostic passed 16b n/a
32b CPU diagnostic, part 1 n/a passed 32b
32b CPU diagnostic, part 2 n/a passed 32b
32b CPU diagnostic, part 3 n/a passed 32b
32b memory diagnostic, part 1 n/a passed 32b
32b memory diagnostic, part 2 n/a passed 32b
32b memory diagnostic, part 3 n/a passed 32b
32b memory diagnostic 6a, part 1 n/a passed 32b
32b memory diagnostic 6a, part 2 n/a passed 32b
32b MAC diagnostic, part 1 n/a passed 32b
32b MAC diagnostic, part 2 n/a passed 32b
Common line printer diagnostic passed 16b passed 32b
Common magtape diagnostic passed 16b passed 32b
Common 2.5/10MB disk diagnostic passed 16b passed 32b
32b MSM disk diagnostic passed 32b
Common floppy disk diagnostic passed 16b passed 32b
Common clock diagnostic passed 16b passed 32b
Not tested:
- 16b floating point
- 32b double precision floating point
- IDC
- PASLA
-------------------------------------------------------------------
Operating Instructions
816E CPU diagnostic, part 1
sim> set cpu 816e
sim> att -e pt0 diag.bin
sim> br c2
sim> boot pt0
Breakpoint: PC: 00C2 (EXBR R8,R6)
sim> run 100
MODEL 8/16E PROCESSOR TEST PART 1 06-211R00
CPU
* 8D
ENTER 0 OR 1
1
NO ERROR
CPU
*
---
816E CPU diagnostic, part 2
sim> set cpu 816e
sim> d tt ttime 1000 ; timing dependency
sim> att -e pt0 diag.bin
sim> br c2
sim> boot pt0
Breakpoint: PC: 00C2 (EXBR R8,R6)
sim> run 100
MODEL 8/16E PROCESSOR TEST PART 2 06-212R00
CPU
* 8D
SUBTEST
* (type subtest number)
Subtests 0, 1, 2, 5, 7, 8, 9 run correctly
Subtest 3, 4 cannot be run (initialization, power fail)
Subtest 6 cannot be run (hexadecimal display)
---
Series 16 CPU diagnostic, part 1
(Central error routine is at 21F4)
sim> set cpu 816e
sim> att -e pt0 diag.bin ; diagnostic
sim> br c0
sim> boot pt0
Breakpoint, PC: 00C0 (8800)
sim> d 234a 0202 ; patch to use
sim> d 234c a4a8 ; TTY as console
sim> d 17a b1e4
sim> run 100
SERIES SIXTEEN PROCESSOR TEST PART 1 06-242F01R00
CPU
* 2D
ENTER 0 OR 1
1
1234567890
NO ERROR
000A 0000
CPU
*
---
16b memory diagnostic, part 1
sim> att -e pt0 diag.bin ; diagnostic
sim> br c2
sim> boot pt0
Breakpoint, PC: 00C2 (EPSR R7,R6)
sim> run 100
02-340 PART 1 06-162F01R01
NO ERRORS
---
16b memory diagnostic, part 2
sim> att -e pt0 diag.bin ; diagnostic
sim> br c2
sim> boot pt0
Breakpoint, PC: 00C2 (EPSR R7,R6)
sim> run 1000
02-340 PART 2 06-162F02R01
NO ERRORS
---
816e extended memory diagnostic, parts 1 and 2
sim> set cpu 816e
sim> set cpu 256k
sim> att -e pt0 diag.bin ; diagnostic
sim> br b4
sim> boot pt0
Breakpoint, PC: 00B4 (LPSW R0,B8)
sim> run 1000
8/16 E EXTENDED MEMORY TEST PART 1 06-221R00
NO ERROR
* (CR to repeat part 1)
8/16 E EXTENDED MEMORY TEST PART 1 06-221R00
NO ERROR
* (LF to go on to part 2)
Breakpoint, PC: 00B4 (LPSW R0,B8)
sim> run 100
8/16 E EXTENDED MEMORY TEST PART 2 06-221R00
PROGRAM DETECTED MAXIMUM MEMORY 3FFFE
*TEST ; standard tests
*RUN
SUBTEST 0 NO ERROR
SUBTEST 1 NO ERROR
SUBTEST 2 NO ERROR
SUBTEST 3 NO ERROR
SUBTEST 4 NO ERROR
SUBTEST 6 NO ERROR
SUBTEST 7 NO ERROR
SUBTEST 8 NO ERROR
END OF TEST
*
---
Series 16 selector channel diagnostic
sim> set cpu 816e
sim> set cpu 256k
sim> att -e pt0 diag.bin ; diagnostic
sim> att mt0 foo.tap ; magtape to test
sim> br c0
sim> boot pt0
Breakpoint, PC: 00C0 (LPSW R0,C8)
sim> d 2e68 2 ; console is TTY
sim> run A00
S16 SELCH TEST 06-222 R01
TOP OF MEMORY 3 FFFF
* IODEV1 C5 ; magtape
* DEV1 2
* RUN ; bank 0 by default
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
TEST 04
NO ERROR
* MEMMOD 1 {2,3} ; repeat for banks 1,2,3
* RUN
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
TEST 04
NO ERROR
*
---
32b CPU diagnostic, part 1
sim> att -e mt0 mmd_r07.tap
sim> d -b 7f 7 ; file 8 on MMD R07 tape
sim> boot mt0
S32PT1 06-154 R03
CPU
*7X
NO ERROR
000A 0000
*
---
32b CPU diagnostic, part 2
sim> set tt 7b ; test is parity sensitive
sim> att -e mt0 mmd_r07.tap
sim> d -b 7f 8 ; file 9 on MMD R07 tape
sim> boot mt0
S32PT2R02
CPU
*
7X
SUBTEST
* (type subtest number)
Subtests 1, 3, 4, 5, 9 run correctly
Subtest 2 cannot be run (7/32 with halfword mode only)
Subtest 6 cannot be run (hexadecimal display)
Subtests 7,8 cannot be run (initialization, power fail)
---
32b CPU diagnostic, part 3
sim> att -e mt0 mmd_r07.tap
sim> d -b 7f 9 ; file 10 on MMD R07 tape
sim> boot mt0
S32PT3 R01
CPU
*
8X ; 7X denotes 7/32 with halfword mode
MAC RESPONSE AT 000300
SUBTEST
*
Subtests 1, 2, 3 run correctly
Subtest 4 cannot be run (parity option)
---
32b memory diagnostic, part 1
sim> att -e mt0 mmd_r07.tap
sim> d -b 7f 17 ; file 24 on MMD R07 tape
sim> br 2000
sim> boot mt0
Breakpoint, PC: 02000 (B 2060)
sim> d -w 2010 0202 ; console is TTY
sim> c
S32MT1 06-156F01R04
MAC PRESENT ? (Y OR N)
*
Y
01
02
03
04
05
06
NO ERROR
*
---
32b memory diagnostic, part 2
sim> att -e mt0 c:\temp\mmd_r07.tap
sim> d -b 7f 18 ; file 25 on MMD R07 tape
sim> br a00
sim> boot mt0
Breakpoint, PC: 00A00 (B A60)
sim> d -w a10 0202 ; console is TTY
sim> c
S32MT2 06-156F02R04
AVAILABLE MEMORY
000000 - 0FFFFF
SUBTEST *
0 ; all standard tests
01
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
02
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
03
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
04
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
05
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
06
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
07
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
SUBTEST *
---
32b memory diagnostic, part 3
sim> att -e mt0 c:\temp\mmd_r07.tap
sim> d -b 7f 19 ; file 26 on MMD R07 tape
sim> br a00
sim> boot mt0
Breakpoint, PC: 00A00 (B A60)
sim> d -w a10 0202 ; console is TTY
sim> c
S32MT3 06-156F03R04
AVAILABLE MEMORY
000000 - 0FFFFF
*
TEST STILL RUNNING ; repeated multiple times
:
NO ERROR
*
---
32b memory diagnostic, 6a, part 1
sim> att -e mt0 c:\temp\mmd_r07.tap
sim> d -b 7f 15 ; file 22 on MMD R07 tape
sim> boot mt0
32 BIT S6A MEMORY TEST 06-157F01R01
AVAILABLE MEMORY
0000-3FFF
MAC ADDRESS = 300
TYPE= 3 ; any value, 0-4
SUBTEST
* 0
01
NO ERROR
02
NO ERROR
03
NO ERROR
04
NO ERROR
05
NO ERROR
06
NO ERROR
07
NO ERROR
08
NO ERROR
SUBTEST
*
---
32b memory diagnostic, 6a, part 2
sim> att -e mt0 c:\temp\mmd_r07.tap
sim> d -b 7f 16 ; file 23 on MMD R07 tape
sim> boot mt0
32 BIT S6A MEMORY TEST 06-157F02R01
AVAILABLE MEMORY
0000f-FFFFF
TYPE= 2 ; any value, 0-4
SUBTEST
* 0
01
NO ERROR
02
NO ERROR
03
NO ERROR
04
NO ERROR
05
NO ERROR
06
NO ERROR
07
NO ERROR
08
NO ERROR
SUBTEST
*
---
32b MAC diagnostic, part 1
sim> att -e mt0 c:\temp\mmd_r07.tap
sim> d -b 7f 24 ; file 37 on MMD R07 tape
sim> boot mt0
MACT 06-160F01R03
AVAILABLE MEMORY
00000- FFFFF
* RUN
TEST 00 NO ERROR
TEST 01 NO ERROR
TEST 02 NO ERROR
TEST 03 NO ERROR
TEST 04 NO ERROR
TEST 05 NO ERROR
TEST 06 NO ERROR
TEST 07 NO ERROR
TEST 08 NO ERROR
TEST 09 NO ERROR
TEST 0B NO ERROR
*
---
sim> att -e mt0 c:\temp\mmd_r07.tap
sim> d -b 7f 25 ; file 38 on MMD R07 tape
sim> br ffd0 ; start != load point
sim> boot mt0
Breakpoint, PC: 0FFD0 (B 1093E)
sim> run 10010
MACT 06-160F02R03
* RUN
TEST 00 NO ERROR
TEST 01 NO ERROR
TEST 02 NO ERROR
TEST 03 NO ERROR
TEST 04 NO ERROR
TEST 05 NO ERROR
TEST 06 NO ERROR
TEST 07 NO ERROR
TEST 08 NO ERROR
*
---
Common line printer diagnostic
sim> att -e pt0 diag.bin
sim> br c2
sim> boot pt0
Breakpoint: PC: 00C2 (EXBR R8,R6)
sim> run a00 ; 32b
sim> run a04 ; 16b
COMMON LINE PRINTER TEST 06-170R02
*TEST 0,1,2,3
*RUN
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
END OF TEST
*INTRPT 1
*RUN
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
END OF TEST
*
---
Common magtape diagnostic
sim> set mt dev=85 ; 800 bpi default
sim> att -e pt0 diag.bin
sim> br c4
sim> boot pt0
Breakpoint, PC: 00C4 (EXBR R8,R6)
sim> run a00 ; 32b
sim> run a04 ; 16b
COMMON MAGNETIC TAPE TEST PROGRAM 06-172R02
*TEST 0,1,2,3,4,5
*MODE 0 ; prog i/o and selch
*RUN
*MODE 0
*RUN
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
TEST 04
NO ERROR
TEST 05
NO ERROR
END OF TEST
*
---
Common 2.5/10MB disk diagnostic
sim> att -e pt0 diag.bin
sim> br c2
sim> boot pt0
Breakpoint, PC: 00C2 (EXBR R8,R6)
sim> set dp0 5440
sim> set dp1 5440
sim> att dp0 test0.dsk
sim> att dp1 test1.dsk
sim> run a00 ; 32b
sim> run a04 ; 16b
COMMON DISC TEST 06-173R01F01
*FILE 2 ; FILE 1 to test fixed platter
*LOCYL 0
*HICYL 197
*TIMCON 1C0
*TEST 0,1,2,3,4,6,7,8,9,A,C ; test 5 requires format capability
; test B requires manual intervention
*RUN
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
TEST 04
NO ERROR
TEST 06
NO ERROR
TEST 07
NO ERROR
TEST 08
NO ERROR
TEST 09
NO ERROR
TEST 0A
NO ERROR
TEST 0C
NO ERROR
END OF TEST
*
---
32b MSM disk diagnostic
sim> att -e mt0 c:\temp\mmd_r07.tap
sim> d -b 7f 45 ; file 70 on MMD R07 tape
sim> br a00
sim> boot mt0
Breakpoint, PC: 00A00 (B A5E)
sim> d -w a10 0101 ; patch for TTY console
sim> att dm0 foo.dsk
sim> att dm1 foo1.dsk
sim> c
MSM DISC TEST 06-200F02R04 (32-BIT)
*LOCYL 0
*HICYL 336 ; tests 8,9,A will run a very long
; time, use 40 to shorten test
*DRIVE 0
*PACTYP 0
*TIMVAL 14D
*XFILE 1
*TEST 0,1,2,3,4,6,7,8,9,A,C ; test 5 requires format capability
; test B requires manual intervention
*RUN
TEST 00
TEST 01
TEST 02
TEST 03
TEST 04
TEST 06
TEST 07
TEST 08
TEST 09
TEST 0A
TEST 0C
---
Common floppy disk diagnostic
sim> att -e pt0 diag.bin
sim> att fd0 foo0.flp
sim> att fd1 foo1.flp
sim> br b8
sim> boot pt0
Breakpoint, PC: 000B8 (BS B2)
sim> d 2a72 bal r15,320a ; patch for multidrive test
sim> run a00 ; 32b
sim> run a04 ; 16b
COMMON FLOPPY DISC TEST 06-198R00
UNPROTECT DISKETTE
*DRIVE AB
*RUN
DRIVE A UNDER TEST
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
TEST 04
NO ERROR
TEST 05
NO ERROR
TEST 06
NO ERROR
TEST 07
NO ERROR
DRIVE B UNDER TEST
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
TEST 04
NO ERROR
TEST 05
NO ERROR
TEST 06
NO ERROR
TEST 07
NO ERROR
END OF TEST
*TEST 9 ; test 8 requires formatting
*RUN
TEST 09
NO ERROR
END OF TEST
*
---
Common clock diagnostic
sim> att -e pt0 diag.bin
sim> br c4
sim> boot pt0
Breakpoint, PC: 00C4 (EXBR R8,R6)
sim> d -w e28 4300 ; R09 patches
sim> d -w e2a 10f4
sim> id -w 10f4:110a
10f4: 4840
10f6: 188a
10f8: 4850
10fa: 188c
10fc: de40
10fe: 1eaf
1100: de50
1102: 1eaf
1104: 4810
1106: 0a24
1108: 4300
1110: 0e2c
sim> d 1b9c bs 1ba6
sim> d -w 1102 1eaf
sim> run a00 ; 32b
sim> run a04 ; 16b
COMMON UNIVERSAL CLOCK MODULE TEST 06-133R05
*TIMVAL 1A4 ; simulator is a fast CPU
*RUN
TEST 00
NO ERROR
TEST 01
NO ERROR
TEST 02
NO ERROR
TEST 03
NO ERROR
TEST 04
NO ERROR
TEST 05
NO ERROR
TEST 06
NO ERROR
TEST 07
NO ERROR
END OF TEST
*
-------------------------------------------------------------------
Bugs found
1. CPU16: instruction decoding interpreting CPU models incorrectly
2. CPU16: SINT should not be conditional on device existing
3. CPU16: immediate interrupts do not do a PSW swap, new PC is block+6
4. CPU16: SLA, SLHA setting C incorrectly
5. CPU16: diagnostic requires 816E extended memory to run
6. CPU16: CCW16_OC defined incorrectly
7. CPU16, CPU32: autoload not fetching or outputing OC
8. CPU16, CPU32: block I/O completion is off by 1
9. CPU16, CPU32: ESPR broken, EPSR rx,rx should copy PSW to rx
10. CPU16, CPU32: PCQ displays in octal instead of hexadecimal
11. CPU16, CPU32: SH and variations overflow calculation wrong
12. CPU16, CPU32: SCH overflow calculation wrong
13. CPU16, CPU32: CH and CLH overflow calculation wrong
14. CPU16, CPU32: CH or'ing into CC's instead of loading
15. CPU16, CPU32: RD, RH, SS, AI store some data on non-existent device
16. CPU16, CPU32: console interrupt not implemented
17. CPU16, CPU32: SRHL(s) setting C incorrectly
18. CPU16, CPU32: WDR, OCR not masking register data to 8b
19. CPU32: WH not masking data to 8b or 16b as required
20. CPU32: 32b register sets ordered incorrectly in memory
21. CPU32: wrong slot length in queue instructions
22. CPU32: display device missing its interrupt declaration
23. CPU32: LPSW(R) must load PC before changing PSW
24. CPU32: SLL setting C incorrectly
25. CPU32: bit instructions use halfword memory access and offsets
26. CPU32: CRC sign-extending rather than zero-extending operands
27. CPU32: SCP incrementing counts before, not after, transfer
28. CPU32: CHVR not implemented
29. CPU32: M(R) algorithm wrong
30. CPU32: M(R) using wrong register as first operand
31. CPU32: memory accesses were fullword rather than halfword aligned
32. CPU32: D(R) overflow calculation incorrect
33. CPU32: on 7/32, exceptions use register set 0, regardless of new PSW
34. CPU32: system queue PSW location misdefined
35. CPU32: autodriver channel not shifting bytes left before use as
translation table index
36. CPU32: MAC, LRA using wrong value for limit test
37. CPU32: LRA using wrong value for segment base
38. CPU32: MAC registers are accessible only if protection is off
39. CPU32: MAC status clears only on write, not read
40. CPU32: MAC write protect abort and interrupts implemented incorrectly
41. CPU32: ex/dep -v test used & instead of &&
42. CPU32: fetch tests for MAC abort at end of fetch, not per halfword
43. FP: unpack and pack detecting RR format incorrectly
44. FP: need separate microcode/hardware algorithms for add/sub denormalization
45. FP: multiply and divide have 'early out' detection of overflow/underflow
46. FP: compare less than not setting C
47. FP: fix overflow not setting V
48. FP: fix shift needed to be hex digits not binary digits
49. IO: interrupt evaluation routine never sets an interrupt
50. SELCH: transfer count calculation off by 1
51. SELCH: device data structure set up incorrectly (reset routine)
52. SELCH: stop clears pending interrupts
53. SELCH: register load algorithm incorrect for 6 byte loads
54. PT, LPT, FD: OR'ing status mask instead of AND'ing
55. PT, TT: SET_INT on status change not conditioned on interrupt armed
56. TT: input char converted to UC incorrectly
57. TT: need SET TT BREAK to run CPU test part 2
58. LPT: not clearing spacing done
59. MT: WREOF not setting EOF status
60. MT: CMD register pointer to wrong place
61. MT: write record byte count taken from wrong variable
62. MT: overrun processing incorrect for selector channel mode
63. PIC, LFC: write data and overflow detection incorrect
64. PIC, LFC: interpolation algorithm for cic read incorrect
65. PIC, LFC: ric reloaded from output buffer on count overflow
66. PIC, LFC: added diagnostic mode, revised use of count vs timer
67. DP: track increment algorithm incorrect
68. DP,IDC: incorrectly setting overrun for less than full sector reads
69. DP: should interrupt on detach (offline)
70. FD: high water mark not updated on write
71. FD: deleted data not implemented, required for diagnostic
72. FD: header CRC not implemented, required for diagnostic
73. FD: function code not stored for service routine
74. FD: LRN to track and sector conversions incorrect
75. FD: reset status incorrect (should be not busy, LRN = 1)
76. FD: extended status track 0 calculation wrong
77. FD: reset does not clear interrupts, requires delay
78. FD: read/write sequencing incorrect
79. FD: command without write data uses implicit LRN
80. FD: extended status is per drive not per controller
81. FD: command start clears only extended status bytes 0,1
82. FD: IDLE sets after BUSY drops and generates a separate interrupt
83. SYS16, SYS32: WH mistyped as WD in symbol table
84. SYS32: MHR, DHR misdefined
85. PAS: busy set instead of cleared initially
86. IDC: busy set instead of cleared initially
87. IDC, DP: busy not cleared at transfer command complete
88. IDC: busy is not cleared at drive command complete
89. IDC: for MSM compatibility, must absorb WH of head/cylinder
90. IDC: drive command 0x30 is an instant NOP
91. IDC: set cylinder with invalid cylinder sets SKI
92. IDC: read with invalid head sets ACF, not DTE

960
Interdata/id_doc.txt Normal file
View file

@ -0,0 +1,960 @@
To: Users
From: Bob Supnik
Subj: Interdata 16b/32b Simulator Usage
Date: 15-Jan-2003
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik
Copyright (c) 1993-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.
This memorandum documents the Interdata 16b and 32b simulators.
1. Simulator Files
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tmxr.h
scp.c
scp_tty.c
sim_sock.c
sim_tmxr.c
sim/interdata/ id_defs.h
id16_cpu.c [or id32_cpu.c]
id16_dboot.c [or id32_dboot.c]
id_dp.c
id_fd.c
id_fp.c
id_idc.c
id_io.c
id_lp.c
id_mt.c
id_pas.c
id_pt.c
id_tt.c
id_ttp.c
id_uvc.c
id16_sys.c [or id32_sys.c]
2. Interdata Features
The Interdata simulator includes simulators for a variety of 16b (I3, I4,
I5, 70, 80, 7/16, 8/16, 8/16E) and 32b (7/32, 8/32) models. This is by
no means a complete sampling of all the variations in the Interdata/Perkin-
Elmer family. The 32b family included options for special communications
instructions (7/32C, 8/32C), as well as a later extension for virtual
memory (3200 series).
The Interdata simulator is configured as follows:
device simulates
name(s)
CPU - 16b Interdata 3, 4, 5, 70, 80, 7/16, or 8/16 CPU with 64KB memory
Interdata 8/16E CPU with 256KB memory
CPU - 32b Interdata 7/32 or 8/32 CPU with 1MB memory
SELCH selector channel (1-4)
PT paper tape reader/punch
TT console terminal, Teletype interface
TTP console terminal, PASLA interface
LFC line frequency clock
PIC programmable interval clock
LPT line printer
FD floppy disk
DP 2.5MB/10MB cartridge disk
DM mass storage module (MSM)/intelligent (IDC) disk controller
MT magnetic tape
PAS programmable asynchronous line controller
PASL programmable asyhchronous lines, up to 32
The Interdata simulator implements two unique stop conditions:
- decode of an undefined instruction, and STOP_INST is set
- runaway carriage control tape in the line printer.
The LOAD command is used to load a carriage control tape for the line
printer. The DUMP command is used to dump a contiguous portion of
memory as a self-loading bootstrap paper tape. The syntax for the DUMP
command is:
DUMP <filename> lowaddr-highaddr
The low address must be greater than or equal to X'D0'.
Devices are assigned their default device numbers, as documented in the
Interdata literature. Device numbers can be changed by the command:
SET <device> DEVNO=num
Device number conflicts are not checked until simulation starts. If
there is a device number conflict, simulation stops immediately with
an error message.
Selector channel devices are assigned by default to selector channel 0.
Selector channel assignments can be changed by the command:
SET <dev> SELCH=num
Selector channel assignments cannot introduce conflicts.
Most devices can be disabled and enabled, with the commands:
SET <dev> DISABLED
SET <dev> ENABLED
All devices are enabled by default.
2.1 CPU (16b)
The CPU options include memory size and CPU type:
SET CPU I3 Interdata 3 (base instruction set)
SET CPU I4 Interdata 4 (base plus single precision
floating point)
SET CPU 716 Interdata 7/16 (extended instruction set)
(equivalent to Models 5, 70, and 80)
SET CPU 816 Interdata 8/16 (extended plus double
precision floating point)
SET CPU 816E Interdata 8/16E (extended plus double
precision plus expanded memory)
SET CPU 8K set memory size = 8KB
SET CPU 16K set memory size = 16KB
SET CPU 24K set memory size = 24KB
SET CPU 32K set memory size = 32KB
SET CPU 48K set memory size = 48KB
SET CPU 64K set memory size = 64KB
SET CPU 128K set memory size = 128KB (8/16E only)
SET CPU 256K set memory size = 256KB (8/16E only)
SET CPU CONSINT assert console interrupt (7/16, 8/16,
and 8/16E only)
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 64KB.
These switches are recognized when examining or depositing in CPU memory
(or any other byte oriented device):
-b examine/deposit bytes
-w examine/deposit halfwords (CPU default)
-f examine/deposit fullwords
-d data radix is decimal
-o data radix is octal
-h data radix is hexadecimal
-v interpret address as virtual
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
name size comments
PC 16 program counter
R0..R15 16 general registers
FR0..F14 32 single precision floating point registers
D0H..D14H 32 double precision floating point registers,
high order
D0L..D14L 32 double precision floating point registers,
low order
PSW 16 processor status word
CC 4 condition codes, PSW<12:15>
SR 16 switch register
DR 32 display register low 16 bits
DRX 8 display register extension (x/16 only)
DRMOD 1 display mode
DRPOS 2 display pointer position
SRPOS 1 switch pointer position
IRQ[0:3] 32 interrupt requests
IEN[0:3] 32 interrupt enables
STOP_INST 1 stop on undefined instruction
STOP_WAIT 1 stop if wait state and no I/O events pending
PCQ[0:63] 16 PC prior to last branch or interrupt;
most recent PC change first
WRU 8 interrupt character
2.2 CPU (32b)
The CPU options include memory size and CPU type:
SET CPU 732 Interdata 7/32, single precision floating point
SET CPU DPFP Interdata 7/32, double precision floating point
SET CPU 832 Interdata 8/32 (double precision floating point)
SET CPU 64K set memory size = 64KB
SET CPU 128K set memory size = 128KB
SET CPU 256K set memory size = 256KB
SET CPU 512K set memory size = 512KB
SET CPU 1M set memory size = 1024KB
SET CPU CONSINT assert console interrupt
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 1024KB.
These switches are recognized when examining or depositing in CPU memory
(or any other byte oriented device):
-b examine/deposit bytes
-w examine/deposit halfwords
-f examine/deposit fullwords (CPU default)
-d data radix is decimal
-o data radix is octal
-h data radix is hexadecimal
-v interpret address as virtual
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
name size comments
PC 20 program counter
R0..R15 32 active general register set
GREG[32] 32 general register sets, 16 x 2
FR0..FR14 32 single precision floating point registers
if double precision floating point; for
microcoded floating point, floating point
registers are kept in memory locations 00 - 1F
D0H..D14H 32 double precision floating point registers,
high order
D0L..D14L 32 double precision floating point registers,
low order
PSW 16 processor status word
CC 4 condition codes, PSW<12:15>
SR 16 switch register
DR 32 display register low 16 bits
DRX 8 display register extension (x/16 only)
DRMOD 1 display mode
DRPOS 2 display pointer position
SRPOS 1 switch pointer position
MACREG[0:15] 32 memory access controller segment registers
MACSTA 5 memory access controller interrupt status
IRQ[0:3] 32 interrupt requests
IEN[0:3] 32 interrupt enables
STOP_INST 1 stop on undefined instruction
STOP_WAIT 1 stop if wait state and no I/O events pending
PCQ[0:63] 20 PC prior to last branch or interrupt;
most recent PC change first
WRU 8 interrupt character
2.3 Selector Channel (SELCH)
An Interdata system can have 1 to 4 selector channels (SELCH0, SELCH1,
SELCH2, SELCH3). The default number of channels is 2. The number of
channels can be changed with the command:
SET SELCH CHANNELS=num
The selector channels implement these registers:
name size comments
SA[0:3] 20 start address, channels 0 to 3
EA[0:3] 20 end address, channels 0 to 3
CMD[0:3] 8 command, channels 0 to 3
DEV[0:3] 8 active device, channels 0 to 3
RDP[0:3] 2 read byte pointer, channels 0 to 3
WDC[0:3] 3 write data counter, channels 0 to 3
IREQ 4 interrupt requests; right to left,
channels 0 to 3
IENB 4 interrupt enables
2.4 Programmed I/O Devices
2.4.1 Paper Tape Reader/Punch (PT)
The paper tape reader and punch (PT units 0 and 1) read data from or
write data to disk files. The RPOS and PPOS registers specify the
number of the next data item to be read and written, respectively.
Thus, by changing RPOS or PPOS, the user can backspace or advance
these devices.
The paper tape reader supports the BOOT command. BOOT PTR copies the
so-called '50 loader' into memory and starts it running.
The paper tape controller implements these registers:
name size comments
RBUF 8 reader buffer
RPOS 32 reader position in the input file
RTIME 24 time from reader start to interrupt
RSTOP_IOE 1 reader stop on I/O error
PBUF 8 punch buffer
PPOS 32 punch position in the output file
PTIME 24 time from punch start to interrupt
PSTOP_IOE 1 punch stop on I/O error
IREQ 1 paper tape interrupt request
IENB 1 paper tape interrupt enable
IARM 1 paper tape interrupt armed
RD 1 paper tape read/write mode
RUN 1 paper tape running
SLEW 1 paper tape reader slew mode
EOF 1 paper tape reader end of file
Error handling is as follows:
type error STOP_IOE processed as
in,out not attached 1 report error and stop
0 out of tape
in end of file 1 report error and stop
0 out of tape
in,out OS I/O error x report error and stop
2.4.2 Console, Teletype Interface (TT)
The Teletype keyboard (TT0) reads from the console keyboard; the
Teletype printer (TT1) writes to the simulator console window.
The Teletype units (TT0, TT1) can be set to one of three modes:
KSR, 7B, or 8B. In KSR mode, lower case input and output characters
are automatically converted to upper case, and the high order bit is
forced to one on input. In 7B mode, input and output characters are
masked to 7 bits. In 8B mode, characters are not modified. Changing
the mode of either unit changes both. The default mode is KSR.
The Teletype has a BREAK key, which is not present on today's
keyboards. To simulate pressing the break key, stop the simulator
and use the command:
SET TT BREAK
Break status will be asserted, and will remain asserted for the
interval specified by KTIME.
The Teletype interface implements these registers:
name size comments
KBUF 8 input buffer
KPOS 32 number of characters input
KTIME 24 input polling interval
TBUF 8 output buffer
TPOS 32 number of characters output
TTIME 24 time from output start to interrupt
IREQ 1 interrupt request
IENB 1 interrupt enable
IARM 1 interrupt armed
RD 1 read/write mode
FDPX 1 half-duplex
CHP 1 input character pending
2.4.3 Console, PASLA Interface (TTP)
Later Interdata system connect the system console via the first
PASLA interface rather than the Teletype interface. The PASLA
console can be simulated with a Telnet session on the first PAS line.
Alternately, the PASLA console can be attached to the simulator
console window, using the TTP device in place of TT.
To switch the simulator console window to TTP, use the command:
SET TTP ENABLED or
SET TT DISABLED
Device TT is automatically disabled and device TTP is enabled.
To switch the simulator console window back to TT, use the command:
SET TT ENABLED or
SET TTP DISABLED
Device TTP is automatically disabled and device TT is enabled.
If TTP is enabled at its default device settings, the base address
for the PAS multiplexor must be changed:
SET PAS DEVNO=12
Otherwise, a device number conflict occurs.
The PASLA keyboard (TTP0) reads from the console keyboard; the
PALSA printer (TTP1) writes to the simulator console window.
The PASLA units (TTP0, TTP1) can be set to one of three modes:
UC, 7B, or 8B. In UC mode, lower case input and output characters
are automatically converted to upper case. In 7B mode, input and
output characters are masked to 7 bits. In 8B mode, characters
are not modified. Changing the mode of either unit changes both.
The default mode is UC.
To simulate pressing the break key, stop the simulator and use
the command:
SET TTP BREAK
Break status will be asserted, and will remain asserted for the
interval specified by KTIME.
The PASLA console interface implements these registers:
name size comments
KBUF 8 input buffer
KPOS 32 number of characters input
KTIME 24 input polling interval
KIREQ 1 input interrupt request
KIENB 1 input interrupt enabled
KARM 1 input interrupt armed
CHP 1 input character pending
TBUF 8 output buffer
TPOS 32 number of characters output
TTIME 24 time from output start to interrupt
TIREQ 1 output interrupt request
TIENB 1 output interrupt enable
TIARM 1 output interrupt armed
2.4.4 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
In addition, the line printer can be programmed with a carriage control
tape. The LOAD command loads a new carriage control tape:
LOAD <file> load carriage control tape file
The format of a carriage control tape consists of multiple lines. Each
line contains an optional repeat count, enclosed in parentheses, optionally
followed by a series of column numbers separated by commas. Column numbers
must be between 0 and 7; column seven is by convention top of form. The
following are all legal carriage control specifications:
<blank line> no punch
(5) 5 lines with no punches
1,5,7 columns 1, 5, 7 punched
(10)2 10 lines with column 2 punched
0 column 0 punched
The default form is 1 line long, with all columns punched.
The line printer implements these registers:
name size comments
BUF 7 last data item processed
BPTR 8 line buffer pointer
LBUF[0:131] 7 line buffer
VFUP 8 vertical forms unit pointer
VFUL 8 vertical forms unit length
VFUT[0:131] 8 vertical forms unit table
IREQ 1 line printer interrupt request
IENB 1 line printer interrupt enable
IARM 1 line printer interrupt armed
POS 32 position in the output file
CTIME 24 character processing time
STIME 24 spacing operation time
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of paper
OS I/O error x report error and stop
2.4.5 Line Frequency Clock (LFC)
The line frequency clock (LFC) implements these registers:
name size comments
IREQ 1 clock interrupt request
IENB 1 clock interrupt enable
IARM 1 clock interrupt armed
TIME 24 clock frequency
TPS 8 ticks per second (120 or 100)
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.4.6 Programmable Interval Clock (PIC)
The programmable interval clock (PIC) implements these registers:
name size comments
BUF 16 output buffer
RIC 16 reset interval and rate
CIC 12 current interval
DECR 10 current decrement value
RDP 1 read byte select
OVF 1 interval overflow flag
IREQ 1 clock interrupt request
IENB 1 clock interrupt enable
IARM 1 clock interrupt armed
If the interval requested is longer than 1 msec, the programmable clock
auto-calibrates; if not, it simply counts instructions.
2.4.7 Floppy Disk Controller (FD)
Floppy disk options include the ability to make units write enabled or
write locked.
SET FDn LOCKED set unit n write locked
SET FDn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE.
The floppy disk supports the BOOT command. BOOT FDn copies an autoload
sequence into memory and starts it running.
The floppy disk controller implements these registers:
name size comments
CMD 8 command
STA 8 status
BUF 8 buffer
LRN 16 logical record number
ESTA[0:5] 8 extended status bytes
DBUF[0:127] 8 transfer buffer
DBPTR 8 transfer buffer pointer
IREQ 1 interrupt request
IENB 1 interrupt enabled
IARM 1 interrupt armed
CTIME 24 command response time
STIME 24 seek time, per cylinder
XTIME 24 transfer time, per byte
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
Floppy disk data is buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.4.8 Programmable Asynchronous Line Adapters (PAS, PASL)
The Programmable Asynchronous Line Adapters (PAS and PASL) represent,
indistinguishably, individual PASLA interfaces, two lines asynchronous
multiplexors, and 8 line asynchronous multiplexors, with a maximum
of 32 lines. All the lines are modelled as a terminal multiplexor, with
PAS as the multiplexor controller, and PASL as the indivdual lines. The
PASLAs perform input and output through Telnet sessions connected to a
user-specified port. The ATTACH command specifies the port to be used:
ATTACH PAS <port> set up listening port
where port is a decimal number between 1 and 65535 that is not being used
for other TCP/IP activities.
Each line (each unit of PASL) can be set to one of three modes: UC, 7B,
or 8B. In UC mode, lower case input and output characters are converted
automatically to upper case. In 7B mode, input and output characters are
masked to 7 bits. In 8B mode, characters are not modified. The default
mode is UC. Each line (each unit of PASL) can also be set for modem
control with the command SET PASLn DATASET. The defaults are UC mode
and DATASET disabled.
Once PAS is attached and the simulator is running, the terminals listen
for connections on the specified port. They assume that the incoming
connections are Telnet connections. The connections remain open until
disconnected either by the Telnet client, a SET PAS DISCONNECT command,
or a DETACH PAS command.
The SHOW PAS CONNECTIONS command displays the current connections to the
extra terminals. The SHOW PAS STATISTICS command displays statistics for
active connections. The SET PAS DISCONNECT=linenumber disconnects the
specified line.
The controller (PAS) implements these registers:
name size comments
STA[0:31] 8 status, lines 0 to 31
CMD[0:31] 16 command, lines 0 to 31
RBUF[0:31] 8 receive buffer, lines 0 to 31
XBUF[0:31] 8 transmit buffer, lines 0 to 31
RIREQ 32 receive interrupt requests;
right to left, lines 0 to 31
RIENB 32 receive interrupt enables
RARM[0:31] 1 receive interrupt armed
XIREQ 32 transmit interrupt requests;
right to left, lines 0 to 31
XIENB 32 transmit interrupt enables
XARM[0:31] 1 transmit interrupt armed
RCHP[0:31] 1 receiver character present, lines 0 to 31
The lines (PASL) implements these registers:
name size comments
TIME[0:31] 24 transmit time, lines 0 to 31
The additional terminals do not support save and restore. All open
connections are lost when the simulator shuts down or PAS is detached.
2.5 Cartridge Disk Controller (DP)
Cartridge disk options include the ability to make units write enabled or
write locked, and to select the type of drive:
SET DPn LOCKED set unit n write locked
SET DPn WRITEENABLED set unit n write enabled
SET DPn 2315 set unit n to 2315 (2.5MB)
SET DPn 5440 set unit n to 5440 (10MB)
Units can also be set ONLINE or OFFLINE.
The cartridge disk supports the BOOT command. To boot OS16/32, the hex
form of the operating system file's extension must be placed in locations
7E:7F. The disk bootstrap looks for a valid OS16/32 volume descriptor in
block 0, and uses that to locate the volume directory. It then searches
the directory for a filename of the form OS16xxxx.hhh or OS32xxxx.hhh,
where the xxxx is ignored and hhh is the ASCII form of the extension from
locations 7E:7F. The 32b bootstrap can also boot Wollongong UNIX; locations
7E:7F must be 0.
All drives have 256 8b bytes per sector. The other disk parameters are:
drive cylinders surfaces sectors
2315 203 2 24
5440 408 4 12
The cartridge disk controller implements these registers:
name size comments
CMD 3 current command
STA 8 controller status
BUF 8 controller buffer
HDSC 8 current head/sector select
CYL 8 current cylinder select
DBUF[0:255] 8 transfer buffer
DBPTR 16 transfer buffer point
DBLNT 16 transfer buffer length
FIRST 1 first DMA service flag
IREQ 5 interrupt requests; right-to-left,
controller, drives 0 to 3
IENB 5 interrupt enables
IARM[0:3] 1 interrupts armed, drives 0 to 3
STIME 24 seek latency, per cylinder
RTIME 24 rotational latency, per sector
WTIME 24 inter-word latency
Error handling is as follows:
error processed as
not attached disk not ready
end of file assume rest of disk is zero
OS I/O error report error and stop
2.6 Mass Storage Module/Intelligent Disk Controller (DM)
MSM/IDC disk controller options include the ability to make units
write enabled or write locked, and to select the type of drive:
SET DMn LOCKED set unit n write locked
SET DMn WRITEENABLED set unit n write enabled
SET DMn MSM80 set unit n to storage module, 80MB
(67MB formatted)
SET DMn MSM300 set unit n to storage module, 300MB
(262MB formatted)
SET DMn MCCD16 set unit n to medium capacity, 16MB
(13.5MB formatted)
SET DMn MCCD48 set unit n to medium capacity, 48MB
(40.5MB formatted)
SET DMn MCCD80 set unit n to medium capacity, 80MB
(67MB formatted)
SET DMn MSM330F set unit n to storage module, 330MB
(300MB formatted)
Note that the disk bootstraps can ONLY boot the MSM80 and MSM300.
Units can be set ONLINE or OFFLINE.
The MSM/IDC controller supports the BOOT command. To boot OS16/32, the hex
form of the operating system file's extension must be placed in locations
7E:7F. The disk bootstrap looks for a valid OS16/32 volume descriptor in
block 0, and uses that to locate the volume directory. It then searches
the directory for a filename of the form OS16xxxx.hhh or OS32xxxx.hhh,
where the xxxx is ignored and hhh is the ASCII form of the extension from
locations 7E:7F. The 32b bootstrap can also boot Wollongong UNIX; locations
7E:7F must be 0. Note that only the MSM80 and MSM300 drives can be boot-
strapped; the boot code does not recognize the other drives.
All drives have 256 8b bytes per sector. The other disk parameters are:
drive cylinders surfaces sectors
MSM80 823 5 64
MSM300 823 19 64
MCCD16 823 1 64
MCCD48 823 3 64
MCCD80 823 5 64
MSM300F 1024 16 64
The MSM/IDC disk controller implements these registers:
name size comments
STA 8 controller status
BUF 8 controller buffer
SEC 8 current sector select
DBUF[0:767] 8 transfer buffer
DBPTR 16 transfer buffer point
DBLNT 16 transfer buffer length
FIRST 1 first DMA service flag
IREQ 5 interrupt requests; right-to-left,
controller, drives 0 to 3
IENB 5 interrupt enables
SIREQ 5 saved interrupt requests
ICARM 1 controller interrupt armed
IDARM[0:3] 1 drive interrupts armed, drives 0 to 3
STIME 24 seek latency, per cylinder
RTIME 24 rotational latency, per sector
WTIME 24 inter-word latency
Error handling is as follows:
error processed as
not attached disk not ready
end of file assume rest of disk is zero
OS I/O error report error and stop
2.7 Magnetic Tape Controller (MT)
Magnetic tape options include the ability to make units write enabled or
or write locked.
SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE.
The magnetic tape supports the BOOT command. BOOT MTn copies an autoload
sequence into memory and starts it running.
The magnetic tape controller implements these registers:
name size comments
CMD 8 command
STA 8 status
BUF 8 buffer
DBUF[0:65535] 8 transfer buffer
DBPTR 16 transfer buffer pointer
DBLNT 16 transfer buffer length
XFR 1 transfer in progress flag
FIRST 1 first DMA service flag
IREQ 4 interrupt requests; right to left,
drives 0 to 3
IENB 4 interrupt enables
IARM[0:3] 1 interrupts armed, drives 0 to 3
STOP_IOE 1 stop on I/O error
WTIME 1 word transfer time
RTIME 1 interrecord latency
UST[0:3] 8 unit status, drives 0 to 3
POS[0:3] 32 tape position, drives 0 to 3
Error handling is as follows:
error processed as
not attached tape not ready; if STOP_IOE, stop
end of file set error flag
OS I/O error set error flag; if STOP_IOE, stop
2.8 Symbolic Display and Input
The Interdata simulator implements symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as two character string
-m display instruction mnemonics
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c two character sixbit string
alphabetic instruction mnemonic
numeric octal number
2.7.1 16b Instruction Input
Instruction input uses standard Interdata assembler syntax. There are
seven instruction classes: short branch, extended short branch, short
immediate, register, register-register, memory, and register-memory.
Short branch instructions have the format
sbop mask,address
where the mask is a hex (decimal) number between 0 and F (15), and
the address is within +32 (forward branch) or -32 (backward branch)
of the current location.
Extended short branch instructions have the format
sbxop address
where the address is within +32 or -32 of the current location. For
extended short branches, the simulator chooses the forward or backward
direction automatically.
Short immediate instructions have the format
siop regnum,immed
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15), and the immediate is a hex digit
between 0 and F.
Register instructions have the format
rop regnum
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15).
Register-register instructions have the format
rrop regnum,regnum
where the register numbers are hex (decimal) numbers, optionally
preceded by R, between 0 and F (15).
Memory instructions have the format
mop address{(index)}
where address is a hex number between 0 and 0xFFFF, and the index
register is a hex (decimal) number, optionally preceded by R,
between 1 and F (15).
Register-memory instructions have the format
rmop regnum,address{(index)}
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15), the address is a hex number
between 0 and 0xFFFF, and the index register is a hex (decimal)
number, optionally preceded by R, between 1 and F (15).
2.7.2 32b Instruction Input
Instruction input uses standard Interdata assembler syntax. There are
nine instruction classes: short branch, extended short branch, short
immediate, 16b immediate, 32b immediate, register, register-register,
memory, and register-memory.
Short branch instructions have the format
sbop mask,address
where the mask is a hex (decimal) number between 0 and F (15), and
the address is within +32 (forward branch) or -32 (backward branch)
of the current location.
Extended short branch instructions have the format
sbxop address
where the address is within +32 or -32 of the current location. For
extended short branches, the simulator chooses the forward or backward
direction automatically.
Short immediate instructions have the format
siop regnum,immed
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15), and the immediate is a hex digit
between 0 and F.
16b immediate instructins have the format
i16op regnum,immed16{(index)}
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15), the immediate is a hex number
between 0 and 0xFFFF, and the index register is a hex (decimal)
number, optionally preceded by R, between 1 and F (15).
32b immediate instructions have the format
i32op regnum,immed32{(index)}
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15), the immediate is a hex number
between 0 and 0xFFFFFFFF, and the index register is a hex (decimal)
number, optionally preceded by R, between 1 and F (15).
Register instructions have the format
rop regnum
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15).
Register-register instructions have the format
rrop regnum,regnum
where the register numbers are hex (decimal) numbers, optionally
preceded by R, between 0 and F (15).
Memory instructions have the format
mop address{(index)} or
mop address{(index1,index2)}
where address is a hex number between 0 and 0xFFFF, and the index
registers are hex (decimal) numbers, optionally preceded by R,
between 1 and F (15).
Register-memory instructions have the format
rmop regnum,address{(index)} or
rmop regnum,address{(index1,index2)}
where the register number is a hex (decimal) number, optionally
preceded by R, between 0 and F (15), the address is a hex number
between 0 and 0xFFFF, and the index registers are hex (decimal)
numbers, optionally preceded by R, between 1 and F (15).
For memory operands, the simulator automatically chooses the format
(RX1, RX2, RX3) that consumes the fewest bytes. If both RX1 and RX2
are feasible, the simulator chooses RX1.

547
Interdata/id_dp.c Normal file
View file

@ -0,0 +1,547 @@
/* id_dp.c: Interdata 2.5MB/10MB cartridge disk simulator
Copyright (c) 2001-2002, 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.
dp M46-421 2.5MB/10MB cartridge disk
*/
#include "id_defs.h"
#include <math.h>
#define DP_NUMBY 256 /* bytes/sector */
#define DP_NUMSC 24 /* sectors/track */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
#define UNIT_M_DTYPE 0x1
#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
#define CYL u3 /* current cylinder */
#define STD u4 /* drive status */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Controller status */
#define STC_OVR 0x80 /* overrun */
#define STC_ACF 0x40 /* addr cmp fail */
#define STC_DEF 0x20 /* def track NI */
#define STC_CYO 0x10 /* cylinder ovflo */
#define STC_IDL 0x02 /* ctrl idle */
#define STC_DTE 0x01 /* xfer error */
#define SETC_EX (STC_OVR|STC_ACF|STC_DEF|STC_CYO)
#define STC_MASK (STC_OVR|STC_ACF|STC_DEF|STC_CYO|STA_BSY|STC_IDL|STC_DTE)
/* Controller command */
#define CMC_MASK 0xF
#define CMC_CLR 0x8 /* reset */
#define CMC_RD 0x1 /* read */
#define CMC_WR 0x2 /* write */
#define CMC_RCHK 0x3 /* read check */
#define CMC_RFMT 0x5 /* read fmt NI */
#define CMC_WFMT 0x6 /* write fmt NI */
/* Drive status, ^ = dynamic, * = in unit status */
#define STD_WRP 0x80 /* ^write prot */
#define STD_WCK 0x40 /* write check NI */
#define STD_ILA 0x20 /* *illegal addr */
#define STD_ILK 0x10 /* ^addr interlock */
#define STD_MOV 0x08 /* *heads in motion */
#define STD_INC 0x02 /* seek incomplete NI */
#define STD_NRDY 0x01 /* ^not ready */
#define STD_UST (STD_ILA | STD_MOV) /* set from unit */
#define SETD_EX (STD_WCK | STD_ILA | STD_ILK) /* set examine */
/* Drive command */
#define CMD_SK 0x02 /* seek */
#define CMD_RST 0x01 /* restore */
/* Head/sector register */
#define HS_SMASK 0x1F /* sector mask */
#define HS_V_SRF 5 /* surface */
#define HS_HMASK 0x20 /* head mask */
#define HS_MASK (HS_HMASK | HS_SMASK)
#define GET_SEC(x) ((x) & HS_SMASK)
#define GET_SRF(x) (((x) & HS_HMASK) >> HS_V_SRF)
#define GET_SA(p,cy,sf,sc,t) (((((((p)*drv_tab[t].cyl)+(cy))*drv_tab[t].surf)+(sf))* \
DP_NUMSC)+(sc))
#define GET_ROTATE(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DP_NUMSC)))
/* This controller supports two different disk drive types:
type #sectors/ #surfaces/ #cylinders/
surface cylinder drive
2315 24 2 203
5440 24 4 408
In theory, each drive can be a different type. The size field in
each unit selects the drive capacity for each drive and thus the
drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE AND MUST HAVE
THE SAME SECTORS/TRACK.
*/
#define TYPE_2315 0
#define CYL_2315 203
#define SURF_2315 2
#define SIZE_2315 (DP_NUMSC * SURF_2315 * CYL_2315 * DP_NUMBY)
#define TYPE_5440 1
#define CYL_5440 408
#define SURF_5440 2
#define SIZE_5440 (2 * DP_NUMSC * SURF_5440 * CYL_5440 * DP_NUMBY)
struct drvtyp {
int32 cyl; /* cylinders */
uint32 surf; /* surfaces */
uint32 size; /* #blocks */
};
static struct drvtyp drv_tab[] = {
{ CYL_2315, SURF_2315, SIZE_2315 },
{ CYL_5440, SURF_5440, SIZE_5440 },
{ 0 } };
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint8 dpxb[DP_NUMBY]; /* xfer buffer */
uint32 dp_bptr = 0; /* buffer ptr */
uint32 dp_db = 0; /* ctrl buffer */
uint32 dp_cyl = 0; /* drive buffer */
uint32 dp_sta = 0; /* ctrl status */
uint32 dp_cmd = 0; /* ctrl command */
uint32 dp_plat = 0; /* platter */
uint32 dp_hdsc = 0; /* head/sector */
uint32 dp_svun = 0; /* most recent unit */
uint32 dp_1st = 0; /* first byte */
uint32 dpd_arm[DP_NUMDR] = { 0 }; /* drives armed */
int32 dp_stime = 100; /* seek latency */
int32 dp_rtime = 100; /* rotate latency */
int32 dp_wtime = 1; /* word time */
uint8 dp_tplte[(2 * DP_NUMDR) + 2]; /* fix/rmv + ctrl + end */
DEVICE dp_dev;
uint32 dp (uint32 dev, uint32 op, uint32 dat);
void dp_ini (t_bool dtpl);
t_stat dp_svc (UNIT *uptr);
t_stat dp_reset (DEVICE *dptr);
t_stat dp_attach (UNIT *uptr, char *cptr);
t_stat dp_detach (UNIT *uptr);
t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dp_rds (UNIT *uptr);
t_stat dp_wds (UNIT *uptr);
t_bool dp_dter (UNIT *uptr, uint32 first);
void dp_done (uint32 flg);
extern t_stat id_dboot (int32 u, DEVICE *dptr);
/* DP data structures
dp_dev DP device descriptor
dp_unit DP unit list
dp_reg DP register list
dp_mod DP modifier list
*/
DIB dp_dib = { d_DPC, 0, v_DPC, dp_tplte, &dp, &dp_ini };
UNIT dp_unit[] = {
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) } };
REG dp_reg[] = {
{ HRDATA (CMD, dp_cmd, 3) },
{ HRDATA (STA, dp_sta, 8) },
{ HRDATA (BUF, dp_db, 8) },
{ HRDATA (PLAT, dp_plat, 1) },
{ HRDATA (HDSC, dp_hdsc, 6) },
{ HRDATA (CYL, dp_cyl, 9) },
{ HRDATA (SVUN, dp_svun, 8), REG_HIDDEN },
{ BRDATA (DBUF, dpxb, 16, 8, DP_NUMBY) },
{ HRDATA (DBPTR, dp_bptr, 9), REG_RO },
{ FLDATA (FIRST, dp_1st, 0) },
{ GRDATA (IREQ, int_req[l_DPC], 16, DP_NUMDR + 1, i_DPC) },
{ GRDATA (IENB, int_enb[l_DPC], 16, DP_NUMDR + 1, i_DPC) },
{ BRDATA (IARM, dpd_arm, 16, 1, DP_NUMDR) },
{ DRDATA (RTIME, dp_rtime, 0), PV_LEFT | REG_NZ },
{ DRDATA (STIME, dp_stime, 0), PV_LEFT | REG_NZ },
{ DRDATA (WTIME, dp_wtime, 0), PV_LEFT | REG_NZ },
{ URDATA (UCYL, dp_unit[0].CYL, 16, 9, 0,
DP_NUMDR, REG_RO) },
{ URDATA (UST, dp_unit[0].STD, 16, 8, 0,
DP_NUMDR, REG_RO) },
{ URDATA (CAPAC, dp_unit[0].capac, 10, 31, 0,
DP_NUMDR, PV_LEFT | REG_HRO) },
{ HRDATA (DEVNO, dp_dib.dno, 8), REG_HRO },
{ HRDATA (SELCH, dp_dib.sch, 2), REG_HRO },
{ NULL } };
MTAB dp_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_2315 << UNIT_V_DTYPE) + UNIT_ATT,
"2315", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_5440 << UNIT_V_DTYPE) + UNIT_ATT,
"5440", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_2315 << UNIT_V_DTYPE),
"2315", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_5440 << UNIT_V_DTYPE),
"5440", NULL, NULL },
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_2315 << UNIT_V_DTYPE),
NULL, "2315", &dp_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_5440 << UNIT_V_DTYPE),
NULL, "5440", &dp_set_size },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH",
&set_sch, &show_sch, NULL },
{ 0 } };
DEVICE dp_dev = {
"DP", dp_unit, dp_reg, dp_mod,
DP_NUMDR, 16, 24, 1, 16, 8,
NULL, NULL, &dp_reset,
&id_dboot, &dp_attach, &dp_detach,
&dp_dib, DEV_DISABLE };
/* Controller: IO routine */
uint32 dpc (uint32 dev, uint32 op, uint32 dat)
{
uint32 f, t, u;
UNIT *uptr;
static uint8 good_cmd[8] = { 0, 1, 1, 1, 0, 0, 0, 0 };
switch (op) { /* case IO op */
case IO_ADR: /* select */
sch_adr (dp_dib.sch, dev); /* inform sel ch */
return BY; /* byte only */
case IO_RD: /* read data */
if (dp_sta & STC_IDL) /* if idle */
return GET_ROTATE (dp_rtime); /* return sector */
else dp_sta = dp_sta | STA_BSY; /* xfr? set busy */
return dp_db; /* return data */
case IO_WD: /* write data */
if (dp_sta & STC_IDL) dp_hdsc = dat & HS_MASK; /* idle? hdsc */
else { /* data xfer */
dp_sta = dp_sta | STA_BSY; /* set busy */
dp_db = dat & 0xFF; } /* store data */
break;
case IO_SS: /* status */
t = dp_sta & STC_MASK; /* get status */
if (t & SETC_EX) t = t | STA_EX; /* test for EX */
return t;
case IO_OC: /* command */
f = dat & CMC_MASK; /* get cmd */
if (f & CMC_CLR) { /* clear? */
dp_reset (&dp_dev); /* reset world */
break; }
u = (dp_svun - dp_dib.dno - o_DP0) / o_DP0; /* get unit */
uptr = dp_dev.units + u; /* ignore if busy */
if (!(dp_sta & STC_IDL) || sim_is_active (uptr)) break;
dp_cmd = f; /* save cmd */
if (dp_cmd == CMC_WR) dp_sta = 0; /* write: bsy=0 else */
else dp_sta = STA_BSY; /* bsy=1,idl,err=0 */
dp_1st = 1; /* xfr not started */
dp_bptr = 0; /* buffer empty */
if (dp_svun & o_DPF) dp_plat = 1; /* upper platter? */
else dp_plat = 0; /* no, lower */
if (good_cmd[f]) sim_activate (uptr, dp_rtime); /* legal? sched */
break; }
return 0;
}
/* Drives: IO routine */
uint32 dp (uint32 dev, uint32 op, uint32 dat)
{
int32 diff;
uint32 t, u;
UNIT *uptr;
if (dev == dp_dib.dno) return dpc (dev, op, dat); /* controller? */
u = (dev - dp_dib.dno - o_DP0) / o_DP0; /* get unit num */
uptr = dp_dev.units + u; /* get unit ptr */
switch (op) { /* case IO op */
case IO_ADR: /* select */
if (dp_sta & STC_IDL) dp_svun = dev; /* idle? save unit */
return BY; /* byte only */
case IO_WD: /* write data */
if (GET_DTYPE (uptr->flags) == TYPE_2315) /* 2.5MB drive? */
dp_cyl = dat & 0xFF; /* cyl is 8b */
else dp_cyl = ((dp_cyl << 8) | dat) & DMASK16; /* insert byte */
break;
case IO_SS: /* status */
if (uptr->flags & UNIT_ATT) t = /* onl? */
((uptr->flags & UNIT_WPRT)? STD_WRP: 0) |
((dp_sta & STC_IDL)? 0: STD_ILK) |
(uptr->STD & STD_UST);
else t = STD_MOV | STD_NRDY; /* off = X'09' */
if (t & SETD_EX) t = t | STA_EX; /* test for ex */
return t;
case IO_OC: /* command */
dpd_arm[u] = int_chg (v_DPC + u + 1, dat, dpd_arm[u]);
if (dat & CMD_SK) t = dp_cyl; /* seek? get cyl */
else if (dat & CMD_RST) t = 0; /* rest? cyl 0 */
else break; /* no action */
diff = t - uptr->CYL;
if (diff < 0) diff = -diff; /* ABS cyl diff */
else if (diff == 0) diff = 1; /* must be nz */
uptr->STD = STD_MOV; /* stat = moving */
uptr->CYL = t; /* put on cyl */
sim_activate (uptr, diff * dp_stime); /* schedule */
break; }
return 0;
}
/* Unit service
If seek done, on cylinder;
if read check, signal completion;
else, do read or write
*/
t_stat dp_svc (UNIT *uptr)
{
uint32 u = uptr - dp_dev.units; /* get unit number */
int32 cyl = uptr->CYL; /* get cylinder */
uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */
uint32 t;
t_stat r;
if (uptr->STD & STD_MOV) { /* seek? */
uptr->STD = 0; /* clr seek in prog */
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* offl? hangs */
if (cyl >= drv_tab[dtype].cyl) { /* bad cylinder? */
uptr->STD = STD_ILA; /* error */
uptr->CYL = drv_tab[dtype].cyl - 1; } /* put at edge */
if (dpd_arm[u]) SET_INT (v_DPC + u + 1); /* req intr */
return SCPE_OK; }
switch (dp_cmd & 0x7) { /* case on func */
case CMC_RCHK: /* read check */
dp_dter (uptr, 1); /* check xfr err */
break;
case CMC_RD: /* read */
if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */
if (dp_dter (uptr, dp_1st)) return SCPE_OK; /* check xfr err */
if (r = dp_rds (uptr)) return r; /* read sec, err? */
dp_1st = 0;
t = sch_wrmem (dp_dib.sch, dpxb, DP_NUMBY); /* write to memory */
if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */
sim_activate (uptr, dp_rtime); /* reschedule */
return SCPE_OK; }
break; } /* no, set done */
dp_sta = dp_sta | STC_DTE; /* can't work */
break;
case CMC_WR: /* write */
if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */
dp_bptr = sch_rdmem (dp_dib.sch, dpxb, DP_NUMBY); /* read from mem */
dp_db = dpxb[dp_bptr - 1]; /* last byte */
if (dp_dter (uptr, dp_1st)) return SCPE_OK; /* check xfr err */
if (r = dp_wds (uptr)) return r; /* write sec, err? */
dp_1st = 0;
if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */
sim_activate (uptr, dp_rtime); /* reschedule */
return SCPE_OK; }
break; } /* no, set done */
dp_sta = dp_sta | STC_DTE; /* can't work */
break; }
dp_done (0); /* done */
return SCPE_OK;
}
/* Read data sector */
t_stat dp_rds (UNIT *uptr)
{
uint32 i;
i = fxread (dpxb, sizeof (uint8), DP_NUMBY, uptr->fileref);
for ( ; i < DP_NUMBY; i++) dpxb[i] = 0; /* fill with 0's */
if (ferror (uptr->fileref)) { /* error? */
perror ("DP I/O error");
clearerr (uptr->fileref);
dp_done (STC_DTE);
return SCPE_IOERR; }
return SCPE_OK;
}
/* Write data sector */
t_stat dp_wds (UNIT *uptr)
{
for ( ; dp_bptr < DP_NUMBY; dp_bptr++)
dpxb[dp_bptr] = dp_db; /* fill with last */
fxwrite (dpxb, sizeof (uint8), DP_NUMBY, uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */
perror ("DP I/O error");
clearerr (uptr->fileref);
dp_done (STC_DTE);
return SCPE_IOERR; }
return SCPE_OK;
}
/* Data transfer error test routine */
t_bool dp_dter (UNIT *uptr, uint32 first)
{
uint32 hd, sc, sa;
uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */
if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */
((uptr->flags & UNIT_WPRT) && (dp_cmd == CMC_WR))) {
dp_done (STC_DTE); /* error, done */
return TRUE; }
hd = GET_SRF (dp_hdsc); /* get head */
sc = GET_SEC (dp_hdsc); /* get sector */
if (dp_cyl != (uint32) uptr->CYL) { /* wrong cylinder? */
dp_done (STC_ACF); /* error, done */
return TRUE; }
if (sc >= DP_NUMSC) { /* bad sector? */
dp_done (STC_OVR); /* error, done */
return TRUE; }
if (!first && (sc == 0) && (hd == 0)) { /* cyl overflow? */
dp_done (STC_CYO); /* error, done */
return TRUE; }
sa = GET_SA (dp_plat, uptr->CYL, hd, sc, dtype); /* curr disk addr */
fseek (uptr->fileref, sa * DP_NUMBY, SEEK_SET);
if ((sc + 1) < DP_NUMSC) dp_hdsc = dp_hdsc + 1; /* end of track? */
else dp_hdsc = (dp_hdsc ^ HS_HMASK) & HS_HMASK; /* sec 0, nxt srf */
return FALSE;
}
/* Data transfer done routine */
void dp_done (uint32 flg)
{
dp_sta = (dp_sta | STC_IDL | flg) & ~STA_BSY; /* set flag, idle */
SET_INT (v_DPC); /* unmaskable intr */
if (flg) sch_stop (dp_dib.sch); /* if err, stop ch */
return;
}
/* Reset routine */
t_stat dp_reset (DEVICE *dptr)
{
uint32 u;
UNIT *uptr;
dp_cmd = 0; /* clear cmd */
dp_sta = STA_BSY | STC_IDL; /* idle, busy */
dp_1st = 0; /* clear flag */
dp_svun = dp_db = 0; /* clear unit, buf */
dp_plat = 0;
dp_hdsc = 0; /* clear addr */
CLR_INT (v_DPC); /* clear ctrl int */
SET_ENB (v_DPC); /* always enabled */
for (u = 0; u < DP_NUMDR; u++) { /* loop thru units */
uptr = dp_dev.units + u;
uptr->CYL = uptr->STD = 0;
CLR_INT (v_DPC + u + 1); /* clear intr */
CLR_ENB (v_DPC + u + 1); /* clear enable */
dpd_arm[u] = 0; /* clear arm */
sim_cancel (uptr); } /* cancel activity */
return SCPE_OK;
}
/* Attach routine (with optional autosizing) */
t_stat dp_attach (UNIT *uptr, char *cptr)
{
uint32 i, p;
t_stat r;
uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;
r = attach_unit (uptr, cptr);
uptr->CYL = 0;
if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r;
if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK;
if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK;
for (i = 0; drv_tab[i].surf != 0; i++) {
if (p <= drv_tab[i].size) {
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
uptr->capac = drv_tab[i].size;
return SCPE_OK; } }
return SCPE_OK;
}
/* Detach routine (generates an interrupt) */
t_stat dp_detach (UNIT *uptr)
{
uint32 u = uptr - dp_dev.units;
if (dpd_arm[u]) SET_INT (v_DPC + u + 1); /* if arm, intr */
return detach_unit (uptr);
}
/* Set size command validation routine */
t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = drv_tab[GET_DTYPE (val)].size;
return SCPE_OK;
}
/* Create device number (T) or interrupt (F) template */
void dp_ini (t_bool dtpl)
{
int32 u, j, dev;
dp_tplte[0] = 0; /* controller */
for (u = 0, j = 1; u < DP_NUMDR; u++) { /* loop thru units */
dev = (u + 1) * o_DP0; /* drive dev # */
dp_tplte[j++] = dev;
if (dtpl && (GET_DTYPE (dp_unit[u].flags) == TYPE_5440))
dp_tplte[j++] = dev + o_DPF; } /* if fixed */
dp_tplte[j] = TPL_END; /* end marker */
return;
}

480
Interdata/id_fd.c Normal file
View file

@ -0,0 +1,480 @@
/* id_fd.c: Interdata floppy disk simulator
Copyright (c) 2001-2002, 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.
fd M46-630 floppy disk
A diskette consists of 77 tracks, each with 26 sectors of 128B. The
Interdata floppy uses a logical record numbering scheme from 1 to 2002.
Physical tracks are numbered 0-76, physical sectors 1-26.
To allow for deleted data handling, a directory is appended to the end
of the image, one byte per LRN. Zero (the default) is a normal record,
non-zero a deleted record.
*/
#include "id_defs.h"
#define FD_NUMTR 77 /* tracks/disk */
#define FD_NUMSC 26 /* sectors/track */
#define FD_NUMBY 128 /* bytes/sector */
#define FD_NUMLRN (FD_NUMTR * FD_NUMSC) /* LRNs/disk */
#define FD_SIZE (FD_NUMLRN * FD_NUMBY) /* bytes/disk */
#define FD_NUMDR 4 /* drives/controller */
#define UNIT_V_WLK (UNIT_V_UF) /* write locked */
#define UNIT_WLK (1u << UNIT_V_UF)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
#define LRN u3 /* last LRN */
#define FNC u4 /* last function */
#define GET_DA(x) (((x) - 1) * FD_NUMBY)
#define GET_TRK(x) (((x) - 1) / FD_NUMSC)
#define GET_SEC(x) ((((x) - 1) % FD_NUMSC) + 1)
#define LRN_BOOT 5 /* boot block LRN */
/* Command byte */
#define CMD_V_UNIT 4 /* unit */
#define CMD_M_UNIT 0x3
#define GET_UNIT(x) (((x) >> CMD_V_UNIT) & CMD_M_UNIT)
#define CMD_V_FNC 0 /* function */
#define CMD_M_FNC 0xF
#define GET_FNC(x) (((x) >> CMD_V_FNC) & CMD_M_FNC)
#define FNC_RD 0x1 /* read */
#define FNC_WR 0x2 /* write */
#define FNC_RDID 0x3 /* read ID */
#define FNC_RSTA 0x4 /* read status */
#define FNC_DEL 0x5 /* write deleted */
#define FNC_BOOT 0x6 /* boot */
#define FNC_STOP 0x7 /* stop */
#define FNC_RESET 0x8 /* reset */
#define FNC_FMT 0x9 /* format NI */
#define FNC_STOPPING 0x10 /* stopping */
/* Status byte, * = dynamic */
#define STA_WRP 0x80 /* *write prot */
#define STA_DEF 0x40 /* def track NI */
#define STA_DEL 0x20 /* del record */
#define STA_ERR 0x10 /* error */
#define STA_IDL 0x02 /* idle */
#define STA_OFL 0x01 /* fault */
#define STA_MASK (STA_DEF|STA_DEL|STA_ERR|STA_BSY|STA_IDL)
#define SET_EX (STA_ERR) /* set EX */
/* Extended status, 6 bytes, * = dynamic */
#define ES_SIZE 6
#define ES0_HCRC 0x80 /* ID CRC NI */
#define ES0_DCRC 0x40 /* data CRC NI */
#define ES0_LRN 0x20 /* illegal LRN */
#define ES0_WRP 0x10 /* *write prot */
#define ES0_ERR 0x08 /* error */
#define ES0_DEF 0x04 /* def trk NI */
#define ES0_DEL 0x02 /* del rec NI */
#define ES0_FLT 0x01 /* fault */
#define ES1_TK0 0x80 /* track 0 */
#define ES1_NRDY 0x40 /* not ready */
#define ES1_NOAM 0x20 /* no addr mk NI */
#define ES1_CMD 0x10 /* illegal cmd */
#define ES1_SKE 0x08 /* seek err NI */
#define ES1_UNS 0x04 /* unsafe NI */
#define ES1_UNIT 0x03 /* unit # */
/* Processing options for commands */
#define C_RD 0x1 /* cmd reads disk */
#define C_WD 0x2 /* cmd writes disk */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint32 fd_sta = 0; /* status */
uint32 fd_cmd = 0; /* command */
uint32 fd_db = 0; /* data buffer */
uint32 fd_bptr = 0; /* buffer pointer */
uint8 fdxb[FD_NUMBY] = { 0 }; /* sector buffer */
uint8 fd_es[FD_NUMDR][ES_SIZE] = { 0 }; /* ext status */
uint32 fd_lrn = 0; /* log rec # */
uint32 fd_wdv = 0; /* wd valid */
uint32 fd_stopioe = 1; /* stop on error */
uint32 fd_arm = 0; /* intr arm */
int32 fd_ctime = 100; /* command time */
int32 fd_stime = 10; /* seek, per LRN */
int32 fd_xtime = 1; /* tr set time */
static uint32 ctab[16] = {
0, C_RD, C_WD, 0, /* 0, rd, wr, 0 */
0, C_WD, C_RD, 0, /* 0, del, boot, 0 */
0, 0, 0, 0,
0, 0, 0, 0 };
DEVICE fd_dev;
uint32 fd (uint32 dev, uint32 op, uint32 dat);
t_stat fd_svc (UNIT *uptr);
t_stat fd_reset (DEVICE *dptr);
t_stat fd_clr (DEVICE *dptr);
t_stat fd_boot (int32 unitno, DEVICE *dptr);
t_bool fd_dte (UNIT *uptr, t_bool wr);
uint32 fd_crc (uint32 crc, uint32 dat, uint32 cnt);
void fd_done (uint32 u, uint32 nsta, uint32 nes0, uint32 nes1);
void sched_seek (UNIT *uptr, int32 newlrn);
/* FD data structures
fd_dev FD device descriptor
fd_unit FD unit list
fd_reg FD register list
fd_mod FD modifier list
*/
DIB fd_dib = { d_FD, -1, v_FD, NULL, &fd, NULL };
UNIT fd_unit[] = {
{ UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) },
{ UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) },
{ UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) },
{ UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) } };
REG fd_reg[] = {
{ HRDATA (CMD, fd_cmd, 8) },
{ HRDATA (STA, fd_sta, 8) },
{ HRDATA (BUF, fd_db, 8) },
{ HRDATA (LRN, fd_lrn, 16) },
{ BRDATA (ESTA, fd_es, 16, 8, ES_SIZE * FD_NUMDR) },
{ BRDATA (DBUF, fdxb, 16, 8, FD_NUMBY) },
{ HRDATA (DBPTR, fd_bptr, 8) },
{ FLDATA (WDV, fd_wdv, 0) },
{ FLDATA (IREQ, int_req[l_FD], i_FD) },
{ FLDATA (IENB, int_enb[l_FD], i_FD) },
{ FLDATA (IARM, fd_arm, 0) },
{ DRDATA (CTIME, fd_ctime, 24), PV_LEFT },
{ DRDATA (STIME, fd_stime, 24), PV_LEFT },
{ DRDATA (XTIME, fd_xtime, 24), PV_LEFT },
{ FLDATA (STOP_IOE, fd_stopioe, 0) },
{ URDATA (ULRN, fd_unit[0].LRN, 16, 16, 0, FD_NUMDR, REG_HRO) },
{ URDATA (UFNC, fd_unit[0].FNC, 16, 8, 0, FD_NUMDR, REG_HRO) },
{ HRDATA (DEVNO, fd_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB fd_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
DEVICE fd_dev = {
"FD", fd_unit, fd_reg, fd_mod,
FD_NUMDR, 16, 20, 1, 16, 8,
NULL, NULL, &fd_reset,
&fd_boot, NULL, NULL,
&fd_dib, DEV_DISABLE };
/* Floppy disk: IO routine */
uint32 fd (uint32 dev, uint32 op, uint32 dat)
{
int32 u, t, fnc;
UNIT *uptr;
fnc = GET_FNC (fd_cmd); /* get fnc */
u = GET_UNIT (fd_cmd); /* get unit */
uptr = fd_dev.units + u;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_RD: /* read */
if (fd_sta & (STA_IDL | STA_BSY)) return fd_db; /* idle, busy? */
if (fd_bptr < FD_NUMBY) fd_db = fdxb[fd_bptr++];/* get byte */
if (fd_bptr >= FD_NUMBY) { /* buf end? */
if (ctab[fnc] & C_RD) { /* disk read? */
sched_seek (uptr, uptr->LRN + 1); /* sched read */
fd_sta = fd_sta | STA_BSY; } /* set busy */
else fd_bptr = 0; } /* just wrap */
if ((ctab[fnc] & C_RD) && fd_arm) /* if rd & arm, */
SET_INT (v_FD); /* interrupt */
return fd_db; /* return buf */
case IO_WD: /* write */
if (fd_sta & STA_IDL) { /* idle? */
fd_lrn = ((fd_lrn << 8) | dat) & DMASK16; /* insert byte */
fd_wdv = 1;
break; }
if (fd_bptr < FD_NUMBY) /* if room, */
fdxb[fd_bptr++] = fd_db = dat; /* store byte */
if (fd_bptr >= FD_NUMBY) { /* buf end? */
if (ctab[fnc] & C_WD) { /* disk write? */
sched_seek (uptr, uptr->LRN + 1); /* sched write */
fd_sta = fd_sta | STA_BSY; } /* set busy */
else fd_bptr = 0; } /* just wrap */
if ((ctab[fnc] & C_WD) && fd_arm) /* if wr & arm, */
SET_INT (v_FD); /* interrupt */
break;
case IO_SS: /* status */
t = fd_sta & STA_MASK; /* get status */
if ((uptr->flags & UNIT_ATT) == 0) t = t | STA_DU;
if (t & SET_EX) t = t | STA_EX; /* test for ex */
return t;
case IO_OC: /* command */
fd_arm = int_chg (v_FD, dat, fd_arm); /* upd int ctrl */
fnc = GET_FNC (dat); /* new fnc */
fd_cmd = dat; /* save cmd */
u = GET_UNIT (dat); /* get unit */
uptr = fd_dev.units + u;
if (fnc == FNC_STOP) { /* stop? */
uptr->FNC = uptr->FNC | FNC_STOPPING; /* flag stop */
if (sim_is_active (uptr)) break; /* busy? cont */
if (ctab[GET_FNC (uptr->FNC)] & C_WD) { /* write? */
sched_seek (uptr, uptr->LRN + 1); /* sched write */
fd_sta = fd_sta | STA_BSY; } /* set busy */
else fd_done (u, 0, 0, 0); /* nrml done */
break; }
else if (fd_sta & STA_IDL) { /* must be idle */
if (fnc != FNC_RSTA) { /* !rd status */
fd_sta = STA_BSY; /* busy, !idle */
fd_es[u][0] = 0;
fd_es[u][1] = u; } /* init ext sta */
else fd_sta = (fd_sta & ~STA_IDL) | STA_BSY;
if (fnc == FNC_BOOT) t = LRN_BOOT; /* boot? fixed sec */
else if (fd_wdv) t = fd_lrn; /* valid data? use */
else t = uptr->LRN; /* use prev */
fd_wdv = 0; /* data invalid */
fd_bptr = 0; /* init buffer */
uptr->FNC = fnc; /* save function */
uptr->LRN = t; /* save LRN */
if (ctab[fnc] & C_RD) sched_seek (uptr, t); /* seek now? */
else sim_activate (uptr, fd_ctime); } /* start cmd */
break; }
return 0;
}
/* Unit service; the action to be taken depends on command */
t_stat fd_svc (UNIT *uptr)
{
uint32 i, u, tk, sc, crc, fnc;
t_addr da;
u = uptr - fd_dev.units; /* get unit number */
fnc = GET_FNC (uptr->FNC); /* get function */
switch (fnc) { /* case on function */
case FNC_RESET: /* reset */
fd_clr (&fd_dev); /* clear device */
fd_done (u, 0, 0, 0); /* set idle */
return SCPE_OK;
case FNC_STOP: /* stop */
fd_done (u, 0, 0, 0); /* set idle */
return SCPE_OK;
case FNC_BOOT: /* boot, buf empty */
case FNC_RD: /* read, buf empty */
if (uptr->FNC & FNC_STOPPING) break; /* stopped? */
if (fd_dte (uptr, FALSE)) return SCPE_OK; /* xfr error? */
da = GET_DA (uptr->LRN); /* get disk addr */
for (i = 0; i < FD_NUMBY; i++) /* read sector */
fdxb[i] = *(((uint8 *) uptr->filebuf) + da + i);
if (*(((uint8 *) uptr->filebuf) + FD_SIZE + uptr->LRN - 1)) {
fd_sta = fd_sta | STA_DEL; /* deleted? set err */
fd_es[u][0] = fd_es[u][0] | ES0_DEL; }
fd_es[u][2] = GET_SEC (uptr->LRN); /* set ext sec/trk */
fd_es[u][3] = GET_TRK (uptr->LRN);
fd_bptr = 0; /* init buf */
uptr->LRN = uptr->LRN + 1; /* next block */
break;
case FNC_WR: case FNC_DEL: /* write block */
if (fd_dte (uptr, TRUE)) return SCPE_OK; /* xfr error? */
if (fd_bptr) { /* any transfer? */
da = GET_DA (uptr->LRN); /* get disk addr */
for (i = fd_bptr; i < FD_NUMBY; i++) /* pad sector */
fdxb[i] = fd_db;
for (i = 0; i < FD_NUMBY; i++) /* write sector */
*(((uint8 *) uptr->filebuf) + da + i) = fdxb[i];
*(((uint8 *) uptr->filebuf) + FD_SIZE + uptr->LRN - 1) =
(fnc == FNC_DEL)? 1: 0; /* write dir */
uptr->hwmark = uptr->capac; /* rewrite all */
fd_es[u][2] = GET_SEC (uptr->LRN); /* set ext sec/trk */
fd_es[u][3] = GET_TRK (uptr->LRN);
fd_bptr = 0; /* init buf */
uptr->LRN = uptr->LRN + 1; } /* next block */
break;
case FNC_RSTA: /* read status */
if (uptr->flags & UNIT_WPRT) /* wr protected? */
fd_es[u][0] = fd_es[u][0] | ES0_WRP;
if (GET_TRK (uptr->LRN) == 0) /* on track 0? */
fd_es[u][1] = fd_es[u][1] | ES1_TK0;
if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */
fd_es[u][0] = fd_es[u][0] | ES0_FLT; /* set err */
fd_es[u][1] = fd_es[u][1] | ES1_NRDY; }
for (i = 0; i < ES_SIZE; i++) fdxb[i] = fd_es[u][i]; /* copy to buf */
for (i = ES_SIZE; i < FD_NUMBY; i++) fdxb[i] = 0;
break;
case FNC_RDID: /* read ID */
if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */
fd_done (u, STA_ERR, ES0_ERR | ES0_FLT, ES1_NRDY);
return SCPE_OK; }
for (i = 0; i < FD_NUMBY; i++) fdxb[i] = 0; /* clr buf */
tk = GET_TRK (uptr->LRN); /* get track */
sc = GET_SEC (uptr->LRN); /* get sector */
fdxb[0] = tk & 0xFF; /* store track */
fdxb[2] = sc & 0xFF; /* store sector */
crc = fd_crc (0xFFFF, 0xFE00, 8); /* CRC addr mark */
crc = fd_crc (crc, tk << 8, 16); /* CRC track */
crc = fd_crc (crc, sc << 8, 16); /* CRC sector */
fdxb[4] = (crc >> 8) & 0xFF; /* store CRC */
fdxb[5] = crc & 0xFF;
break;
case FNC_FMT: /* format */
default:
fd_done (u, STA_ERR, ES0_ERR, ES1_CMD); /* ill cmd */
uptr->LRN = 1; /* on track 0 */
return SCPE_OK; }
if (uptr->FNC & FNC_STOPPING) { /* stopping? */
uptr->FNC = FNC_STOP; /* fnc = STOP */
sim_activate (uptr, fd_ctime); } /* schedule */
fd_sta = fd_sta & ~STA_BSY; /* clear busy */
if (fd_arm) SET_INT (v_FD); /* if armed, int */
return SCPE_OK;
}
/* Schedule seek */
void sched_seek (UNIT *uptr, int32 newlrn)
{
int32 diff = newlrn - uptr->LRN; /* LRN diff */
if (diff < 0) diff = -diff; /* ABS */
if (diff < 10) diff = 10; /* MIN 10 */
sim_activate (uptr, diff * fd_stime); /* schedule */
return;
}
/* Command complete */
void fd_done (uint32 u, uint32 nsta, uint32 nes0, uint32 nes1)
{
fd_sta = (fd_sta | STA_IDL | nsta) & ~STA_BSY; /* set idle */
if (fd_arm) SET_INT (v_FD); /* if armed, int */
fd_es[u][0] = fd_es[u][0] | nes0; /* set ext state */
fd_es[u][1] = fd_es[u][1] | nes1;
return;
}
/* Test for data transfer error */
t_bool fd_dte (UNIT *uptr, t_bool wr)
{
uint32 u = uptr - fd_dev.units;
if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */
fd_done (u, STA_ERR, ES0_ERR | ES0_FLT, ES1_NRDY);
return TRUE; }
if (wr && (uptr->flags & UNIT_WPRT)) { /* wr protected? */
fd_done (u, STA_ERR, ES0_ERR | ES0_WRP, 0);
return TRUE; }
if ((uptr->LRN == 0) || (uptr->LRN > FD_NUMLRN)) { /* bad LRN? */
fd_done (u, STA_ERR, ES0_ERR | ES0_LRN, 0);
return TRUE; }
return FALSE;
}
/* Header CRC calculation */
uint32 fd_crc (uint32 crc, uint32 dat, uint32 cnt)
{
uint32 i, wrk;
for (i = 0; i < cnt; i++) {
wrk = crc ^ dat;
crc = (crc << 1) & DMASK16;
if (wrk & SIGN16) crc = ((crc ^ 0x1020) + 1) & DMASK16;
dat = (dat << 1) & DMASK16; }
return crc;
}
/* Reset routine */
t_stat fd_clr (DEVICE *dptr)
{
int32 i, j;
UNIT *uptr;
fd_sta = STA_IDL; /* idle */
fd_cmd = 0; /* clear state */
fd_db = 0;
fd_bptr = 0;
fd_lrn = 1;
fd_wdv = 0;
for (i = 0; i < FD_NUMBY; i++) fdxb[i] = 0; /* clr xfr buf */
for (i = 0; i < FD_NUMDR; i++) { /* loop thru units */
for (j = 0; j < ES_SIZE; j++) fd_es[i][j] = 0; /* clr ext sta */
fd_es[i][2] = 1; /* sector 1 */
uptr = fd_dev.units + i;
sim_cancel (uptr); /* stop drive */
uptr->LRN = 1; /* clear state */
uptr->FNC = 0; }
return SCPE_OK;
}
t_stat fd_reset (DEVICE *dptr)
{
CLR_INT (v_FD); /* clear int */
CLR_ENB (v_FD); /* disable int */
fd_arm = 0; /* disarm int */
return fd_clr (dptr);;
}
/* Bootstrap routine */
#define BOOT_START 0x50
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
static uint8 boot_rom[] = {
0xD5, 0x00, /* ST: AL CF */
0x00, 0xCF,
0x43, 0x00, /* BR 80 */
0x00, 0x80
};
t_stat fd_boot (int32 unitno, DEVICE *dptr)
{
extern uint32 PC, dec_flgs;
extern uint16 decrom[];
if (decrom[0xD5] & dec_flgs) return SCPE_NOFNC; /* AL defined? */
IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy boot */
IOWriteB (AL_DEV, fd_dib.dno); /* set dev no */
IOWriteB (AL_IOC, 0x86 + (unitno << CMD_V_UNIT)); /* set dev cmd, unit num */
IOWriteB (AL_SCH, 0); /* clr sch dev no */
PC = BOOT_START;
return SCPE_OK;
}

471
Interdata/id_fp.c Normal file
View file

@ -0,0 +1,471 @@
/* id_fp.c: Interdata floating point instructions
Copyright (c) 2000-2002, 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.
The Interdata uses IBM 360 floating point format:
0 7 8 15 23 31
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|S| exponent | fraction | :single
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| fraction low | :double
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
where S = 0 for plus, 1 for minus
exponent = 16**n, in excess 64 code
fraction = .hhhhhh, seen as 6-14 hexadecimal digits
Numbers can be normalized or unnormalized but are always normalized
when loaded.
Interdata has 8 floating point registers, F0, F2, ... , FE. In floating
point instructions, the low order bit of the register number is ignored.
On floating point overflow, the exponent and fraction are set to 1's.
On floating point underflow, the exponent and fraction are set to 0's.
Interdata has both 32b only and 32b/64b floating point implementations.
In 32b only implementations, add and subtract are truncated, but multiply
and divide are rounded, and the floating point registers are kept in
memory. In 64b implementations, all single precision precision operations
are rounded, double precision operations are truncated, and the floating
point registers are kept in separate hardware arrays.
*/
#include "id_defs.h"
struct ufp { /* unpacked fp */
int32 sign; /* sign */
int32 exp; /* unbiased exp */
uint32 h; /* fr high */
uint32 l; }; /* fr low */
#define FP_V_SIGN 31 /* sign */
#define FP_M_SIGN 0x1
#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN)
#define FP_V_EXP 24 /* exponent */
#define FP_M_EXP 0x7F
#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP)
#define FP_V_FRH 0 /* fraction */
#define FP_M_FRH 0xFFFFFF
#define FP_GETFRH(x) (((x) >> FP_V_FRH) & FP_M_FRH)
#define FP_GETFRL(x) (x)
#define FP_BIAS 0x40 /* exp bias */
#define FP_CARRY (1 << FP_V_EXP ) /* carry out */
#define FP_NORM (0xF << (FP_V_EXP - 4)) /* normalized */
#define FP_ROUND 0x80000000
/* Double precision fraction add/subtract/compare */
#define FR_ADD(d,s) d.l = (d.l + s.l) & DMASK32; \
d.h = (d.h + s.h + (d.l < s.l)) & DMASK32
#define FR_SUB(d,s) d.h = (d.h - s.h - (d.l < s.l)) & DMASK32; \
d.l = (d.l - s.l) & DMASK32
#define FR_GE(s1,s2) ((s1.h > s2.h) || \
((s1.h == s2.h) && (s1.l >= s2.l)))
/* Variable and constant shifts; for constants, 0 < k < 32 */
#define FR_RSH_V(v,s) if ((s) < 32) { \
v.l = ((v.l >> (s)) | \
(v.h << (32 - (s)))) & DMASK32; \
v.h = (v.h >> (s)) & DMASK32; } \
else { v.l = v.h >> ((s) - 32); \
v.h = 0; }
#define FR_RSH_K(v,s) v.l = ((v.l >> (s)) | \
(v.h << (32 - (s)))) & DMASK32; \
v.h = (v.h >> (s)) & DMASK32
#define FR_LSH_K(v,s) v.h = ((v.h << (s)) | \
(v.l >> (32 - (s)))) & DMASK32; \
v.l = (v.l << (s)) & DMASK32
#define Q_RND(op) (OP_DPFP (op) == 0)
#define Q_RND_AS(op) ((OP_DPFP (op) == 0) && fp_in_hwre)
extern uint32 *R;
extern uint32 F[8];
extern dpr_t D[8];
extern uint16 decrom[];
extern uint32 fp_in_hwre;
extern uint32 ReadF (uint32 loc, uint32 rel);
extern void WriteF (uint32 loc, uint32 dat, uint32 rel);
void ReadFP2 (struct ufp *fop, uint32 op, uint32 r2, uint32 ea);
void UnpackFPR (struct ufp *fop, uint32 op, uint32 r1);
void NormUFP (struct ufp *fop);
uint32 StoreFPR (struct ufp *fop, uint32 op, uint32 r1, uint32 rnd);
uint32 StoreFPX (struct ufp *fop, uint32 op, uint32 r1);
/* Floating point load */
uint32 f_l (uint32 op, uint32 r1, uint32 r2, uint32 ea)
{
struct ufp fop2;
ReadFP2 (&fop2, op, r2, ea); /* get op, normalize */
return StoreFPR (&fop2, op, r1, 0); /* store, chk unflo */
}
/* Floating point compare */
uint32 f_c (uint32 op, uint32 r1, uint32 r2, uint32 ea)
{
struct ufp fop1, fop2;
ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */
UnpackFPR (&fop1, op, r1); /* get op1, norm */
if (fop1.sign ^ fop2.sign) /* signs differ? */
return (fop2.sign? CC_G: (CC_C | CC_L));
if (fop1.exp != fop2.exp) /* exps differ? */
return (((fop1.exp > fop2.exp) ^ fop1.sign)? CC_G: (CC_C | CC_L));
if (fop1.h != fop2.h) /* hi fracs differ? */
return (((fop1.h > fop2.h) ^ fop1.sign)? CC_G: (CC_C | CC_L));
if (OP_DPFP (op) && (fop1.l != fop2.l)) /* dp: low fracs diff? */
return (((fop1.l > fop2.l) ^ fop1.sign)? CC_G: (CC_C | CC_L));
return 0;
}
/* Floating to integer conversion */
uint32 f_fix (uint32 op, uint32 r1, uint32 r2) /* 16b */
{
struct ufp res;
uint32 cc;
UnpackFPR (&res, op, r2); /* get op2, norm */
if ((res.h == 0) || (res.exp < 0x41)) { /* result zero? */
R[r1] = 0;
return 0; }
if ((res.exp > 0x44) || /* result too big? */
((res.exp == 0x44) && (res.h >= 0x00800000))) {
res.h = MMASK16;
cc = CC_V; }
else { res.h = res.h >> ((0x46 - res.exp) * 4); /* right align frac */
cc = 0; }
if (res.sign) {
R[r1] = ((res.h ^ DMASK16) + 1) & DMASK16; /* negate result */
return cc | CC_L; }
R[r1] = res.h & DMASK16;
return cc | CC_G;
}
uint32 f_fix32 (uint32 op, uint32 r1, uint32 r2) /* 32b */
{
struct ufp res;
uint32 cc;
UnpackFPR (&res, op, r2); /* get op2, norm */
if ((res.h == 0) || (res.exp < 0x41)) { /* result zero? */
R[r1] = 0;
return 0; }
if ((res.exp > 0x48) || /* result too big? */
((res.exp == 0x48) && (res.h >= 0x00800000))) {
res.h = MMASK32;
cc = CC_V; }
else { FR_LSH_K (res, 8); /* get all in 32b */
res.h = res.h >> ((0x48 - res.exp) * 4); /* right align frac */
cc = 0; }
if (res.sign) {
R[r1] = (res.h ^ DMASK32) + 1; /* negate result */
return cc | CC_L; }
R[r1] = res.h;
return cc | CC_G;
}
/* Integer to floating conversion */
uint32 f_flt (uint32 op, uint32 r1, uint32 r2) /* 16b */
{
struct ufp res = { 0, 0x44, 0, 0 }; /* +, 16**4 */
uint32 cc;
if (R[r2] == 0) cc = 0; /* zero arg? */
else if (R[r2] & SIGN16) { /* neg arg? */
res.sign = FP_M_SIGN; /* set sign */
res.h = ((~R[r2] + 1) & DMASK16) << 8; /* get magnitude */
cc = CC_L; }
else { res.h = R[r2] << 8; /* pos nz arg */
cc = CC_G; }
NormUFP (&res); /* normalize */
StoreFPR (&res, op, r1, 0); /* store result */
return cc;
}
uint32 f_flt32 (uint32 op, uint32 r1, uint32 r2) /* 32b */
{
struct ufp res = { 0, 0x48, 0, 0 }; /* +, 16**8 */
uint32 cc, t;
t = R[r2]; /* int op */
if (t) { /* nonzero arg? */
if (t & SIGN32) { /* neg arg? */
res.sign = FP_M_SIGN; /* set sign */
t = (~t + 1) & DMASK32; /* get magnitude */
cc = CC_L; }
else cc = CC_G; /* pos nz arg */
res.h = t >> 8; /* hi frac */
res.l = t << 24; } /* lo frac */
else cc = 0; /* zero arg */
NormUFP (&res); /* normalize */
StoreFPR (&res, op, r1, 0); /* store result */
return cc;
}
/* Floating point add/subtract */
uint32 f_as (uint32 op, uint32 r1, uint32 r2, uint32 ea)
{
struct ufp fop1, fop2, t;
int32 ediff;
ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */
UnpackFPR (&fop1, op, r1); /* get op1, norm */
if (op & 1) fop2.sign = fop2.sign ^ 1; /* if sub, inv sign2 */
if (fop1.h == 0) fop1 = fop2; /* if op1 = 0, res = op2 */
else if (fop2.h != 0) { /* if op2 = 0, no add */
if ((fop1.exp < fop2.exp) || /* |op1| < |op2|? */
((fop1.exp == fop2.exp) &&
((fop1.h < fop2.h) ||
((fop1.h == fop2.h) && (fop1.l < fop2.l))))) {
t = fop2; /* swap operands */
fop2 = fop1;
fop1 = t; }
ediff = fop1.exp - fop2.exp; /* exp difference */
if (OP_DPFP (op) || fp_in_hwre) { /* dbl prec or hwre? */
if (ediff >= 14) fop2.h = fop2.l = 0; /* diff too big? */
else if (ediff) { /* any difference? */
FR_RSH_V (fop2, ediff * 4); } } /* shift frac */
else { /* sgl prec ucode */
if (ediff >= 6) fop2.h = 0; /* diff too big? */
else if (ediff) /* any difference? */
fop2.h = fop2.h >> (ediff * 4); } /* shift frac */
if (fop1.sign ^ fop2.sign) { /* eff subtract */
FR_SUB (fop1, fop2); /* sub fractions */
NormUFP (&fop1); } /* normalize result */
else {
FR_ADD (fop1, fop2); /* add fractions */
if (fop1.h & FP_CARRY) { /* carry out? */
FR_RSH_K (fop1, 4); /* renormalize */
fop1.exp = fop1.exp + 1; } } /* incr exp */
} /* end if fop2 */
return StoreFPR (&fop1, op, r1, Q_RND_AS (op)); /* store result */
}
/* Floating point multiply
Notes:
- Exponent overflow/underflow is tested right after the exponent
add, without regard to potential changes due to normalization
- Exponent underflow is tested right after normalization, without
regard to changes due to rounding
- Single precision hardware multiply may generate up to 48b
- Double precision multiply generates 56b with no guard bits
*/
int32 f_m (uint32 op, uint32 r1, uint32 r2, uint32 ea)
{
struct ufp fop1, fop2;
struct ufp res = { 0, 0, 0, 0 };
uint32 i;
ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */
UnpackFPR (&fop1, op, r1); /* get op1, norm */
if (fop1.h && fop2.h) { /* if both != 0 */
res.sign = fop1.sign ^ fop2.sign; /* sign = diff */
res.exp = fop1.exp + fop2.exp - FP_BIAS; /* exp = sum */
if ((res.exp < 0) || (res.exp > FP_M_EXP)) /* ovf/undf? */
return StoreFPX (&res, op, r1); /* early out */
if ((fop1.l | fop2.l) == 0) { /* 24b x 24b? */
for (i = 0; i < 24; i++) { /* 24 iterations */
if (fop2.h & 1) res.h = res.h + fop1.h; /* add hi only */
FR_RSH_K (res, 1); /* shift dp res */
fop2.h = fop2.h >> 1; }
}
else { /* some low 0's */
if (fop2.l != 0) { /* 56b x 56b? */
for (i = 0; i < 32; i++) { /* do low 32b */
if (fop2.l & 1) { FR_ADD (res, fop1); }
FR_RSH_K (res, 1);
fop2.l = fop2.l >> 1; } }
for (i = 0; i < 24; i++) { /* do hi 24b */
if (fop2.h & 1) { FR_ADD (res, fop1); }
FR_RSH_K (res, 1);
fop2.h = fop2.h >> 1; }
}
NormUFP (&res); /* normalize */
if (res.exp < 0) /* underflow? */
return StoreFPX (&res, op, r1); /* early out */
}
return StoreFPR (&res, op, r1, Q_RND (op)); /* store */
}
/* Floating point divide - see overflow/underflow notes for multiply */
int32 f_d (uint32 op, uint32 r1, uint32 r2, uint32 ea)
{
struct ufp fop1, fop2;
struct ufp quo = { 0, 0, 0, 0 };
int32 i;
ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */
UnpackFPR (&fop1, op, r1); /* get op1, norm */
if (fop2.h == 0) return CC_C | CC_V; /* div by zero? */
if (fop1.h) { /* dvd != 0? */
quo.sign = fop1.sign ^ fop2.sign; /* sign = diff */
quo.exp = fop1.exp - fop2.exp + FP_BIAS; /* exp = diff */
if ((quo.exp < 0) || (quo.exp > FP_M_EXP)) /* ovf/undf? */
return StoreFPX (&quo, op, r1); /* early out */
if (!FR_GE (fop1, fop2)) {
FR_LSH_K (fop1, 4); } /* ensure success */
else { /* exp off by 1 */
quo.exp = quo.exp + 1; /* incr exponent */
if (quo.exp > FP_M_EXP) /* overflow? */
return StoreFPX (&quo, op, r1); } /* early out */
for (i = 0; i < (OP_DPFP (op)? 14: 6); i++) { /* 6/14 hex digits */
FR_LSH_K (quo, 4); /* shift quotient */
while (FR_GE (fop1, fop2)) { /* while sub works */
FR_SUB (fop1, fop2); /* decrement */
quo.l = quo.l + 1; } /* add quo bit */
FR_LSH_K (fop1, 4); } /* shift divd */
if (!OP_DPFP (op)) { /* single? */
quo.h = quo.l; /* move quotient */
if (fop1.h >= (fop2.h << 3)) quo.l = FP_ROUND;
else quo.l = 0; }
/* don't need to normalize */
} /* end if fop1.h */
return StoreFPR (&quo, op, r1, Q_RND (op)); /* store result */
}
/* Utility routines */
/* Unpack floating point number */
void UnpackFPR (struct ufp *fop, uint32 op, uint32 r1)
{
uint32 hi;
if (OP_DPFP (op)) { /* double prec? */
hi = D[r1 >> 1].h; /* get hi */
fop->l = FP_GETFRL (D[r1 >> 1].l); } /* get lo */
else { hi = ReadFReg (r1); /* single prec */
fop->l = 0; } /* lo is zero */
fop->h = FP_GETFRH (hi); /* get hi frac */
if (fop->h || fop->l) { /* non-zero? */
fop->sign = FP_GETSIGN (hi); /* get sign */
fop->exp = FP_GETEXP (hi); /* get exp */
NormUFP (fop); } /* normalize */
else fop->sign = fop->exp = 0; /* clean zero */
return;
}
/* Read memory operand */
void ReadFP2 (struct ufp *fop, uint32 op, uint32 r2, uint32 ea)
{
uint32 hi;
if (OP_TYPE (op) > OP_RR) { /* mem ref? */
hi = ReadF (ea, VR); /* get hi */
if (OP_DPFP (op)) fop->l = ReadF (ea + 4, VR); /* dp? get lo */
else fop->l = 0; } /* sp, lo = 0 */
else { if (OP_DPFP (op)) { /* RR */
hi = D[r2 >> 1].h; /* dp? get dp reg */
fop->l = D[r2 >> 1].l; }
else {
hi = ReadFReg (r2); /* get sp reg */
fop->l = 0; } }
fop->h = FP_GETFRH (hi); /* get hi frac */
if (fop->h || fop->l) { /* non-zero? */
fop->sign = FP_GETSIGN (hi); /* get sign */
fop->exp = FP_GETEXP (hi); /* get exp */
NormUFP (fop); } /* normalize */
else fop->sign = fop->exp = 0; /* clean zero */
return;
}
/* Normalize unpacked floating point number */
void NormUFP (struct ufp *fop)
{
if ((fop->h & FP_M_FRH) || fop->l) { /* any fraction? */
while ((fop->h & FP_NORM) == 0) { /* until norm */
fop->h = (fop->h << 4) | ((fop->l >> 28) & 0xF);
fop->l = fop->l << 4;
fop->exp = fop->exp - 1; } }
else fop->sign = fop->exp = 0; /* clean 0 */
return;
}
/* Round fp number, store, generate condition codes */
uint32 StoreFPR (struct ufp *fop, uint32 op, uint32 r1, uint32 rnd)
{
uint32 hi, cc;
if (rnd && (fop->l & FP_ROUND)) { /* round? */
fop->h = fop->h + 1; /* add 1 to frac */
if (fop->h & FP_CARRY) { /* carry out? */
fop->h = fop->h >> 4; /* renormalize */
fop->exp = fop->exp + 1; } } /* incr exp */
if (fop->h == 0) { /* result 0? */
hi = fop->l = 0; /* store clean 0 */
cc = 0; }
else if (fop->exp < 0) { /* underflow? */
hi = fop->l = 0; /* store clean 0 */
cc = CC_V; }
else if (fop->exp > FP_M_EXP) { /* overflow? */
hi = (fop->sign)? 0xFFFFFFFF: 0x7FFFFFFF;
fop->l = 0xFFFFFFFF;
cc = (CC_V | ((fop->sign)? CC_L: CC_G)); }
else { hi = ((fop->sign & FP_M_SIGN) << FP_V_SIGN) | /* pack result */
((fop->exp & FP_M_EXP) << FP_V_EXP) |
((fop->h & FP_M_FRH) << FP_V_FRH);
cc = (fop->sign)? CC_L: CC_G; } /* set cc's */
if (OP_DPFP (op)) { /* double precision? */
D[r1 >> 1].h = hi;
D[r1 >> 1].l = fop->l; }
else { WriteFReg (r1, hi); }
return cc;
}
/* Generate exception result */
uint32 StoreFPX (struct ufp *fop, uint32 op, uint32 r1)
{
uint32 cc = CC_V;
if (fop->exp < 0) fop->h = fop->l = 0; /* undf? clean 0 */
else { fop->h = (fop->sign)? 0xFFFFFFFF: 0x7FFFFFFF; /* overflow */
fop->l = 0xFFFFFFFF;
cc = cc | ((fop->sign)? CC_L: CC_G); }
if (OP_DPFP (op)) { /* double precision? */
D[r1 >> 1].h = fop->h;
D[r1 >> 1].l = fop->l; }
else { WriteFReg (r1, fop->h); }
return cc;
}

690
Interdata/id_idc.c Normal file
View file

@ -0,0 +1,690 @@
/* id_idc.c: Interdata MSM/IDC disk controller simulator
Copyright (c) 2001-2002, 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.
idc MSM/IDC disk controller
Note: define flag ID_IDC to enable the extra functions of the intelligent
disk controller
*/
#include "id_defs.h"
#define IDC_NUMBY 256 /* bytes/sector */
#define IDC_NUMSC 64 /* sectors/track */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
#define UNIT_M_DTYPE 0x7
#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
#define CYL u3 /* current cylinder */
#define HD u4 /* current head */
#define STD buf /* drive status */
#define FNC wait /* function */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
#define IDC_DRVMASK ((1 << ID_NUMDR) - 1) /* drive bit mask */
#define IDC_DIRMASK (IDC_DRVMASK << (i_IDC + 1)) /* drive irq mask */
/* Controller status */
#define STC_WRP 0x80 /* write protected */
#define STC_ACF 0x40 /* addr cmp fail */
#define STC_DEF 0x20 /* def track NI */
#define STC_CYO 0x10 /* cylinder ovflo */
#define STC_IDL 0x02 /* ctrl idle */
#define STC_DTE 0x01 /* xfer error */
#define SETC_EX (STC_WRP|STC_ACF|STC_DEF|STC_CYO)
#define STC_MASK (STC_WRP|STC_ACF|STC_DEF|STC_CYO|STA_BSY|STC_IDL|STC_DTE)
/* Controller command */
#define CMC_MASK 0x3F
#define CMC_CLR 0x08 /* reset */
#define CMC_RD 0x01 /* read */
#define CMC_WR 0x02 /* write */
#define CMC_RCHK 0x03 /* read check */
#define CMC_FCHK 0x04 /* format check NI */
#define CMC_RFMT 0x05 /* read fmt NI */
#define CMC_WFMT 0x06 /* write fmt NI */
#define CMC_WFTK 0x07 /* write fmt track NI */
/* IDC only functions */
#define CMC_RRAM 0x10 /* read RAM */
#define CMC_WRAM 0x11 /* write RAM */
#define CMC_EXP0 0x12 /* read page 0 NI */
#define CMC_RUNC 0x21 /* read uncorr */
#define CMC_STST 0x30 /* self test */
#define CMC_WLNG 0x32 /* write long NI */
#define CMC_LAMP 0x37 /* lamp test */
#define CMC_DRV 0x100 /* drive func */
#define CMC_DRV1 0x200 /* drive func, part 2 */
/* Drive status, ^ = dynamic, * = in unit status */
#define STD_WRP 0x80 /* ^write prot */
/* 0x40 /* unused */
#define STD_ACH 0x20 /* alt chan busy NI */
#define STD_UNS 0x10 /* *unsafe */
#define STD_NRDY 0x08 /* ^not ready */
#define STD_SKI 0x02 /* *seek incomplete */
#define STD_OFFL 0x01 /* ^offline */
#define STD_UST (STD_UNS | STD_SKI) /* set from unit */
#define SETD_EX (STD_WRP | STD_UNS) /* set examine */
/* Drive command */
#define CMDF_SHD 0x20 /* set head */
#define CMDF_SCY 0x10 /* set cylinder */
#define CMD_SK 0x02 /* seek */
#define CMD_RST 0x01 /* restore */
#define CMDX_MASK 0x30 /* ext cmd bits */
#define CMDX_RLS 0x80 /* release */
#define CMDX_CLF 0x40 /* clear fault */
#define CMDX_SVP 0x08 /* servo + */
#define CMDX_SVM 0x04 /* servo - */
#define CMDX_DSP 0x02 /* strobe + */
#define CMDX_DSM 0x01 /* strobe - */
/* Geometry masks */
#define CY_MASK 0xFFF /* cylinder */
#define HD_MASK 0x1F /* head mask */
#define SC_MASK 0x3F /* sector mask */
#define HCYL_V_HD 10 /* head/cyl word */
#define HCYL_V_CYL 0
#define GET_SA(cy,sf,sc,t) (((((cy)*drv_tab[t].surf)+(sf))* \
IDC_NUMSC)+(sc))
/* The MSM (IDC) controller supports (two) six different disk drive types:
type #sectors/ #surfaces/ #cylinders/
surface cylinder drive
MCCDD16 64 1 823 IDC
MCCDD48 64 3 823 IDC
MCCDD80 64 5 823 IDC
MSM80 64 5 823 MSM
MSM300 64 19 823 MSM
MSM330F 64 16 1024 IDC
In theory, each drive can be a different type. The size field in
each unit selects the drive capacity for each drive and thus the
drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE AND MUST HAVE
THE SAME SECTORS/TRACK.
*/
#define TYPE_MCCDD16 0
#define SURF_MCCDD16 1
#define CYL_MCCDD16 823
#define SIZE_MCCDD16 (IDC_NUMSC * SURF_MCCDD16 * CYL_MCCDD16 * IDC_NUMBY)
#define TYPE_MCCDD48 1
#define SURF_MCCDD48 3
#define CYL_MCCDD48 823
#define SIZE_MCCDD48 (IDC_NUMSC * SURF_MCCDD48 * CYL_MCCDD48 * IDC_NUMBY)
#define TYPE_MCCDD80 2
#define SURF_MCCDD80 5
#define CYL_MCCDD80 823
#define SIZE_MCCDD80 (IDC_NUMSC * SURF_MCCDD80 * CYL_MCCDD80 * IDC_NUMBY)
#define TYPE_MSM80 3
#define SURF_MSM80 5
#define CYL_MSM80 823
#define SIZE_MSM80 (IDC_NUMSC * SURF_MSM80 * CYL_MSM80 * IDC_NUMBY)
#define TYPE_MSM300 4
#define SURF_MSM300 19
#define CYL_MSM300 823
#define SIZE_MSM300 (IDC_NUMSC * SURF_MSM300 * CYL_MSM300 * IDC_NUMBY)
#define TYPE_MSM330F 5
#define SURF_MSM330F 16
#define CYL_MSM330F 1024
#define SIZE_MSM330F (IDC_NUMSC * SURF_MSM330F * CYL_MSM330F * IDC_NUMBY)
struct drvtyp {
uint32 surf; /* surfaces */
uint32 cyl; /* cylinders */
uint32 size; /* #blocks */
uint32 msmf; /* MSM drive */
};
static struct drvtyp drv_tab[] = {
{ SURF_MCCDD16, CYL_MCCDD16, SIZE_MCCDD16, 0 },
{ SURF_MCCDD48, CYL_MCCDD48, SIZE_MCCDD48, 0 },
{ SURF_MCCDD80, CYL_MCCDD80, SIZE_MCCDD80, 0 },
{ SURF_MSM80, CYL_MSM80, SIZE_MSM80, 1 },
{ SURF_MSM300, CYL_MSM300, SIZE_MSM300, 1 },
{ SURF_MSM330F, CYL_MSM330F, SIZE_MSM330F, 0 },
{ 0 } };
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint8 idcxb[IDC_NUMBY * 3]; /* xfer buffer */
uint32 idc_bptr = 0; /* buffer ptr */
uint32 idc_db = 0; /* ctrl buffer */
uint32 idd_db = 0; /* drive buffer */
uint32 idc_sta = 0; /* ctrl status */
uint32 idc_sec = 0; /* sector */
uint32 idc_hcyl = 0; /* head/cyl */
uint32 idc_svun = 0; /* most recent unit */
uint32 idc_1st = 0; /* first byte */
uint32 idc_arm = 0; /* ctrl armed */
uint32 idd_arm[ID_NUMDR] = { 0 }; /* drives armed */
uint16 idd_dcy[ID_NUMDR] = { 0 }; /* desired cyl */
uint32 idd_sirq = 0; /* drive saved irq */
int32 idc_stime = 100; /* seek latency */
int32 idc_rtime = 100; /* rotate latency */
int32 idc_ctime = 5; /* command latency */
uint8 idc_tplte[] = { 0, 1, 2, 3, 4, TPL_END }; /* ctrl + drive */
DEVICE idc_dev;
uint32 id (uint32 dev, uint32 op, uint32 dat);
t_stat idc_svc (UNIT *uptr);
t_stat idc_reset (DEVICE *dptr);
t_stat idc_attach (UNIT *uptr, char *cptr);
t_stat idc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat idc_rds (UNIT *uptr);
t_stat idc_wds (UNIT *uptr);
t_bool idc_dter (UNIT *uptr, uint32 first);
void idc_done (uint32 flg);
extern t_stat id_dboot (int32 u, DEVICE *dptr);
/* DP data structures
idc_dev DP device descriptor
idc_unit DP unit list
idc_reg DP register list
idc_mod DP modifier list
*/
DIB idc_dib = { d_IDC, 0, v_IDC, idc_tplte, &id, NULL };
UNIT idc_unit[] = {
{ UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) },
{ UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) },
{ UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) },
{ UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) } };
REG idc_reg[] = {
{ HRDATA (STA, idc_sta, 8) },
{ HRDATA (BUF, idc_db, 8) },
{ HRDATA (SEC, idc_sec, 8) },
{ HRDATA (HCYL, idc_hcyl, 16) },
{ HRDATA (BUF, idd_db, 8) },
{ HRDATA (SVUN, idc_svun, 2), REG_HIDDEN },
{ BRDATA (DBUF, idcxb, 16, 8, IDC_NUMBY * 3) },
{ HRDATA (DBPTR, idc_bptr, 10), REG_RO },
{ FLDATA (FIRST, idc_1st, 0) },
{ GRDATA (IREQ, int_req[l_IDC], 16, ID_NUMDR + 1, i_IDC) },
{ GRDATA (IENB, int_enb[l_IDC], 16, ID_NUMDR + 1, i_IDC) },
{ GRDATA (SIREQ, idd_sirq, 16, ID_NUMDR, i_IDC + 1), REG_RO },
{ FLDATA (ICARM, idc_arm, 0) },
{ BRDATA (IDARM, idd_arm, 16, 1, ID_NUMDR) },
{ DRDATA (RTIME, idc_rtime, 24), PV_LEFT | REG_NZ },
{ DRDATA (STIME, idc_stime, 24), PV_LEFT | REG_NZ },
{ DRDATA (CTIME, idc_ctime, 24), PV_LEFT | REG_NZ },
{ BRDATA (CYL, idd_dcy, 16, 16, ID_NUMDR) },
{ URDATA (UCYL, idc_unit[0].CYL, 16, 12, 0,
ID_NUMDR, REG_RO) },
{ URDATA (UHD, idc_unit[0].HD, 16, 5, 0,
ID_NUMDR, REG_RO) },
{ URDATA (UFNC, idc_unit[0].FNC, 16, 10, 0,
ID_NUMDR, REG_HRO) },
{ URDATA (UST, idc_unit[0].STD, 16, 8, 0,
ID_NUMDR, REG_RO) },
{ URDATA (CAPAC, idc_unit[0].capac, 10, 31, 0,
ID_NUMDR, PV_LEFT | REG_HRO) },
{ HRDATA (DEVNO, idc_dib.dno, 8), REG_HRO },
{ HRDATA (SELCH, idc_dib.sch, 2), REG_HRO },
{ BRDATA (TPLTE, idc_tplte, 16, 8, ID_NUMDR + 1), REG_HRO },
{ NULL } };
MTAB idc_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD16 << UNIT_V_DTYPE) + UNIT_ATT,
"MCCDD16", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD48 << UNIT_V_DTYPE) + UNIT_ATT,
"MCCDD48", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD80 << UNIT_V_DTYPE) + UNIT_ATT,
"MCCDD80", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_MSM330F << UNIT_V_DTYPE) + UNIT_ATT,
"MSM330F", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD16 << UNIT_V_DTYPE),
"MCCDD16", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD48 << UNIT_V_DTYPE),
"MCCDD48", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD80 << UNIT_V_DTYPE),
"MCCDD80", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MSM330F << UNIT_V_DTYPE),
"MSM330F", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_MCCDD16 << UNIT_V_DTYPE),
NULL, "MCCDD16", &idc_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_MCCDD48 << UNIT_V_DTYPE),
NULL, "MCCDD48", &idc_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_MCCDD80 << UNIT_V_DTYPE),
NULL, "MCCDD80", &idc_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_MSM330F << UNIT_V_DTYPE),
NULL, "MSM330F", &idc_set_size },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_MSM80 << UNIT_V_DTYPE) + UNIT_ATT,
"MSM80", NULL, NULL },
{ (UNIT_DTYPE+UNIT_ATT), (TYPE_MSM300 << UNIT_V_DTYPE) + UNIT_ATT,
"MSM300", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MSM80 << UNIT_V_DTYPE),
"MSM80", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MSM300 << UNIT_V_DTYPE),
"MSM300", NULL, NULL },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_MSM80 << UNIT_V_DTYPE),
NULL, "MSM80", &idc_set_size },
{ (UNIT_AUTO+UNIT_DTYPE), (TYPE_MSM300 << UNIT_V_DTYPE),
NULL, "MSM300", &idc_set_size },
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH",
&set_sch, &show_sch, NULL },
{ 0 } };
DEVICE idc_dev = {
"DM", idc_unit, idc_reg, idc_mod,
ID_NUMDR, 16, 29, 1, 16, 8,
NULL, NULL, &idc_reset,
&id_dboot, &idc_attach, NULL,
&idc_dib, DEV_DISABLE };
/* Controller: IO routine */
uint32 idc (uint32 dev, uint32 op, uint32 dat)
{
uint32 f, t;
UNIT *uptr;
switch (op) { /* case IO op */
case IO_ADR: /* select */
sch_adr (idc_dib.sch, dev); /* inform sel ch */
return HW; /* halfwords */
case IO_RD: /* read data */
case IO_RH: /* read halfword */
return 0; /* return data */
case IO_WD: /* write data */
idc_sec = dat; /* sector */
break;
case IO_WH: /* write halfword */
idc_hcyl = dat; /* head/cylinder */
break;
case IO_SS: /* status */
t = idc_sta & STC_MASK; /* get status */
if (t & SETC_EX) t = t | STA_EX; /* test for EX */
return t;
case IO_OC: /* command */
idc_arm = int_chg (v_IDC, dat, idc_arm); /* upd int ctrl */
f = dat & CMC_MASK; /* get cmd */
uptr = idc_dev.units + idc_svun; /* get unit */
if (f & CMC_CLR) { /* clear? */
idc_reset (&idc_dev); /* reset world */
break; }
if (!(idc_sta & STC_IDL) || /* if !idle, */
sim_is_active (uptr) || /* unit busy, */
(f == CMC_EXP0)) break; /* expg, ignore */
idc_sta = STA_BSY; /* bsy=1,idl,err=0 */
idc_1st = 1; /* xfr not started */
idc_bptr = 0; /* buffer empty */
uptr->FNC = f; /* save cmd */
sim_activate (uptr, idc_rtime); /* schedule */
idd_sirq = int_req[l_IDC] & IDC_DIRMASK; /* save drv ints */
int_req[l_IDC] = int_req[l_IDC] & ~IDC_DIRMASK; /* clr drv ints */
break; }
return 0;
}
/* Drives: IO routine */
uint32 id (uint32 dev, uint32 op, uint32 dat)
{
uint32 t, u;
UNIT *uptr;
if (dev == idc_dib.dno) return idc (dev, op, dat); /* controller? */
u = (dev - idc_dib.dno - o_ID0) / o_ID0; /* get unit num */
uptr = idc_dev.units + u; /* get unit ptr */
switch (op) { /* case IO op */
case IO_ADR: /* select */
if (idc_sta & STC_IDL) idc_svun = u; /* idle? save unit */
return HW; /* byte only */
case IO_RD: /* read data */
case IO_RH:
return 0;
case IO_WD: /* write data */
case IO_WH: /* write halfword */
idd_db = dat; /* save data */
break;
case IO_SS: /* status */
if (uptr->flags & UNIT_ATT) t =
((uptr->flags & UNIT_WPRT)? STD_WRP: 0) |
(sim_is_active (uptr)? STD_NRDY: 0) |
(uptr->STD & STD_UST);
else t = STD_NRDY | STD_OFFL; /* off = X'09' */
if (t & SETD_EX) t = t | STA_EX; /* test for ex */
return t;
case IO_OC: /* command */
idd_arm[u] = int_chg (v_IDC + u + 1, dat, idd_arm[u]);
if (idd_arm[u] == 0) /* disarmed? */
idd_sirq &= ~(1 << (v_IDC + u + 1)); /* clr saved req */
if (sim_is_active (uptr) || /* if busy or */
!(idc_sta & STC_IDL)) break; /* !idle, ignore */
if ((dat & CMC_MASK) == CMDX_MASK) break; /* ignore 0x30 */
uptr->FNC = (dat & CMC_MASK) | CMC_DRV; /* save cmd */
idc_sta = idc_sta & ~STC_IDL; /* clr idle */
sim_activate (uptr, idc_ctime); /* schedule */
break; }
return 0;
}
/* Unit service
If drive command, process; if an interrupt is needed (positioning
command), schedule second part
If data transfer command, process; must use selector channel
*/
t_stat idc_svc (UNIT *uptr)
{
int32 diff;
uint32 f, u = uptr - idc_dev.units; /* get unit number */
uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */
uint32 t;
t_stat r;
if (uptr->FNC & CMC_DRV) { /* drive cmd? */
f = uptr->FNC & CMC_MASK; /* get cmd */
if (uptr->FNC & CMC_DRV1) { /* part 2? */
if (idd_arm[u]) { /* drv int armed? */
if (idc_sta & STC_IDL) /* ctrl idle? */
SET_INT (v_IDC + u + 1); /* req intr */
else idd_sirq |= (1 << (v_IDC + u + 1)); } /* def intr */
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK;
if (((f & CMDX_MASK) == 0) && /* seek? */
(f & (CMD_SK | CMD_RST))) {
if (idd_dcy[u] >= drv_tab[dtype].cyl) /* bad cylinder? */
uptr->STD = uptr->STD | STD_SKI; /* error */
uptr->CYL = idd_dcy[u]; } /* put on cyl */
} /* end if p2 */
else { /* part 1 */
idc_sta = idc_sta | STC_IDL; /* set idle */
uptr->FNC = uptr->FNC | CMC_DRV1; /* set part 2 */
if (f >= CMDX_MASK) { /* extended? */
if (f & CMDX_CLF) /* clr fault? */
uptr->STD = uptr->STD & ~STD_UNS; /* clr unsafe */
if (f & (CMDX_RLS | CMDX_SVP | CMDX_SVM)) /* intr expected? */
sim_activate (uptr, idc_ctime); }
else if (f >= CMDF_SCY) { /* tag? */
if (f & CMDF_SHD) uptr->HD = idd_db & HD_MASK;
else if (f & CMDF_SCY) {
if (idd_db >= drv_tab[dtype].cyl) /* bad cylinder? */
uptr->STD = uptr->STD | STD_SKI; /* set seek inc */
idd_dcy[u] = idd_db & CY_MASK; } }
else if (f & (CMD_SK | CMD_RST)) { /* seek? */
if (f == CMD_RST) idd_dcy[u] = 0; /* restore? */
if (idd_dcy[u] >= drv_tab[dtype].cyl) { /* bad cylinder? */
uptr->STD = uptr->STD | STD_SKI; /* set seek inc */
idd_dcy[u] = uptr->CYL; /* no motion */
sim_activate (uptr, 0); } /* finish asap */
else { /* cylinder ok */
uptr->STD = uptr->STD & ~STD_SKI; /* clr seek inc */
diff = idd_dcy[u] - uptr->CYL;
if (diff < 0) diff = -diff; /* ABS cyl diff */
else if (diff == 0) diff = 1; /* must be nz */
sim_activate (uptr, diff * idc_stime); } }
} /* end else p1 */
return SCPE_OK; } /* end if drv */
switch (uptr->FNC & CMC_MASK) { /* case on func */
case CMC_RCHK: /* read check */
idc_dter (uptr, 1); /* check xfr err */
break;
#if defined (ID_IDC)
case CMC_RUNC: /* read uncorr */
#endif
case CMC_RD: /* read */
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */
if (idc_dter (uptr, idc_1st)) return SCPE_OK; /* dte? done */
/* fseek done */
if (r = idc_rds (uptr)) return r; /* read sec, err? */
idc_1st = 0;
t = sch_wrmem (idc_dib.sch, idcxb, IDC_NUMBY); /* write mem */
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */
sim_activate (uptr, idc_rtime); /* reschedule */
return SCPE_OK; }
break; } /* no, set done */
idc_sta = idc_sta | STC_DTE; /* cant work */
break;
case CMC_WR: /* write */
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */
idc_bptr = sch_rdmem (idc_dib.sch, idcxb, IDC_NUMBY); /* read mem */
idc_db = idcxb[idc_bptr - 1]; /* last byte */
if (idc_dter (uptr, idc_1st)) return SCPE_OK; /* dte? done */
if (r = idc_wds (uptr)) return r; /* write sec, err? */
idc_1st = 0;
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */
sim_activate (uptr, idc_rtime); /* reschedule */
return SCPE_OK; }
break; } /* no, set done */
idc_sta = idc_sta | STC_DTE; /* cant work */
break;
case CMC_FCHK: case CMC_RFMT: case CMC_WFMT: case CMC_WFTK:
idc_dter (uptr, 1);
idc_sta = idc_sta | STC_WRP;
break;
#if defined (ID_IDC)
case CMC_RRAM: /* read RAM */
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */
sch_wrmem (idc_dib.sch, idcxb, IDC_NUMBY * 3);
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */
sim_activate (uptr, idc_rtime); /* reschedule */
return SCPE_OK; }
break; } /* no, set done */
idc_sta = idc_sta | STC_DTE; /* cant work */
break;
case CMC_WRAM: /* write RAM */
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */
sch_rdmem (idc_dib.sch, idcxb, IDC_NUMBY * 3); /* read from mem */
if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */
sim_activate (uptr, idc_rtime); /* reschedule */
return SCPE_OK; }
break; } /* no, set done */
idc_sta = idc_sta | STC_DTE; /* cant work */
break;
case CMC_STST: case CMC_LAMP: /* tests */
break;
#endif
default:
idc_sta = idc_sta | STC_DTE;
break; }
idc_done (0); /* done */
return SCPE_OK;
}
/* Read data sector */
t_stat idc_rds (UNIT *uptr)
{
uint32 i;
i = fxread (idcxb, sizeof (uint8), IDC_NUMBY, uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */
perror ("IDC I/O error");
clearerr (uptr->fileref);
idc_done (STC_DTE);
return SCPE_IOERR; }
for ( ; i < IDC_NUMBY; i++) idcxb[i] = 0; /* fill with 0's */
return SCPE_OK;
}
/* Write data sector */
t_bool idc_wds (UNIT *uptr)
{
for ( ; idc_bptr < IDC_NUMBY; idc_bptr++)
idcxb[idc_bptr] = idc_db; /* fill with last */
fxwrite (idcxb, sizeof (uint8), IDC_NUMBY, uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */
perror ("IDC I/O error");
clearerr (uptr->fileref);
idc_done (STC_DTE);
return SCPE_IOERR; }
return FALSE;
}
/* Data transfer error test routine */
t_bool idc_dter (UNIT *uptr, uint32 first)
{
uint32 cy;
uint32 hd, sc, sa;
uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
idc_done (STC_DTE); /* error, done */
return TRUE; }
if ((uptr->flags & UNIT_WPRT) && (uptr->FNC == CMC_WR)) {
idc_done (STC_WRP); /* error, done */
return TRUE; }
cy = uptr->CYL; /* get cylinder */
hd = uptr->HD; /* get head */
sc = idc_sec & SC_MASK; /* get sector */
if (cy >= drv_tab[dtype].cyl) { /* bad cylinder? */
uptr->STD = uptr->STD | STD_SKI; /* error */
idc_done (STC_DTE); /* error, done */
return TRUE; }
if (hd >= drv_tab[dtype].surf) { /* bad head? */
if (first) { /* 1st xfer? */
uptr->STD = uptr->STD | STD_UNS; /* drive unsafe */
idc_done (STC_ACF); }
else idc_done (STC_CYO); /* no, cyl ovf */
return TRUE; }
sa = GET_SA (cy, hd, sc, dtype); /* curr disk addr */
fseek (uptr->fileref, sa * IDC_NUMBY, SEEK_SET); /* seek to pos */
idc_sec = (idc_sec + 1) & SC_MASK; /* incr disk addr */
if (idc_sec == 0) uptr->HD = uptr->HD + 1;
return FALSE;
}
/* Data transfer done routine */
void idc_done (uint32 flg)
{
idc_sta = (idc_sta | STC_IDL | flg) & ~STA_BSY; /* set flag, idle */
if (idc_arm) SET_INT (v_IDC); /* if armed, intr */
int_req[l_IDC] = int_req[l_IDC] | idd_sirq; /* restore drv ints */
idd_sirq = 0; /* clear saved */
if (flg) sch_stop (idc_dib.sch); /* if err, stop sch */
return;
}
/* Reset routine */
t_stat idc_reset (DEVICE *dptr)
{
uint32 u;
UNIT *uptr;
idc_sta = STC_IDL | STA_BSY; /* idle, busy */
idc_1st = 0; /* clear flag */
idc_svun = idc_db = 0; /* clear unit, buf */
idc_sec = 0; /* clear addr */
idc_hcyl = 0;
CLR_INT (v_IDC); /* clear ctrl int */
CLR_ENB (v_IDC); /* clear ctrl enb */
idc_arm = 0; /* clear ctrl arm */
idd_sirq = 0;
for (u = 0; u < ID_NUMDR; u++) { /* loop thru units */
uptr = idc_dev.units + u;
uptr->CYL = uptr->STD = 0;
uptr->HD = uptr->FNC = 0;
idd_dcy[u] = 0;
CLR_INT (v_IDC + u + 1); /* clear intr */
CLR_ENB (v_IDC + u + 1); /* clear enable */
idd_arm[u] = 0; /* clear arm */
sim_cancel (uptr); } /* cancel activity */
return SCPE_OK;
}
/* Attach routine (with optional autosizing) */
t_stat idc_attach (UNIT *uptr, char *cptr)
{
uint32 i, p;
t_stat r;
uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;
r = attach_unit (uptr, cptr);
uptr->CYL = 0;
if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r;
if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK;
if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK;
for (i = 0; drv_tab[i].surf != 0; i++) {
if (p <= drv_tab[i].size) {
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
uptr->capac = drv_tab[i].size;
return SCPE_OK; } }
return SCPE_OK;
}
/* Set size command validation routine */
t_stat idc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = drv_tab[GET_DTYPE (val)].size;
return SCPE_OK;
}

542
Interdata/id_io.c Normal file
View file

@ -0,0 +1,542 @@
/* id_io.c: Interdata CPU-independent I/O routines
Copyright (c) 2001-2002, 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.
Interdata I/O devices are defined by a device information block:
dno base device number
sch selector channel, -1 if none
irq interrupt request flag
tplte device number template, NULL if one device number
iot I/O processing routine
ini initialization routine
Interdata I/O uses the following interconnected tables:
dev_tab[dev] Indexed by device number, points to the I/O instruction
processing routine for the device. Initialized in the
device reset routine.
sch_tab[dev] Indexed by device number, if non-zero, the number + 1
of the selector channel used by the device.
int_req[level] Indexed by interrupt level, device interrupt flags.
int_enb[level] Indexed by interrupt level, device interrupt enable flags.
int_tab[idx] Indexed by ((interrupt level * 32) + interrupt number),
maps bit positions in int_req to device numbers.
*/
#include "id_defs.h"
/* Selector channel */
#define SCHC_EXA 0x40 /* read ext addr */
#define SCHC_RD 0x20 /* read */
#define SCHC_GO 0x10 /* go */
#define SCHC_STOP 0x08 /* stop */
#define SCHC_SSTA 0x04 /* sel ch status */
#define SCHC_EXM 0x03 /* ext mem */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
extern uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout);
extern uint32 pawidth;
extern UNIT cpu_unit;
extern FILE *sim_log;
extern DEVICE *sim_devices[];
uint32 sch_max = 2; /* sch count */
uint32 sch_sa[SCH_NUMCH] = { 0 }; /* start addr */
uint32 sch_ea[SCH_NUMCH] = { 0 }; /* end addr */
uint8 sch_sdv[SCH_NUMCH] = { 0 }; /* device */
uint8 sch_cmd[SCH_NUMCH] = { 0 }; /* command */
uint8 sch_rdp[SCH_NUMCH] = { 0 }; /* read ptr */
uint8 sch_wdc[SCH_NUMCH] = { 0 }; /* write ctr */
uint32 sch_tab[DEVNO] = { 0 }; /* dev to sch map */
uint32 int_tab[INTSZ * 32] = { 0 }; /* int to dev map */
uint8 sch_tplte[SCH_NUMCH + 1]; /* dnum template */
uint32 sch (uint32 dev, uint32 op, uint32 dat);
void sch_ini (t_bool dtpl);
t_stat sch_reset (DEVICE *dptr);
t_stat sch_vchan (UNIT *uptr, int32 val, char *cptr, void *desc);
/* Selector channel data structures
sch_dev channel device descriptor
sch_unit channel unit descriptor
sch_mod channel modifiers list
sch_reg channel register list
*/
DIB sch_dib = { d_SCH, -1, v_SCH, sch_tplte, &sch, &sch_ini };
UNIT sch_unit = { UDATA (NULL, 0, 0) };
REG sch_reg[] = {
{ HRDATA (CHAN, sch_max, 3), REG_HRO },
{ BRDATA (SA, sch_sa, 16, 20, SCH_NUMCH) },
{ BRDATA (EA, sch_ea, 16, 20, SCH_NUMCH) },
{ BRDATA (CMD, sch_cmd, 16, 8, SCH_NUMCH) },
{ BRDATA (DEV, sch_sdv, 16, 8, SCH_NUMCH) },
{ BRDATA (RDP, sch_rdp, 16, 2, SCH_NUMCH) },
{ BRDATA (WDC, sch_wdc, 16, 3, SCH_NUMCH) },
{ GRDATA (IREQ, int_req[l_SCH], 16, SCH_NUMCH, i_SCH) },
{ GRDATA (IENB, int_enb[l_SCH], 16, SCH_NUMCH, i_SCH) },
{ HRDATA (DEVNO, sch_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB sch_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_VAL, 0, "channels", "CHANNELS",
&sch_vchan, NULL, &sch_reg[0] },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, &sch_dib },
{ 0 } };
DEVICE sch_dev = {
"SELCH", &sch_unit, sch_reg, sch_mod,
1, 16, 8, 1, 16, 8,
NULL, NULL, &sch_reset,
NULL, NULL, NULL,
&sch_dib, 0 };
/* (Extended) selector channel
There are really three different selector channels:
- 16b selector channel (max 4B of data)
- 18b selector channel (max 4B of data)
- 20b selector channel (max 6B of data)
The algorithm for loading the start and end addresses is taken
from the maintenance manual for the Extended Selector Channel.
*/
#define SCH_EXR(ch) ((sch_cmd[ch] & SCHC_EXA) && (pawidth == PAWIDTH32))
uint32 sch (uint32 dev, uint32 op, uint32 dat)
{
uint32 t, bank, sdv, ch = dev - sch_dib.dno;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_RD: /* read data */
t = (sch_sa[ch] >> (sch_rdp[ch] * 8)) & DMASK8; /* get sa byte */
if (sch_rdp[ch] == 0) sch_rdp[ch] = /* wrap? */
SCH_EXR (ch)? 2: 1;
else sch_rdp[ch] = sch_rdp[ch] - 1; /* dec byte ptr */
return t;
case IO_WD: /* write data */
if (pawidth != PAWIDTH32) { /* 16b? max 4 */
if (sch_wdc[ch] >= 4) break; /* stop at 4 */
sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea to sa */
(sch_ea[ch] >> 8)) & DMASK16;
sch_ea[ch] = ((sch_ea[ch] << 8) | /* ripple ea low */
dat) & DMASK16; } /* insert byte */
else { /* 32b? max 6 */
if (sch_wdc[ch] >= 6) break; /* stop at 6 */
if (sch_wdc[ch] != 5) { /* if not last */
sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea<15:8> to sa */
((sch_ea[ch] >> 8) & DMASK8)) & PAMASK32;
sch_ea[ch] = /* ripple ea<7:0> */
(((sch_ea[ch] & DMASK8) << 8) | dat) & PAMASK32; }
else sch_ea[ch] = ((sch_ea[ch] << 8) | dat) & PAMASK32; }
sch_wdc[ch] = sch_wdc[ch] + 1; /* adv sequencer */
break;
case IO_SS: /* status */
if (sch_cmd[ch] & SCHC_GO) return STA_BSY; /* test busy */
if (sch_cmd[ch] & SCHC_SSTA) return 0; /* test sch sta */
else {
sdv = sch_sdv[ch]; /* get dev */
if (dev_tab[sdv] == 0) return CC_V; /* not there? */
dev_tab[sdv] (sdv, IO_ADR, 0); /* select dev */
t = dev_tab[sdv] (sdv, IO_SS, 0); /* get status */
return t & ~STA_BSY; } /* clr busy */
case IO_OC: /* command */
bank = 0; /* assume no bank */
if (pawidth != PAWIDTH32) { /* 16b/18b proc? */
dat = dat & ~(SCHC_EXA | SCHC_SSTA); /* clr ext func */
if (pawidth == PAWIDTH16E) /* 18b proc? */
bank = (dat & SCHC_EXM) << 16; }
if (dat & SCHC_STOP) { /* stop? */
sch_cmd[ch] = dat & (SCHC_EXA | SCHC_SSTA); /* clr go */
CLR_INT (v_SCH + ch); /* clr intr */
sch_rdp[ch] = SCH_EXR (ch)? 2: 1; /* init sequencers */
sch_wdc[ch] = 0; }
else if (dat & SCHC_GO) { /* go? */
sch_cmd[ch] = dat & (SCHC_GO | SCHC_RD);
if (sch_wdc[ch] <= 4) { /* 4 bytes? */
sch_sa[ch] = (sch_sa[ch] & PAMASK16) | bank; /* 16b addr */
sch_ea[ch] = (sch_ea[ch] & PAMASK16) | bank; }
sch_sa[ch] = sch_sa[ch] & ~1;
if (sch_ea[ch] <= sch_sa[ch]) /* wrap? */
sch_ea[ch] = sch_ea[ch] | /* modify end addr */
((pawidth == PAWIDTH32)? PAMASK32: PAMASK16); }
break; }
return 0;
}
/* CPU call to test if channel blocks access to device */
t_bool sch_blk (uint32 dev)
{
uint32 ch = sch_tab[dev] - 1;
if ((ch < sch_max) && (sch_cmd[ch] & SCHC_GO)) return TRUE;
return FALSE;
}
/* Device call to 'remember' last dev on channel */
void sch_adr (uint32 ch, uint32 dev)
{
if (ch < sch_max) sch_sdv[ch] = dev;
return;
}
/* Device call to see if selector channel is active for device */
t_bool sch_actv (uint32 ch, uint32 dev)
{
if ((ch < sch_max) && /* chan valid, */
(sch_cmd[ch] & SCHC_GO) && /* on, and */
(sch_sdv[ch] == dev)) return TRUE; /* set for dev? */
return FALSE; /* no */
}
/* Device call to read a block of memory */
uint32 sch_rdmem (uint32 ch, uint8 *buf, uint32 cnt)
{
uint32 addr, end, xfr, inc;
if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0)) return 0;
addr = sch_sa[ch]; /* start */
end = sch_ea[ch]; /* end */
xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */
inc = IOReadBlk (addr, xfr, buf); /* read mem */
if ((addr + inc) > end) { /* end? */
SET_INT (v_SCH + ch); /* interrupt */
sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */
sch_sa[ch] = sch_sa[ch] + inc - 1; } /* end addr */
else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */
return inc;
}
/* Device call to write a block of memory */
uint32 sch_wrmem (uint32 ch, uint8 *buf, uint32 cnt)
{
uint32 addr, end, xfr, inc;
if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0)) return 0;
addr = sch_sa[ch]; /* start */
end = sch_ea[ch]; /* end */
xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */
inc = IOWriteBlk (addr, xfr, buf); /* write mem */
if ((addr + inc) > end) { /* end? */
SET_INT (v_SCH + ch); /* interrupt */
sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */
sch_sa[ch] = sch_sa[ch] + inc - 1; } /* end addr */
else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */
return inc;
}
/* Device call to stop a selector channel */
void sch_stop (uint32 ch)
{
if (ch < sch_max) {
SET_INT (v_SCH + ch); /* interrupt */
sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); } /* clear GO */
return;
}
/* Reset */
void sch_reset_ch (uint32 rst_lim)
{
uint32 ch;
for (ch = 0; ch < SCH_NUMCH; ch++) {
if (ch >= rst_lim) {
CLR_INT (v_SCH + ch);
SET_ENB (v_SCH + ch);
sch_sa[ch] = sch_ea[ch] = 0;
sch_cmd[ch] = sch_sdv[ch] = 0;
sch_wdc[ch] = 0;
sch_rdp[ch] = 1; } }
return;
}
t_stat sch_reset (DEVICE *dptr)
{
sch_reset_ch (0); /* reset all chan */
return SCPE_OK;
}
/* Set number of channels */
t_stat sch_vchan (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 i, newmax;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
newmax = get_uint (cptr, 10, SCH_NUMCH, &r); /* get new max */
if ((r != SCPE_OK) || (newmax == sch_max)) return r; /* err or no chg? */
if (newmax == 0) return SCPE_ARG; /* must be > 0 */
if (newmax < sch_max) { /* reducing? */
for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && (dibp->sch >= (int32) newmax)) {/* dev using chan? */
printf ("Device %02X uses channel %d\n",
dibp->dno, dibp->sch);
if (sim_log) fprintf (sim_log, "Device %02X uses channel %d\n",
dibp->dno, dibp->sch);
return SCPE_OK; } } }
sch_max = newmax; /* set new max */
sch_reset_ch (sch_max); /* reset chan */
return SCPE_OK;
}
/* Initialize template */
void sch_ini (t_bool dtpl)
{
uint32 i;
for (i = 0; i < sch_max; i++) sch_tplte[i] = i;
sch_tplte[sch_max] = TPL_END;
return;
}
/* Evaluate interrupt */
void int_eval (void)
{
int i;
extern uint32 qevent;
for (i = 0; i < INTSZ; i++)
if (int_req[i] & int_enb[i]) {
qevent = qevent | EV_INT;
return; }
qevent = qevent & ~EV_INT;
return;
}
/* Return interrupting device */
uint32 int_getdev (void)
{
int32 i, j, t;
uint32 r;
for (i = t = 0; i < INTSZ; i++) { /* loop thru array */
if (r = int_req[i] & int_enb[i]) { /* find nz int wd */
for (j = 0; j < 32; t++, j++) {
if (r & (1u << j)) {
int_req[i] = int_req[i] & ~(1u << j); /* clr request */
return int_tab[t]; } } }
else t = t + 32; }
return 0;
}
/* Update device interrupt status */
int32 int_chg (uint32 irq, int32 dat, int32 arm)
{
int32 t = CMD_GETINT (dat); /* get int ctrl */
if (t == CMD_IENB) { /* enable? */
SET_ENB (irq);
return 1; }
else if (t == CMD_IDIS) { /* disable? */
CLR_ENB (irq);
return 1; }
if (t == CMD_IDSA) { /* disarm? */
CLR_ENB (irq);
CLR_INT (irq);
return 0; }
return arm;
}
/* Process a 2b field and return unchanged, set, clear, complement */
int32 io_2b (int32 val, int32 pos, int32 old)
{
int32 t = (val >> pos) & 3;
if (t == 0) return old;
if (t == 1) return 1;
if (t == 2) return 0;
return old ^1;
}
/* Block transfer routines */
uint32 IOReadBlk (uint32 loc, uint32 cnt, uint8 *buf)
{
uint32 i;
if (!MEM_ADDR_OK (loc) || (cnt == 0)) return 0;
if (!MEM_ADDR_OK (loc + cnt - 1)) cnt = MEMSIZE - loc;
for (i = 0; i < cnt; i++) buf[i] = IOReadB (loc + i);
return cnt;
}
uint32 IOWriteBlk (uint32 loc, uint32 cnt, uint8 *buf)
{
uint32 i;
if (!MEM_ADDR_OK (loc) || (cnt == 0)) return 0;
if (!MEM_ADDR_OK (loc + cnt - 1)) cnt = MEMSIZE - loc;
for (i = 0; i < cnt; i++) IOWriteB (loc + i, buf[i]);
return cnt;
}
/* Change selector channel for a device */
t_stat set_sch (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newch;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if ((dibp == NULL) || (dibp->sch < 0)) return SCPE_IERR;
newch = get_uint (cptr, 16, sch_max - 1, &r); /* get new */
if (r != SCPE_OK) return r;
dibp->sch = newch; /* store */
return SCPE_OK;
}
/* Show selector channel for a device */
t_stat show_sch (FILE *st, UNIT *uptr, int32 val, void *desc)
{
DEVICE *dptr;
DIB *dibp;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if ((dibp == NULL) || (dibp->sch < 0)) return SCPE_IERR;
fprintf (st, "selch=%X", dibp->sch);
return SCPE_OK;
}
/* Change device number for a device */
t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newdev;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
newdev = get_uint (cptr, 16, DEV_MAX, &r); /* get new */
if ((r != SCPE_OK) || (newdev == dibp->dno)) return r;
if (newdev == 0) return SCPE_ARG; /* must be > 0 */
dibp->dno = newdev; /* store */
return SCPE_OK;
}
/* Show device number for a device */
t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc)
{
DEVICE *dptr;
DIB *dibp;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if ((dibp == NULL) || (dibp->dno == 0)) return SCPE_IERR;
fprintf (st, "devno=%02X", dibp->dno);
return SCPE_OK;
}
/* Init device tables */
t_bool devtab_init (void)
{
DEVICE *dptr;
DIB *dibp;
uint32 i, j, dno, dmsk, doff, t, dmap[DEVNO / 32];
uint8 *tplte, dflt_tplte[] = { 0, TPL_END };
/* Clear tables, device map */
for (i = 0; i < DEVNO; i++) {
dev_tab[i] = NULL;
sch_tab[i] = 0; }
for (i = 0; i < (INTSZ * 32); i++) int_tab[i] = 0;
for (i = 0; i < (DEVNO / 32); i++) dmap[i] = 0;
/* Test each device for conflict; add to map; init tables */
for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if ((dibp == NULL) || (dptr->flags & DEV_DIS)) continue; /* exist, enabled? */
dno = dibp->dno; /* get device num */
if (dibp->ini) dibp->ini (TRUE); /* gen dno template */
tplte = dibp->tplte; /* get template */
if (tplte == NULL) tplte = dflt_tplte; /* none? use default */
for ( ; *tplte != TPL_END; tplte++) { /* loop thru template */
t = (dno + *tplte) & DEV_MAX; /* loop thru template */
dmsk = 1u << (t & 0x1F); /* bit to test */
doff = t / 32; /* word to test */
if (dmap[doff] & dmsk) { /* in use? */
printf ("Device number conflict, devno = %02X\n", t);
if (sim_log) fprintf (sim_log,
"Device number conflict, devno = %02X\n", t);
return TRUE; }
dmap[doff] = dmap[doff] | dmsk;
if (dibp->sch >= 0) sch_tab[t] = dibp->sch + 1;
dev_tab[t] = dibp->iot; }
if (dibp->ini) dibp->ini (FALSE); /* gen int template */
tplte = dibp->tplte; /* get template */
if (tplte == NULL) tplte = dflt_tplte; /* none? use default */
for (j = dibp->irq; *tplte != TPL_END; j++, tplte++) {
int_tab[j] = (dno + *tplte) & DEV_MAX; }
} /* end for i */
return FALSE;
}

288
Interdata/id_lp.c Normal file
View file

@ -0,0 +1,288 @@
/* id_lp.c: Interdata line printer
Copyright (c) 2001-2002, 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.
lpt M46-206 line printer
*/
#include "id_defs.h"
#include <ctype.h>
/* Device definitions */
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
#define SPC_BASE 0x40 /* spacing base */
#define VFU_BASE 0x78 /* VFU base */
#define VFU_WIDTH 0x8 /* VFU width */
#define LF 0xA
#define VT 0xB
#define VT_VFU 4 /* VFU chan for VT */
#define FF 0xC
#define FF_VFU 8 /* VFU chan for FF */
#define CR 0xD
#define VFUP(ch,val) ((val) & (1 << (ch))) /* VFU chan test */
/* Status byte, * = dynamic */
#define STA_PAPE 0x40 /* *paper empty */
#define STA_MASK (STA_BSY) /* static status */
uint32 lpt_sta = STA_BSY; /* status */
char lpxb[LPT_WIDTH + 1]; /* line buffer */
uint32 lpt_bptr = 0; /* buf ptr */
uint32 lpt_spnd = 0; /* space pending */
uint32 lpt_vfup = 0; /* VFU ptr */
uint32 lpt_vful = 1; /* VFU lnt */
uint8 lpt_vfut[VFU_LNT] = { 0xFF }; /* VFU tape */
uint32 lpt_arm = 0; /* int armed */
int32 lpt_ctime = 10; /* char time */
int32 lpt_stime = 1000; /* space time */
int32 lpt_stopioe = 0; /* stop on err */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
DEVICE lpt_dev;
uint32 lpt (uint32 dev, uint32 op, uint32 dat);
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat lpt_bufout (UNIT *uptr);
t_stat lpt_vfu (UNIT *uptr, int32 ch);
t_stat lpt_spc (UNIT *uptr, int32 cnt);
/* LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit descriptors
lpt_reg LPT register list
*/
DIB lpt_dib = { d_LPT, -1, v_LPT, NULL, &lpt, NULL };
UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_UC, 0) };
REG lpt_reg[] = {
{ HRDATA (STA, lpt_sta, 8) },
{ HRDATA (BUF, lpt_unit.buf, 7) },
{ BRDATA (DBUF, lpxb, 16, 7, LPT_WIDTH) },
{ HRDATA (DBPTR, lpt_bptr, 8) },
{ HRDATA (VFUP, lpt_vfup, 8) },
{ HRDATA (VFUL, lpt_vful, 8) },
{ BRDATA (VFUT, lpt_vfut, 16, 8, VFU_LNT) },
{ FLDATA (IREQ, int_req[l_LPT], i_LPT) },
{ FLDATA (IENB, int_enb[l_LPT], i_LPT) },
{ FLDATA (IARM, lpt_arm, 0) },
{ DRDATA (POS, lpt_unit.pos, 32), PV_LEFT },
{ DRDATA (CTIME, lpt_ctime, 24), PV_LEFT },
{ DRDATA (STIME, lpt_stime, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ HRDATA (DEVNO, lpt_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB lpt_mod[] = {
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 16, 7,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, NULL,
&lpt_dib, DEV_DISABLE };
/* Line printer: IO routine */
uint32 lpt (uint32 dev, uint32 op, uint32 dat)
{
int32 t;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_OC: /* command */
lpt_arm = int_chg (v_LPT, dat, lpt_arm); /* upd int ctrl */
break;
case IO_WD: /* write */
t = lpt_unit.buf = dat & 0x7F; /* mask char */
lpt_sta = STA_BSY; /* set busy */
if (lpt_spnd || ((t >= LF) && (t <= CR))) /* space op? */
sim_activate (&lpt_unit, lpt_stime);
else sim_activate (&lpt_unit, lpt_ctime); /* normal char */
break;
case IO_SS: /* status */
t = lpt_sta & STA_MASK; /* status byte */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* test paper out */
t = t | STA_EX | STA_PAPE | STA_BSY;
return t; }
return 0;
}
/* Unit service */
t_stat lpt_svc (UNIT *uptr)
{
int32 t;
t_stat r = SCPE_OK;
lpt_sta = 0; /* clear busy */
if (lpt_arm) SET_INT (v_LPT); /* armed? intr */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
t = uptr->buf; /* get character */
if (lpt_spnd || ((t >= LF) && (t < CR))) { /* spc pend or spc op? */
lpt_spnd = 0;
if (lpt_bufout (uptr) != SCPE_OK) return SCPE_IOERR; /* print */
if ((t == 1) || (t == LF)) lpt_spc (uptr, 1); /* single space */
else if (t == VT) r = lpt_vfu (uptr, VT_VFU - 1); /* VT->VFU */
else if (t == 0xC) r = lpt_vfu (uptr, FF_VFU - 1); /* FF->VFU */
else if ((t >= SPC_BASE) && (t < VFU_BASE))
lpt_spc (uptr, t - SPC_BASE); /* space */
else if ((t >= VFU_BASE) && (t < VFU_BASE + VFU_WIDTH))
r = lpt_vfu (uptr, t - VFU_BASE); /* VFU */
else fputs ("\r", uptr->fileref); /* overprint */
uptr->pos = ftell (uptr->fileref); /* update position */
if (ferror (lpt_unit.fileref)) {
perror ("LPT I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; } }
else if (t == CR) { /* CR? */
lpt_spnd = 1; /* set spc pend */
return lpt_bufout (uptr); } /* print line */
else if (t >= 0x40) { /* printable? */
if ((uptr->flags & UNIT_UC) && islower (t)) /* UC only? */
t = toupper (t);
if (lpt_bptr < LPT_WIDTH) lpxb[lpt_bptr++] = t; }
return r;
}
/* Printing and spacing routines */
t_stat lpt_bufout (UNIT *uptr)
{
int32 i;
t_stat r = SCPE_OK;
if (lpt_bptr == 0) return SCPE_OK; /* any char in buf? */
for (i = LPT_WIDTH - 1; (i >= 0) && (lpxb[i] == ' '); i--)
lpxb[i] = 0; /* backscan line */
if (lpxb[0]) { /* any char left? */
fputs (lpxb, uptr->fileref); /* write line */
lpt_unit.pos = ftell (uptr->fileref); /* update position */
if (ferror (uptr->fileref)) {
perror ("LPT I/O error");
clearerr (uptr->fileref);
r = SCPE_IOERR; } }
lpt_bptr = 0; /* reset buffer */
for (i = 0; i < LPT_WIDTH; i++) lpxb[i] = ' ';
lpxb[LPT_WIDTH] = 0;
return r;
}
t_stat lpt_vfu (UNIT *uptr, int32 ch)
{
uint32 i, j;
if ((ch == (FF_VFU - 1)) && VFUP (ch, lpt_vfut[0])) { /* top of form? */
fputs ("\n\f", uptr->fileref); /* nl + ff */
lpt_vfup = 0; /* top of page */
return SCPE_OK; }
for (i = 1; i < lpt_vful + 1; i++) { /* sweep thru cct */
lpt_vfup = (lpt_vfup + 1) % lpt_vful; /* adv pointer */
if (VFUP (ch, lpt_vfut[lpt_vfup])) { /* chan punched? */
for (j = 0; j < i; j++) fputc ('\n', uptr->fileref);
return SCPE_OK; } }
return STOP_VFU; /* runaway channel */
}
t_stat lpt_spc (UNIT *uptr, int32 cnt)
{
int32 i;
if (cnt == 0) fputc ('\r', uptr->fileref);
else { for (i = 0; i < cnt; i++) fputc ('\n', uptr->fileref);
lpt_vfup = (lpt_vfup + cnt) % lpt_vful; }
return SCPE_OK;
}
/* Reset routine */
t_stat lpt_reset (DEVICE *dptr)
{
int32 i;
sim_cancel (&lpt_unit); /* deactivate */
lpt_sta = 0; /* clr busy */
lpt_bptr = 0; /* clr buf ptr */
for (i = 0; i < LPT_WIDTH; i++) lpxb[i] = ' '; /* clr buf */
lpxb[LPT_WIDTH] = 0;
CLR_INT (v_LPT); /* clearr int */
CLR_ENB (v_LPT); /* disable int */
lpt_arm = 0; /* disarm int */
return SCPE_OK;
}
/* Attach routine */
t_stat lpt_attach (UNIT *uptr, char *cptr)
{
lpt_vfup = 0; /* top of form */
return attach_unit (uptr, cptr);
}
/* Carriage control load routine */
t_stat lp_load (FILE *fileref, char *cptr, char *fnam)
{
int32 col, ptr, mask, vfubuf[VFU_LNT];
uint32 rpt;
t_stat r;
char cbuf[CBUFSIZE], gbuf[CBUFSIZE];
if (*cptr != 0) return SCPE_ARG;
ptr = 0;
for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
mask = 0;
if (*cptr == '(') { /* repeat count? */
cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
rpt = get_uint (gbuf, 10, VFU_LNT, &r); /* repeat count */
if (r != SCPE_OK) return SCPE_FMT; }
else rpt = 1;
while (*cptr != 0) { /* get col no's */
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
col = get_uint (gbuf, 10, 7, &r); /* column number */
if (r != SCPE_OK) return SCPE_FMT;
mask = mask | (1 << col); } /* set bit */
for ( ; rpt > 0; rpt--) { /* store vals */
if (ptr >= VFU_LNT) return SCPE_FMT;
vfubuf[ptr++] = mask; } }
if (ptr == 0) return SCPE_FMT;
lpt_vful = ptr;
lpt_vfup = 0;
for (rpt = 0; rpt < lpt_vful; rpt++) lpt_vfut[rpt] = vfubuf[rpt];
return SCPE_OK;
}

529
Interdata/id_mt.c Normal file
View file

@ -0,0 +1,529 @@
/* id_mt.c: Interdata magnetic tape simulator
Copyright (c) 2001-2002, 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.
mt M46-494 dual density 9-track magtape controller
Magnetic tapes are represented as a series of variable 8b records
of the form:
32b record length in bytes - exact number
byte 0
byte 1
:
byte n-2
byte n-1
32b record length in bytes - exact number
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a single record length of 0.
End of tape is two consecutive end of file marks.
*/
#include "id_defs.h"
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_PNU (1 << UNIT_V_PNU)
#define UST u3 /* unit status */
#define UCMD u4 /* unit command */
#define MT_MAXFR (1 << 16) /* max transfer */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Command - in UCMD */
#define MTC_SPCR 0x11 /* backspace */
#define MTC_SKFR 0x13 /* space file rev */
#define MTC_CLR 0x20 /* clear */
#define MTC_RD 0x21 /* read */
#define MTC_WR 0x22 /* write */
#define MTC_SKFF 0x23 /* space file fwd */
#define MTC_WEOF 0x30 /* write eof */
#define MTC_REW 0x38 /* rewind */
#define MTC_MASK 0x3F
#define MTC_STOP1 0x40 /* stop, set EOM */
#define MTC_STOP2 0x80 /* stop, set NMTN */
/* Status byte, * = in UST */
#define STA_ERR 0x80 /* error */
#define STA_EOF 0x40 /* end of file */
#define STA_EOT 0x20 /* *end of tape */
#define STA_NMTN 0x10 /* *no motion */
#define STA_UFLGS (STA_EOT|STA_NMTN) /* unit flags */
#define STA_MASK (STA_ERR|STA_EOF|STA_BSY|STA_EOM)
#define SET_EX (STA_ERR|STA_EOF|STA_NMTN)
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint8 mtxb[MT_MAXFR]; /* xfer buffer */
uint32 mt_bptr = 0; /* pointer */
uint32 mt_blnt = 0; /* length */
uint32 mt_sta = 0; /* status byte */
uint32 mt_db = 0; /* data buffer */
uint32 mt_xfr = 0; /* data xfr in prog */
uint32 mt_arm[MT_NUMDR] = { 0 }; /* intr armed */
int32 mt_wtime = 10; /* byte latency */
int32 mt_rtime = 1000; /* record latency */
int32 mt_stopioe = 1; /* stop on error */
uint8 mt_tplte[] = { 0, o_MT0, o_MT0*2, o_MT0*3, TPL_END };
static const uint8 bad_cmd[64] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 };
DEVICE mt_dev;
uint32 mt (uint32 dev, uint32 op, uint32 dat);
t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
t_bool mt_forwsp (UNIT *uptr, int32 *err);
t_bool mt_backsp (UNIT *uptr, int32 *err);
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_detach (UNIT *uptr);
t_stat mt_boot (int32 unitno, DEVICE *dptr);
/* MT data structures
mt_dev MT device descriptor
mt_unit MT unit list
mt_reg MT register list
mt_mod MT modifier list
*/
DIB mt_dib = { d_MT, 0, v_MT, mt_tplte, &mt, NULL };
UNIT mt_unit[] = {
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } };
REG mt_reg[] = {
{ HRDATA (STA, mt_sta, 8) },
{ HRDATA (BUF, mt_db, 8) },
{ BRDATA (DBUF, mtxb, 16, 8, MT_MAXFR) },
{ HRDATA (DBPTR, mt_bptr, 16) },
{ HRDATA (DBLNT, mt_blnt, 17), REG_RO },
{ FLDATA (XFR, mt_xfr, 0) },
{ GRDATA (IREQ, int_req[l_MT], 16, MT_NUMDR, i_MT) },
{ GRDATA (IENB, int_enb[l_MT], 16, MT_NUMDR, i_MT) },
{ BRDATA (IARM, mt_arm, 16, 1, MT_NUMDR) },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ DRDATA (WTIME, mt_wtime, 24), PV_LEFT + REG_NZ },
{ DRDATA (RTIME, mt_rtime, 24), PV_LEFT + REG_NZ },
{ URDATA (UST, mt_unit[0].UST, 16, 8, 0, MT_NUMDR, 0) },
{ URDATA (CMD, mt_unit[0].UCMD, 16, 8, 0, MT_NUMDR, 0) },
{ URDATA (POS, mt_unit[0].pos, 10, 32, 0,
MT_NUMDR, PV_LEFT | REG_RO) },
{ HRDATA (DEVNO, mt_dib.dno, 8), REG_HRO },
{ HRDATA (SELCH, mt_dib.sch, 1), REG_HRO },
{ NULL } };
MTAB mt_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH",
&set_sch, &show_sch, NULL },
{ 0 } };
DEVICE mt_dev = {
"MT", mt_unit, mt_reg, mt_mod,
MT_NUMDR, 10, 31, 1, 16, 8,
NULL, NULL, &mt_reset,
&mt_boot, &mt_attach, &mt_detach,
&mt_dib, DEV_DISABLE };
/* Magtape: IO routine */
uint32 mt (uint32 dev, uint32 op, uint32 dat)
{
uint32 i, f, t;
uint32 u = (dev - mt_dib.dno) / o_MT0;
UNIT *uptr = mt_dev.units + u;
switch (op) { /* case IO op */
case IO_ADR: /* select */
sch_adr (mt_dib.sch, dev); /* inform sel ch */
return BY; /* byte only */
case IO_RD: /* read data */
if (mt_xfr) mt_sta = mt_sta | STA_BSY; /* xfr? set busy */
return mt_db; /* return data */
case IO_WD: /* write data */
if (mt_xfr) { /* transfer? */
mt_sta = mt_sta | STA_BSY; /* set busy */
if ((uptr->UCMD & (MTC_STOP1 | MTC_STOP2)) &&
((uptr->UCMD & MTC_MASK) == MTC_WR)) /* while stopping? */
mt_sta = mt_sta | STA_ERR; } /* write overrun */
mt_db = dat & DMASK8; /* store data */
break;
case IO_SS: /* status */
mt_sta = mt_sta & STA_MASK; /* ctrl status */
if (uptr->flags & UNIT_ATT) /* attached? */
t = mt_sta | (uptr->UST & STA_UFLGS); /* yes, unit status */
else t = mt_sta | STA_DU; /* no, dev unavail */
if (t & SET_EX) t = t | STA_EX; /* test for ex */
return t;
case IO_OC: /* command */
mt_arm[u] = int_chg (v_MT + u, dat, mt_arm[u]);
f = dat & MTC_MASK; /* get cmd */
if (f == MTC_CLR) { /* clear? */
mt_reset (&mt_dev); /* reset world */
break; }
if (((uptr->flags & UNIT_ATT) == 0) || /* ignore if unatt */
bad_cmd[f] || /* or bad cmd */
(((f == MTC_WR) || (f == MTC_WEOF)) && /* or write */
(uptr->flags & UNIT_WPRT))) break; /* and protected */
for (i = 0; i < MT_NUMDR; i++) { /* check other drvs */
if (sim_is_active (&mt_unit[i]) && /* active? */
(mt_unit[i].UCMD != MTC_REW)) { /* not rewind? */
sim_cancel (&mt_unit[i]); /* stop */
mt_unit[i].UCMD = 0; }
if (sim_is_active (uptr) && /* unit active? */
!(uptr->UCMD & (MTC_STOP1 | MTC_STOP2))) /* not stopping? */
break; /* ignore */
if ((f == MTC_WR) || (f == MTC_REW)) mt_sta = 0;/* write, rew: bsy=0 */
else mt_sta = STA_BSY; /* bsy=1,nmtn,eom,err=0 */
mt_bptr = mt_blnt = 0; /* not yet started */
if ((f == MTC_RD) || (f == MTC_WR)) /* data xfr? */
mt_xfr = 1; /* set xfr flag */
else mt_xfr = 0; }
uptr->UCMD = f; /* save cmd */
uptr->UST = 0; /* clr tape stat */
sim_activate (uptr, mt_rtime); /* start op */
break; }
return 0;
}
/* Unit service
A given operation can generate up to three interrupts
- EOF generates an interrupt when set (read, space, wreof)
BUSY will still be set, EOM and NMTN will be clear
- After operation complete + delay, EOM generates an interrupt
BUSY will be clear, EOM will be set, NMTN will be clear
- After a further delay, NMTN generates an interrupt
BUSY will be clear, EOM and NMTN will be set
Rewind generates an interrupt when NMTN sets
*/
t_stat mt_svc (UNIT *uptr)
{
uint32 i, pnu;
int32 err;
int32 u = uptr - mt_dev.units;
uint32 dev = mt_dib.dno + (u * o_MT0);
t_mtrlnt tbc;
static t_mtrlnt bceof = { 0 };
err = 0;
pnu = MT_TST_PNU (uptr); /* get pos not upd */
MT_CLR_PNU (uptr); /* and clear */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
uptr->UCMD = 0; /* clr cmd */
uptr->UST = 0; /* set status */
mt_xfr = 0; /* clr op flags */
mt_sta = STA_ERR | STA_EOM; /* set status */
if (mt_arm[u]) SET_INT (v_MT + u); /* interrupt */
return IORETURN (mt_stopioe, SCPE_UNATT); }
if (uptr->UCMD & MTC_STOP2) { /* stop, gen NMTN? */
uptr->UCMD = 0; /* clr cmd */
uptr->UST = STA_NMTN; /* set nmtn, not eot */
mt_xfr = 0; /* clr xfr */
if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */
return SCPE_OK; }
if (uptr->UCMD & MTC_STOP1) { /* stop, gen EOM? */
uptr->UCMD = uptr->UCMD | MTC_STOP2; /* clr cmd */
mt_sta = (mt_sta & ~STA_BSY) | STA_EOM; /* clr busy, set eom */
if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */
sim_activate (uptr, mt_rtime); /* schedule */
return SCPE_OK; } /* end case */
switch (uptr->UCMD) { /* case on function */
case MTC_REW: /* rewind */
uptr->UCMD = 0; /* clr cmd */
uptr->pos = 0; /* update position */
uptr->UST = STA_NMTN | STA_EOT; /* update status */
mt_sta = mt_sta & ~STA_BSY; /* don't set EOM */
if (mt_arm[u]) SET_INT (v_MT + u); /* interrupt */
return SCPE_OK;
/* Unit service, continued
For read, busy = 1 => buffer empty
For write, busy = 1 => buffer full
For read, data transfers continue for the full length of the
record, or the maximum size of the transfer buffer
For write, data transfers continue until a write is attempted
and the buffer is empty
*/
case MTC_RD: /* read */
if (mt_blnt == 0) { /* first time? */
if (mt_rdlntf (uptr, &tbc, &err)) break; /* read rec lnt, err? */
mt_blnt = tbc; /* set buf lnt */
if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */
i = fxread (mtxb, sizeof (uint8), mt_blnt, uptr->fileref);
if (err = ferror (uptr->fileref)) { /* error? */
MT_SET_PNU (uptr); /* pos not upd */
break; }
for ( ; i < mt_blnt; i++) mtxb[i] = 0; /* fill with 0's */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) /* upd pos */
+ (2 * sizeof (t_mtrlnt)); }
if (sch_actv (mt_dib.sch, dev)) { /* sch active? */
i = sch_wrmem (mt_dib.sch, mtxb, mt_blnt); /* store rec in mem */
if (sch_actv (mt_dib.sch, dev)) /* sch still active? */
sch_stop (mt_dib.sch); /* stop chan, long rd */
else if (i < mt_blnt) /* process entire rec? */
mt_sta = mt_sta | STA_ERR; } /* no, overrun error */
else if (mt_bptr < mt_blnt) { /* no, if !eor */
if (!(mt_sta & STA_BSY)) /* busy still clr? */
mt_sta = mt_sta | STA_ERR; /* read overrun */
mt_db = mtxb[mt_bptr++]; /* get next byte */
mt_sta = mt_sta & ~STA_BSY; /* !busy = buf full */
if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */
sim_activate (uptr, mt_wtime); /* reschedule */
return SCPE_OK; }
break; /* record done */
case MTC_WR: /* write */
if (sch_actv (mt_dib.sch, dev)) { /* sch active? */
mt_bptr = sch_rdmem (mt_dib.sch, mtxb, MT_MAXFR); /* get rec */
if (sch_actv (mt_dib.sch, dev)) /* not done? */
sch_stop (mt_dib.sch); } /* stop chan */
else if (mt_sta & STA_BSY) { /* no, if !eor */
if (mt_bptr < MT_MAXFR) /* if room */
mtxb[mt_bptr++] = mt_db; /* store in buf */
mt_sta = mt_sta & ~STA_BSY; /* !busy = buf emp */
if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */
sim_activate (uptr, mt_wtime); /* reschedule */
return SCPE_OK; }
if (mt_bptr) { /* any chars? */
int32 ebc = (mt_bptr + 1) & ~1; /* force even */
fseek (uptr->fileref, uptr->pos, SEEK_SET);
fxwrite (&mt_bptr, sizeof (t_mtrlnt), 1, uptr->fileref);
fxwrite (mtxb, sizeof (uint8), ebc, uptr->fileref);
fxwrite (&mt_bptr, sizeof (t_mtrlnt), 1, uptr->fileref);
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr);
else uptr->pos = uptr->pos + ebc + (2 * sizeof (t_mtrlnt)); }
break; /* record done */
/* Unit service, continued */
case MTC_WEOF: /* write eof */
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref);
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr);
else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */
mt_sta = mt_sta | STA_EOF; /* set eof */
if (mt_arm[u]) SET_INT (v_MT + u); /* interrupt */
break;
case MTC_SKFF: /* skip file fwd */
while (mt_forwsp (uptr, &err)) ; /* spc until EOF/EOT */
break;
case MTC_SKFR: /* skip file rev */
while (mt_backsp (uptr, &err)) ; /* spc until EOF/BOT */
break;
case MTC_SPCR: /* backspace */
if (!pnu) mt_backsp (uptr, &err); /* if pos not upd */
break; } /* end case */
if (err != 0) { /* I/O error */
mt_sta = mt_sta | STA_ERR;
perror ("MT I/O error");
clearerr (uptr->fileref);
if (mt_stopioe) return SCPE_IOERR; }
uptr->UCMD = uptr->UCMD | MTC_STOP1; /* set stop stage 1 */
sim_activate (uptr, mt_rtime); /* schedule */
return SCPE_OK;
}
/* Tape motion routines */
t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
{
int32 u = uptr - mt_dev.units;
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position */
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */
if ((*err = ferror (uptr->fileref)) || /* err or eom? */
feof (uptr->fileref) || (*tbc == MTR_EOM)) {
mt_sta = mt_sta | STA_ERR; /* set err */
MT_SET_PNU (uptr); /* pos not upd */
return TRUE; }
if (*tbc == MTR_TMK) { /* tape mark? */
mt_sta = mt_sta | STA_EOF; /* set eof */
if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */
return TRUE; }
*tbc = MTRL (*tbc);
return FALSE;
}
t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
{
int32 u = uptr - mt_dev.units;
if (uptr->pos < sizeof (t_mtrlnt)) { /* at bot? */
uptr->UST = uptr->UST | STA_EOT; /* set err */
return TRUE; }
fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET);
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */
if ((*err = ferror (uptr->fileref)) || /* err or eof? */
feof (uptr->fileref)) {
mt_sta = mt_sta | STA_ERR; /* set err */
return TRUE; }
if (*tbc == MTR_EOM) { /* eom? */
mt_sta = mt_sta | STA_ERR; /* set err */
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* update pos */
return TRUE; }
if (*tbc == MTR_TMK) { /* tape mark? */
mt_sta = mt_sta | STA_EOF; /* set eof */
if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* update pos */
return TRUE; }
*tbc = MTRL (*tbc);
return FALSE;
}
t_bool mt_forwsp (UNIT *uptr, int32 *err)
{
t_mtrlnt tbc;
if (mt_rdlntf (uptr, &tbc, err)) return FALSE; /* read rec lnt, err? */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* space to next rec */
(2 * sizeof (t_mtrlnt));
return TRUE;
}
t_bool mt_backsp (UNIT *uptr, int32 *err)
{
t_mtrlnt tbc;
if (mt_rdlntr (uptr, &tbc, err)) return FALSE; /* read rec lnt, err? */
uptr->pos = uptr->pos - ((tbc + 1) & ~1) - /* space to prv rec */
(2 * sizeof (t_mtrlnt));
return TRUE;
}
/* Reset routine */
t_stat mt_reset (DEVICE *dptr)
{
uint32 u;
UNIT *uptr;
mt_bptr = mt_blnt = 0; /* clr buf */
mt_sta = STA_BSY; /* clr flags */
mt_xfr = 0; /* clr controls */
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
CLR_INT (v_MT + u); /* clear int */
CLR_ENB (v_MT + u); /* disable int */
mt_arm[u] = 0; /* disarm int */
uptr = mt_dev.units + u;
MT_CLR_PNU (uptr); /* clear pos flag */
sim_cancel (uptr); /* cancel activity */
uptr->UST = (uptr->UST & STA_UFLGS) | STA_NMTN; /* init status */
uptr->UCMD = 0; } /* init cmd */
return SCPE_OK;
}
/* Attach routine */
t_stat mt_attach (UNIT *uptr, char *cptr)
{
int32 u = uptr - mt_dev.units;
t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
uptr->pos = 0;
MT_CLR_PNU (uptr);
uptr->UST = STA_EOT;
if (mt_arm[u]) SET_INT (v_MT + u);
return r;
}
/* Detach routine */
t_stat mt_detach (UNIT* uptr)
{
int32 u = uptr - mt_dev.units;
t_stat r;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK;
r = detach_unit (uptr);
if (r != SCPE_OK) return r;
if (mt_arm[u]) SET_INT (v_MT + u);
MT_CLR_PNU (uptr);
uptr->UST = 0;
return SCPE_OK;
}
/* Bootstrap routine */
#define BOOT_START 0x50
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
static uint8 boot_rom[] = {
0xD5, 0x00, /* ST: AL CF */
0x00, 0xCF,
0x43, 0x00, /* BR 80 */
0x00, 0x80
};
t_stat mt_boot (int32 unitno, DEVICE *dptr)
{
extern uint32 PC, dec_flgs;
extern uint16 decrom[];
extern DIB sch_dib;
uint32 sch_dev;
if (decrom[0xD5] & dec_flgs) return SCPE_NOFNC; /* AL defined? */
mt_unit[unitno].pos = 0; /* rewind */
sch_dev = sch_dib.dno + mt_dib.sch; /* sch dev # */
IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy boot */
IOWriteB (AL_DEV, mt_dib.dno + (unitno * o_MT0)); /* set dev no for unit */
IOWriteB (AL_IOC, 0xA1); /* set dev cmd */
IOWriteB (AL_SCH, sch_dev); /* set dev no for chan */
PC = BOOT_START;
return SCPE_OK;
}

546
Interdata/id_pas.c Normal file
View file

@ -0,0 +1,546 @@
/* id_pas.c: Interdata programmable async line adapter simulator
Copyright (c) 2001-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.
pas Programmable asynchronous line adapter(s)
This module implements up to 32 individual serial interfaces, representing
either individual PASLA modules or combinations of the 2-line and 8-line
multiplexors, which are functionally very similar. These interfaces are mapped
to Telnet based connections as the lines of a terminal multiplexor. The
connection polling mechanism and the character input polling for all lines
are done through a single polling job.
*/
#include "id_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>
#define PAS_LINES 32
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
#define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */
#define UNIT_V_MDM (UNIT_V_UF + 2) /* modem control */
#define UNIT_8B (1 << UNIT_V_8B)
#define UNIT_UC (1 << UNIT_V_UC)
#define UNIT_MDM (1 << UNIT_V_MDM)
#define PAS_INIT_POLL 8000
#define PASL_WAIT 500
/* Status byte */
#define STA_OVR 0x80 /* overrun RO */
#define STA_PF 0x40 /* parity err RONI */
#define STA_NCL2S 0x40 /* not clr to snd XO */
#define STA_FR 0x20 /* framing err RO */
#define STA_RCR 0x10 /* rv chan rcv NI */
#define STA_CROF 0x02 /* carrier off RO */
#define STA_RING 0x01 /* ring RO */
#define STA_RCV (STA_OVR|STA_PF|STA_FR|STA_RCR|STA_CROF|STA_RING)
#define SET_EX (STA_OVR|STA_PF|STA_FR)
#define STA_XMT (STA_BSY)
/* Command bytes 1,0 */
#define CMD_DTR (0x20 << 8) /* DTR */
#define CMD_ECHO (0x10 << 8) /* echoplex */
#define CMD_RCT (0x08 << 8) /* RCT/DTB NI */
#define CMD_XMTB (0x04 << 8) /* xmt break NI */
#define CMD_WRT (0x02 << 8) /* write/read */
#define CMD_V_CLK 6 /* baud rate */
#define CMD_M_CLK 0x3
#define CMD_V_DB 4 /* data bits */
#define CMD_M_DB 0x3
#define CMD_STOP 0x80 /* stop bit */
#define CMD_V_PAR 1 /* parity */
#define CMD_M_PAR 0x3
#define GET_PAR(x) (((x) >> CMD_V_PAR) & CMD_M_PAR)
#define PAR_NONE 0
#define PAR_RAW 1
#define PAR_ODD 2
#define PAR_EVEN 3
#define CMD_TYP 0x01 /* command type */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint8 pas_sta[PAS_LINES]; /* status */
uint16 pas_cmd[PAS_LINES]; /* command */
uint8 pas_rbuf[PAS_LINES]; /* rcv buf */
uint8 pas_xbuf[PAS_LINES]; /* xmt buf */
uint8 pas_rarm[PAS_LINES]; /* rcvr int armed */
uint8 pas_xarm[PAS_LINES]; /* xmt int armed */
uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */
uint32 pas_tps = 50; /* polls/second */
uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */
TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */
TMXR pas_desc = { 8, 0, 0, &pas_ldsc[0], NULL }; /* mux descriptor */
#define PAS_ENAB pas_desc.lines
uint32 pas (uint32 dev, uint32 op, uint32 dat);
void pas_ini (t_bool dtpl);
t_stat pasi_svc (UNIT *uptr);
t_stat paso_svc (UNIT *uptr);
t_stat pas_reset (DEVICE *dptr);
t_stat pas_attach (UNIT *uptr, char *cptr);
t_stat pas_detach (UNIT *uptr);
t_stat pas_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat pas_show (FILE *st, UNIT *uptr, int32 val, void *desc);
int32 pas_par (int32 cmd, int32 c);
t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
void pas_reset_ln (int32 i);
/* PAS data structures
pas_dev PAS device descriptor
pas_unit PAS unit descriptor
pas_reg PAS register list
pas_mod PAS modifiers list
*/
DIB pas_dib = { d_PAS, -1, v_PAS, pas_tplte, &pas, &pas_ini };
UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE, 0), PAS_INIT_POLL };
REG pas_nlreg = { DRDATA (NLINES, PAS_ENAB, 6), PV_LEFT };
REG pas_reg[] = {
{ BRDATA (STA, pas_sta, 16, 8, PAS_LINES) },
{ BRDATA (CMD, pas_cmd, 16, 16, PAS_LINES) },
{ BRDATA (RBUF, pas_rbuf, 16, 8, PAS_LINES) },
{ BRDATA (XBUF, pas_xbuf, 16, 8, PAS_LINES) },
{ BRDATA (IREQ, &int_req[l_PAS], 16, 32, PAS_LINES / 16) },
{ BRDATA (IENB, &int_enb[l_PAS], 16, 32, PAS_LINES / 16) },
{ BRDATA (RARM, pas_rarm, 16, 1, PAS_LINES) },
{ BRDATA (XARM, pas_xarm, 16, 1, PAS_LINES) },
{ BRDATA (RCHP, pas_rchp, 16, 1, PAS_LINES) },
{ HRDATA (DEVNO, pas_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB pas_mod[] = {
{ MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",
&pas_vlines, NULL, &pas_nlreg },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &pas_desc },
{ UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &pas_summ },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &pas_show, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &pas_show, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
DEVICE pas_dev = {
"PAS", &pas_unit, pas_reg, pas_mod,
1, 10, 31, 1, 16, 8,
&tmxr_ex, &tmxr_dep, &pas_reset,
NULL, &pas_attach, &pas_detach,
&pas_dib, DEV_DISABLE };
/* PASL data structures
pasl_dev PASL device descriptor
pasl_unit PASL unit descriptor
pasl_reg PASL register list
pasl_mod PASL modifiers list
*/
UNIT pasl_unit[] = {
{ UDATA (&paso_svc, 0, 0), PASL_WAIT }, /* all but 8 dis */
{ UDATA (&paso_svc, 0, 0), PASL_WAIT },
{ UDATA (&paso_svc, 0, 0), PASL_WAIT },
{ UDATA (&paso_svc, 0, 0), PASL_WAIT },
{ UDATA (&paso_svc, 0, 0), PASL_WAIT },
{ UDATA (&paso_svc, 0, 0), PASL_WAIT },
{ UDATA (&paso_svc, 0, 0), PASL_WAIT },
{ UDATA (&paso_svc, 0, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
{ UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT } };
MTAB pasl_mod[] = {
{ UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", NULL },
{ UNIT_UC+UNIT_8B, 0 , "7b", "7B", NULL },
{ UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", NULL },
{ UNIT_MDM, 0, "no dataset", "NODATASET", NULL },
{ UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL },
{ 0 } };
REG pasl_reg[] = {
{ URDATA (TIME, pasl_unit[0].wait, 16, 24, 0,
PAS_LINES, REG_NZ + PV_LEFT) },
{ NULL } };
DEVICE pasl_dev = {
"PASL", pasl_unit, pasl_reg, pasl_mod,
PAS_LINES, 10, 31, 1, 16, 8,
NULL, NULL, &pas_reset,
NULL, NULL, NULL,
NULL, 0 };
/* PAS: IO routine */
uint32 pas (uint32 dev, uint32 op, uint32 dat)
{
int32 ln = (dev - pas_dib.dno) >> 1;
int32 xmt = (dev - pas_dib.dno) & 1;
int32 t, old_cmd;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_RD: /* read */
pas_rchp[ln] = 0; /* clr chr pend */
pas_sta[ln] = pas_sta[ln] & ~STA_OVR; /* clr overrun */
return pas_rbuf[ln]; /* return buf */
case IO_WD: /* write */
pas_xbuf[ln] = dat & 0xFF; /* store char */
pas_sta[ln] = pas_sta[ln] | STA_BSY; /* set busy */
sim_activate (&pasl_unit[ln], pasl_unit[ln].wait);
break;
case IO_SS: /* status */
if (xmt) { /* xmt side? */
if (pas_ldsc[ln].conn == 0) /* not conn? */
t = STA_NCL2S | STA_BSY; /* busy, not clr */
else t = pas_sta[ln] & STA_XMT; } /* else just busy */
else {
t = pas_sta[ln] & STA_RCV; /* get static */
if (!pas_rchp[ln]) t = t | STA_BSY; /* no char? busy */
if (pas_ldsc[ln].conn == 0) /* not connected? */
t = t | STA_BSY | STA_EX; /* = !dsr */
if (t & SET_EX) t = t | STA_EX; } /* test for ex */
return t;
case IO_OC: /* command */
old_cmd = pas_cmd[ln]; /* old cmd */
if (dat & CMD_TYP) { /* type 1? */
pas_cmd[ln] = (pas_cmd[ln] & 0xFF) | (dat << 8);
if (pas_cmd[ln] & CMD_WRT) /* write? */
pas_xarm[ln] = int_chg (v_PASX + ln + ln, dat, pas_xarm[ln]);
else pas_rarm[ln] = int_chg (v_PAS + ln + ln, dat, pas_rarm[ln]); }
else pas_cmd[ln] = (pas_cmd[ln] & ~0xFF) | dat;
if (pasl_unit[ln].flags & UNIT_MDM) { /* modem ctrl? */
if ((pas_cmd[ln] & CMD_DTR) && (pas_sta[ln] & STA_RING))
pas_sta[ln] = pas_sta[ln] & ~(STA_CROF | STA_RING);
if (old_cmd & ~pas_cmd[ln] & CMD_DTR) {
tmxr_msg (pas_ldsc[ln].conn, "\r\nLine hangup\r\n");
tmxr_reset_ln (&pas_ldsc[ln]); /* reset line */
pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */
if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln); } }
break; }
return 0;
}
/* Unit service - receive side
Poll all active lines for input
Poll for new connections
*/
t_stat pasi_svc (UNIT *uptr)
{
int32 ln, c, out, t;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
t = sim_rtcn_calb (pas_tps, TMR_PAS); /* calibrate */
sim_activate (uptr, t); /* continue poll */
ln = tmxr_poll_conn (&pas_desc); /* look for connect */
if (ln >= 0) { /* got one? */
if ((pasl_unit[ln].flags & UNIT_MDM) && /* modem control */
((pas_cmd[ln] & CMD_DTR) == 0)) /* & !dtr? */
pas_sta[ln] = pas_sta[ln] | STA_RING | STA_CROF; /* set ring, no cd */
else pas_sta[ln] = pas_sta[ln] & ~STA_CROF; /* just answer */
if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln); /* interrupt */
pas_ldsc[ln].rcve = 1; } /* rcv enabled */
tmxr_poll_rx (&pas_desc); /* poll for input */
for (ln = 0; ln < PAS_ENAB; ln++) { /* loop thru lines */
if (pas_ldsc[ln].conn) { /* connected? */
if (c = tmxr_getc_ln (&pas_ldsc[ln])) { /* any char? */
pas_sta[ln] = pas_sta[ln] & ~(STA_FR | STA_PF);
if (pas_rchp[ln]) pas_sta[ln] = pas_sta[ln] | STA_OVR;
if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln);
if (c & SCPE_BREAK) { /* break? */
pas_sta[ln] = pas_sta[ln] | STA_FR; /* framing error */
pas_rbuf[ln] = 0; } /* no character */
else { /* normal */
out = c & 0x7F; /* echo is 7b */
if (pasl_unit[ln].flags & UNIT_8B) /* 8b? */
c = c & 0xFF;
else { /* UC or 7b */
if ((pasl_unit[ln].flags & UNIT_UC) && islower (out))
out = toupper (out); /* cvt to UC */
c = pas_par (pas_cmd[ln], out); } /* apply parity */
pas_rbuf[ln] = c; /* save char */
pas_rchp[ln] = 1; /* char pending */
if ((pas_cmd[ln] & CMD_ECHO) && pas_ldsc[ln].xmte) {
TMLN *lp = &pas_ldsc[ln]; /* get line */
tmxr_putc_ln (lp, out); /* output char */
tmxr_poll_tx (&pas_desc); } /* poll xmt */
} /* end else normal */
} /* end if char */
} /* end if conn */
else if ((pas_sta[ln] & STA_CROF) == 0) { /* not conn, was conn? */
pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */
if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln); } /* intr */
} /* end for */
return SCPE_OK;
}
/* Unit service - transmit side */
t_stat paso_svc (UNIT *uptr)
{
int32 c;
uint32 ln = uptr - pasl_unit; /* line # */
if (pas_ldsc[ln].conn) { /* connected? */
if (pas_ldsc[ln].xmte) { /* xmt enabled? */
TMLN *lp = &pas_ldsc[ln]; /* get line */
if (pasl_unit[ln].flags & UNIT_8B) /* 8b? */
c = pas_par (pas_cmd[ln], pas_xbuf[ln]);/* apply parity */
else { /* UC or 7b */
c = pas_xbuf[ln] & 0x7F; /* mask char */
if ((pasl_unit[ln].flags & UNIT_UC) && islower (c))
c = toupper (c); } /* cvt to UC */
tmxr_putc_ln (lp, c); /* output char */
tmxr_poll_tx (&pas_desc); } /* poll xmt */
else { /* buf full */
tmxr_poll_tx (&pas_desc); /* poll xmt */
sim_activate (uptr, pasl_unit[ln].wait); /* wait */
return SCPE_OK; } }
pas_sta[ln] = pas_sta[ln] & ~STA_BSY; /* not busy */
if (pas_xarm[ln]) SET_INT (v_PASX + ln + ln); /* set intr */
return SCPE_OK;
}
int32 pas_par (int32 cmd, int32 c)
{
int32 pf = GET_PAR (cmd);
static const uint8 odd_par[] = {
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80 };
switch (pf) { /* case on parity */
case PAR_ODD:
return (odd_par[c & 0x7F]) | (c & 0x7F);
case PAR_EVEN:
return (odd_par[c & 0x7F] ^ 0x80) | (c & 0x7F);
case PAR_NONE:
case PAR_RAW:
break; }
return c & 0xFF;
}
/* Reset routine */
t_stat pas_reset (DEVICE *dptr)
{
int32 i, t;
if (dptr->flags & DEV_DIS) { /* disabled? */
pas_dev.flags = pas_dev.flags | DEV_DIS; /* disable lines */
pasl_dev.flags = pasl_dev.flags | DEV_DIS; }
else { pas_dev.flags = pas_dev.flags & ~DEV_DIS; /* enable lines */
pasl_dev.flags = pasl_dev.flags & ~DEV_DIS; }
if (pas_unit.flags & UNIT_ATT) { /* master att? */
if (!sim_is_active (&pas_unit)) {
t = sim_rtcn_init (pas_unit.wait, TMR_PAS);
sim_activate (&pas_unit, t); } } /* activate */
else sim_cancel (&pas_unit); /* else stop */
for (i = 0; i < PAS_LINES; i++) {
pas_desc.ldsc[i] = &pas_ldsc[i];
pas_reset_ln (i); }
return SCPE_OK;
}
/* Attach master unit */
t_stat pas_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = tmxr_attach (&pas_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
sim_rtcn_init (pas_unit.wait, TMR_PAS);
sim_activate (uptr, 100); /* quick poll */
return SCPE_OK;
}
/* Detach master unit */
t_stat pas_detach (UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach (&pas_desc, uptr); /* detach */
for (i = 0; i < PAS_LINES; i++) pas_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (uptr); /* stop poll */
return r;
}
/* Show summary processor */
t_stat pas_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < PAS_LINES; i++) t = t + (pas_ldsc[i].conn != 0);
if (t == 1) fprintf (st, "1 connection");
else fprintf (st, "%d connections", t);
return SCPE_OK;
}
/* SHOW CONN/STAT processor */
t_stat pas_show (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i;
for (i = 0; (i < PAS_LINES) && (pas_ldsc[i].conn == 0); i++) ;
if (i < PAS_LINES) {
for (i = 0; i < PAS_LINES; i++) {
if (pas_ldsc[i].conn)
if (val) tmxr_fconns (st, &pas_ldsc[i], i);
else tmxr_fstats (st, &pas_ldsc[i], i); } }
else fprintf (st, "all disconnected\n");
return SCPE_OK;
}
/* Change number of lines */
t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
newln = get_uint (cptr, 10, PAS_LINES, &r);
if ((r != SCPE_OK) || (newln == PAS_ENAB)) return r;
if (newln == 0) return SCPE_ARG;
if (newln < PAS_ENAB) {
for (i = newln, t = 0; i < PAS_ENAB; i++) t = t | pas_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < PAS_ENAB; i++) {
if (pas_ldsc[i].conn) {
tmxr_msg (pas_ldsc[i].conn, "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&pas_ldsc[i]); } /* reset line */
pasl_unit[i].flags = pasl_unit[i].flags | UNIT_DIS;
pas_reset_ln (i); }
}
else { for (i = PAS_ENAB; i < newln; i++) {
pasl_unit[i].flags = pasl_unit[i].flags & ~UNIT_DIS;
pas_reset_ln (i); }
}
PAS_ENAB = newln;
return SCPE_OK;
}
/* Reset an individual line */
void pas_reset_ln (int32 i)
{
CLR_INT (v_PAS + i + i); /* clear int */
CLR_ENB (v_PAS + i + i);
CLR_INT (v_PASX + i + i); /* disable int */
CLR_ENB (v_PASX + i + i);
pas_rarm[i] = pas_xarm[i] = 0; /* disarm int */
pas_rbuf[i] = pas_xbuf[i] = 0; /* clear state */
pas_cmd[i] = 0;
pas_rchp[i] = 0;
pas_sta[i] = 0;
if (pas_ldsc[i].conn == 0) /* clear carrier */
pas_sta[i] = pas_sta[i] | STA_CROF;
sim_cancel (&pasl_unit[i]);
return;
}
/* Init template */
void pas_ini (t_bool dtpl)
{
int32 i, j;
for (i = j = 0; i < PAS_ENAB; i++) {
pas_tplte[j] = j;
pas_tplte[j + 1] = j + o_PASX;
j = j + 2; }
pas_tplte[j] = TPL_END;
return;
}

350
Interdata/id_pt.c Normal file
View file

@ -0,0 +1,350 @@
/* id_pt.c: Interdata paper tape reader
Copyright (c) 2000-2001, 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.
pt paper tape reader and punch
*/
#include "id_defs.h"
#include <ctype.h>
/* Device definitions */
#define PTR 0 /* unit subscripts */
#define PTP 1
#define STA_OVR 0x80 /* overrun */
#define STA_NMTN 0x10 /* no motion */
#define STA_MASK (STA_BSY | STA_OVR | STA_DU) /* static bits */
#define SET_EX (STA_OVR | STA_NMTN) /* set EX */
#define CMD_V_RUN 4 /* run/stop */
#define CMD_V_SLEW 2 /* slew/step */
#define CMD_V_RD 0 /* read/write */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint32 pt_run = 0, pt_slew = 0; /* ptr modes */
uint32 pt_rd = 1, pt_chp = 0; /* pt state */
uint32 pt_arm = 0; /* int arm */
uint32 pt_sta = STA_BSY; /* status */
uint32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
DEVICE pt_dev;
uint32 pt (uint32 dev, uint32 op, uint32 dat);
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat pt_boot (int32 unitno, DEVICE *dptr);
t_stat pt_reset (DEVICE *dptr);
/* PT data structures
pt_dev PT device descriptor
pt_unit PT unit descriptors
pt_reg PT register list
*/
DIB pt_dib = { d_PT, -1, v_PT, NULL, &pt, NULL };
UNIT pt_unit[] = {
{ UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT },
{ UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0),
SERIAL_OUT_WAIT } };
REG pt_reg[] = {
{ HRDATA (STA, pt_sta, 8) },
{ HRDATA (RBUF, pt_unit[PTR].buf, 8) },
{ DRDATA (RPOS, pt_unit[PTR].pos, 32), PV_LEFT },
{ DRDATA (RTIME, pt_unit[PTR].wait, 24), PV_LEFT },
{ FLDATA (RSTOP_IOE, ptr_stopioe, 0) },
{ HRDATA (PBUF, pt_unit[PTP].buf, 8) },
{ DRDATA (PPOS, pt_unit[PTP].pos, 32), PV_LEFT },
{ DRDATA (PTIME, pt_unit[PTP].wait, 24), PV_LEFT },
{ FLDATA (PSTOP_IOE, ptp_stopioe, 0) },
{ FLDATA (IREQ, int_req[l_PT], i_PT) },
{ FLDATA (IENB, int_enb[l_PT], i_PT) },
{ FLDATA (IARM, pt_arm, 0) },
{ FLDATA (RD, pt_rd, 0) },
{ FLDATA (RUN, pt_run, 0) },
{ FLDATA (SLEW, pt_slew, 0) },
{ FLDATA (CHP, pt_chp, 0) },
{ HRDATA (DEVNO, pt_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB pt_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "devno", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
DEVICE pt_dev = {
"PT", pt_unit, pt_reg, pt_mod,
2, 10, 31, 1, 16, 8,
NULL, NULL, &pt_reset,
&pt_boot, NULL, NULL,
&pt_dib, DEV_DISABLE };
/* Paper tape: IO routine */
uint32 pt (uint32 dev, uint32 op, uint32 dat)
{
uint32 t, old_rd, old_run;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_OC: /* command */
old_rd = pt_rd; /* save curr rw */
old_run = pt_run; /* save curr run */
pt_arm = int_chg (v_PT, dat, pt_arm); /* upd int ctrl */
pt_rd = io_2b (dat, CMD_V_RD, pt_rd); /* upd read/wr */
if (old_rd != pt_rd) { /* rw change? */
pt_sta = pt_sta & ~STA_OVR; /* clr overrun */
if (sim_is_active (&pt_unit[pt_rd? PTR: PTP])) {
pt_sta = pt_sta | STA_BSY; /* busy = 1 */
CLR_INT (v_PT); } /* clear int */
else { /* not active */
pt_sta = pt_sta & ~STA_BSY; /* busy = 0 */
if (pt_arm) SET_INT (v_PT); } } /* no, set int */
if (pt_rd) { /* reader? */
pt_run = io_2b (dat, CMD_V_RUN, pt_run); /* upd run/stop */
pt_slew = io_2b (dat, CMD_V_SLEW, pt_slew); /* upd slew/inc */
if (pt_run) { /* run set? */
if (old_run == 0) { /* run 0 -> 1? */
sim_activate (&pt_unit[PTR], pt_unit[PTR].wait);
pt_sta = pt_sta & ~STA_DU; } } /* clear eof */
else sim_cancel (&pt_unit[PTR]); } /* clr, stop rdr */
else pt_sta = pt_sta & ~STA_DU; /* punch, clr eof */
break;
case IO_RD: /* read */
if (pt_run && !pt_slew) { /* incremental? */
sim_activate (&pt_unit[PTR], pt_unit[PTR].wait);
pt_sta = pt_sta & ~STA_DU; } /* clr eof */
pt_chp = 0; /* clr char pend */
if (pt_rd) pt_sta = pt_sta | STA_BSY; /* set busy */
return (pt_unit[PTR].buf & 0xFF); /* return char */
case IO_WD: /* write */
pt_unit[PTP].buf = dat & DMASK8; /* save char */
if (!pt_rd) pt_sta = pt_sta | STA_BSY; /* set busy */
sim_activate (&pt_unit[PTP], pt_unit[PTP].wait);
break;
case IO_SS: /* status */
t = pt_sta & STA_MASK; /* get status */
if (pt_rd && !pt_run && !sim_is_active (&pt_unit[PTR]))
t = t | STA_NMTN; /* stopped? */
if ((pt_unit[pt_rd? PTR: PTP].flags & UNIT_ATT) == 0)
t = t | STA_DU; /* offline? */
if (t & SET_EX) t = t | STA_EX; /* test for EX */
return t; }
return 0;
}
/* Unit service */
t_stat ptr_svc (UNIT *uptr)
{
uint32 temp;
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
if (pt_rd) { /* read mode? */
pt_sta = pt_sta & ~STA_BSY; /* clear busy */
if (pt_arm) SET_INT (v_PT); /* if armed, intr */
if (pt_chp) pt_sta = pt_sta | STA_OVR; } /* overrun? */
pt_chp = 1; /* char pending */
if ((temp = getc (uptr->fileref)) == EOF) { /* error? */
if (feof (uptr->fileref)) { /* eof? */
pt_sta = pt_sta | STA_DU; /* set DU */
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
uptr->buf = temp & DMASK8; /* store char */
uptr->pos = uptr->pos + 1; /* incr pos */
if (pt_slew) sim_activate (uptr, uptr->wait); /* slew? continue */
return SCPE_OK;
}
t_stat ptp_svc (UNIT *uptr)
{
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
if (!pt_rd) { /* write mode? */
pt_sta = pt_sta & ~STA_BSY; /* clear busy */
if (pt_arm) SET_INT (v_PT); } /* if armed, intr */
if (putc (uptr->buf, uptr -> fileref) == EOF) { /* write char */
perror ("PTP I/O error");
clearerr (uptr -> fileref);
return SCPE_IOERR; }
uptr -> pos = uptr -> pos + 1; /* incr pos */
return SCPE_OK;
}
/* Reset routine */
t_stat pt_reset (DEVICE *dptr)
{
sim_cancel (&pt_unit[PTR]); /* deactivate units */
sim_cancel (&pt_unit[PTP]);
pt_rd = 1; /* read */
pt_chp = pt_run = pt_slew = 0; /* stop, inc, disarm */
pt_sta = STA_BSY; /* buf empty */
CLR_INT (v_PT); /* clear int */
CLR_ENB (v_PT); /* disable int */
pt_arm = 0; /* disarm int */
return SCPE_OK;
}
/* Bootstrap routine */
#define BOOT_START 0x50
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
#define BOOT3_START 0x3E
#define BOOT3_LEN (sizeof (boot_rom) / sizeof (uint8))
static uint8 boot_rom[] = {
0xD5, 0x00, /* ST AL CF */
0x00, 0xCF,
0x43, 0x00, /* BR 80 */
0x00, 0x80
};
static uint8 boot3_rom[] = {
0xC8, 0x20, /* ST LHI 2,80 */
0x00, 0x80,
0xC8, 0x30, /* LHI 3,1 */
0x00, 0x01,
0xC8, 0x40, /* LHI 4,CF */
0x00, 0xCF,
0xD3, 0xA0, /* LB A,78 */
0x00, 0x78,
0xDE, 0xA0, /* OC A,79 */
0x00, 0x79,
0x9D, 0xAE, /* LP SSR A,E */
0x42, 0xF0, /* BTC F,LP */
0x00, 0x52,
0x9B, 0xAE, /* RDR A,E */
0x08, 0xEE, /* LHR E,E */
0x43, 0x30, /* BZ LP */
0x00, 0x52,
0x43, 0x00, /* BR STO */
0x00, 0x6C,
0x9D, 0xAE, /* LP1 SSR A,E */
0x42, 0xF0, /* BTC F,LP1 */
0x00, 0x64,
0x9B, 0xAE, /* RDR A,E */
0xD2, 0xE2, /* STO STB E,0(2) */
0x00, 0x00,
0xC1, 0x20, /* BXLE 2,LP1 */
0x00, 0x64,
0x43, 0x00, /* BR 80 */
0x00, 0x80
};
t_stat pt_boot (int32 unitno, DEVICE *dptr)
{
extern uint32 PC, dec_flgs;
extern uint16 decrom[];
if (decrom[0xD5] & dec_flgs) /* AL defined? */
IOWriteBlk (BOOT3_START, BOOT3_LEN, boot3_rom); /* no, 50 seq */
else IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy AL boot */
IOWriteB (AL_DEV, pt_dib.dno); /* set dev no */
IOWriteB (AL_IOC, 0x99); /* set dev cmd */
IOWriteB (AL_SCH, 0); /* clr sch dev no */
PC = BOOT_START;
return SCPE_OK;
}
/* Dump routine */
#define LOAD_START 0x80
#define LOAD_LO 0x8A
#define LOAD_HI 0x8E
#define LOAD_CS 0x93
#define LOAD_LEN (sizeof (load_rom) / sizeof (uint8))
#define LOAD_LDR 50
static uint8 load_rom[] = {
0x24, 0x21, /* BOOT LIS R2,1 */
0x23, 0x03, /* BS BOOT */
0x00, 0x00, /* 32b psw pointer */
0x00, 0x00, /* 32b reg pointer */
0xC8, 0x10, /* ST LHI R1,lo */
0x00, 0x00,
0xC8, 0x30, /* LHI R3,hi */
0x00, 0x00,
0xC8, 0x60, /* LHI R3,cs */
0x00, 0x00,
0xD3, 0x40, /* LB R4,X'78' */
0x00, 0x78,
0xDE, 0x40, /* OC R4,X'79' */
0x00, 0x79,
0x9D, 0x45, /* LDR SSR R4,R5 */
0x20, 0x91, /* BTBS 9,.-2 */
0x9B, 0x45, /* RDR R4,R5 */
0x08, 0x55, /* L(H)R R5,R5 */
0x22, 0x34, /* BZS LDR */
0xD2, 0x51, /* LOOP STB R5,0(R1) */
0x00, 0x00,
0x07, 0x65, /* X(H)R R6,R5 */
0x9A, 0x26, /* WDR R2,R6 */
0x9D, 0x45, /* SSR R4,R5 */
0x20, 0x91, /* BTBS 9,.-2 */
0x9B, 0x45, /* RDR R4,R5 */
0xC1, 0x10, /* BXLE R1,LOOP */
0x00, 0xA6,
0x24, 0x78, /* LIS R7,8 */
0x91, 0x7C, /* SLLS R7,12 */
0x95, 0x57, /* EPSR R5,R7 */
0x22, 0x03 /* BS .-6 */
};
t_stat pt_dump (FILE *of, char *cptr, char *fnam)
{
t_addr i, lo, hi;
uint32 cs;
char *tptr;
extern DEVICE cpu_dev;
if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG;
tptr = get_range (cptr, &lo, &hi, cpu_dev.aradix, 0xFFFF, 0);
if ((tptr == NULL) || (lo < INTSVT)) return SCPE_ARG;
if (*tptr != 0) return SCPE_2MARG;
for (i = lo, cs = 0; i <= hi; i++) cs = cs ^ IOReadB (i);
IOWriteBlk (LOAD_START, LOAD_LEN, load_rom);
IOWriteB (LOAD_LO, (lo >> 8) & 0xFF);
IOWriteB (LOAD_LO + 1, lo & 0xFF);
IOWriteB (LOAD_HI, (hi >> 8) & 0xFF);
IOWriteB (LOAD_HI + 1, hi & 0xFF);
IOWriteB (LOAD_CS, cs & 0xFF);
for (i = 0; i < LOAD_LDR; i++) fputc (0, of);
for (i = LOAD_START; i < (LOAD_START + LOAD_LEN); i++)
fputc (IOReadB (i), of);
for (i = 0; i < LOAD_LDR; i++) fputc (0, of);
for (i = lo; i <= hi; i++) fputc (IOReadB (i), of);
for (i = 0; i < LOAD_LDR; i++) fputc (0, of);
return SCPE_OK;
}

259
Interdata/id_tt.c Normal file
View file

@ -0,0 +1,259 @@
/* id_tt.c: Interdata teletype
Copyright (c) 2000-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.
tt console
11-Jan-03 RMS Added TTP support
22-Dec-02 RMS Added break support
*/
#include "id_defs.h"
#include <ctype.h>
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */
#define UNIT_8B (1 << UNIT_V_8B)
#define UNIT_KSR (1 << UNIT_V_KSR)
/* Device definitions */
#define TTI 0
#define TTO 1
#define STA_OVR 0x80 /* overrun */
#define STA_BRK 0x20 /* break */
#define STA_MASK (STA_OVR | STA_BRK | STA_BSY) /* status mask */
#define SET_EX (STA_OVR | STA_BRK) /* set EX */
#define CMD_V_FDPX 4 /* full/half duplex */
#define CMD_V_RD 2 /* read/write */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint32 tt_sta = STA_BSY; /* status */
uint32 tt_fdpx = 1; /* tt mode */
uint32 tt_rd = 1, tt_chp = 0; /* tt state */
uint32 tt_arm = 0; /* int arm */
uint32 tt (uint32 dev, uint32 op, uint32 dat);
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tt_reset (DEVICE *dptr);
t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat tt_set_break (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc);
/* TT data structures
tt_dev TT device descriptor
tt_unit TT unit descriptors
tt_reg TT register list
tt_mod TT modifiers list
*/
DIB tt_dib = { d_TT, -1, v_TT, NULL, &tt, NULL };
UNIT tt_unit[] = {
{ UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT },
{ UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT }
};
REG tt_reg[] = {
{ HRDATA (STA, tt_sta, 8) },
{ HRDATA (KBUF, tt_unit[TTI].buf, 8) },
{ DRDATA (KPOS, tt_unit[TTI].pos, 32), PV_LEFT },
{ DRDATA (KTIME, tt_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
{ HRDATA (TBUF, tt_unit[TTO].buf, 8) },
{ DRDATA (TPOS, tt_unit[TTO].pos, 32), PV_LEFT },
{ DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (IREQ, int_req[l_TT], i_TT) },
{ FLDATA (IENB, int_enb[l_TT], i_TT) },
{ FLDATA (IARM, tt_arm, 0) },
{ FLDATA (RD, tt_rd, 0) },
{ FLDATA (FDPX, tt_fdpx, 0) },
{ FLDATA (CHP, tt_chp, 0) },
{ HRDATA (DEVNO, tt_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB tt_mod[] = {
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tt_set_mode },
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tt_set_mode },
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tt_set_mode },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ENABLED",
&tt_set_enbdis, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, DEV_DIS, NULL, "DISABLED",
&tt_set_enbdis, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "BREAK",
&tt_set_break, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, &tt_dib },
{ 0 } };
DEVICE tt_dev = {
"TT", tt_unit, tt_reg, tt_mod,
2, 10, 31, 1, 16, 8,
NULL, NULL, &tt_reset,
NULL, NULL, NULL,
&tt_dib, 0 };
/* Terminal: IO routine */
uint32 tt (uint32 dev, uint32 op, uint32 dat)
{
uint32 old_rd, t;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_OC: /* command */
old_rd = tt_rd;
tt_arm = int_chg (v_TT, dat, tt_arm); /* upd int ctrl */
tt_fdpx = io_2b (dat, CMD_V_FDPX, tt_fdpx); /* upd full/half */
tt_rd = io_2b (dat, CMD_V_RD, tt_rd); /* upd rd/write */
if (tt_rd != old_rd) { /* rw change? */
if (tt_rd? tt_chp: !sim_is_active (&tt_unit[TTO])) {
tt_sta = 0; /* busy = 0 */
if (tt_arm) SET_INT (v_TT); } /* req intr */
else {
tt_sta = STA_BSY; /* busy = 1 */
CLR_INT (v_TT); } } /* clr int */
else tt_sta = tt_sta & ~STA_OVR; /* clr ovflo */
break;
case IO_RD: /* read */
tt_chp = 0; /* clear pend */
if (tt_rd) tt_sta = (tt_sta | STA_BSY) & ~STA_OVR;
return (tt_unit[TTI].buf & 0xFF);
case IO_WD: /* write */
tt_unit[TTO].buf = dat & 0xFF; /* save char */
if (!tt_rd) tt_sta = tt_sta | STA_BSY; /* set busy */
sim_activate (&tt_unit[TTO], tt_unit[TTO].wait);
break;
case IO_SS: /* status */
t = tt_sta & STA_MASK; /* get status */
if (t & SET_EX) t = t | STA_EX; /* test for EX */
return t; }
return 0;
}
/* Unit service routines */
t_stat tti_svc (UNIT *uptr)
{
int32 out, temp;
sim_activate (uptr, uptr->wait); /* continue poll */
tt_sta = tt_sta & ~STA_BRK; /* clear break */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
if (tt_rd) { /* read mode? */
tt_sta = tt_sta & ~STA_BSY; /* clear busy */
if (tt_arm) SET_INT (v_TT); /* if armed, intr */
if (tt_chp) tt_sta = tt_sta | STA_OVR; } /* got char? overrun */
tt_chp = 1; /* char pending */
out = temp & 0x7F; /* echo is 7B */
if (temp & SCPE_BREAK) { /* break? */
tt_sta = tt_sta | STA_BRK; /* set status */
uptr->buf = 0; } /* no character */
else if (uptr->flags & UNIT_KSR) { /* KSR mode? */
if (islower (out)) out = toupper (out); /* cvt to UC */
uptr->buf = out | 0x80; } /* set high bit */
else uptr->buf = temp & ((tt_unit[TTI].flags & UNIT_8B)? 0xFF: 0x7F);
uptr->pos = uptr->pos + 1; /* incr count */
if (!tt_fdpx) { /* half duplex? */
if (out) sim_putchar (out); /* write char */
tt_unit[TTO].pos = tt_unit[TTO].pos + 1; }
return SCPE_OK;
}
t_stat tto_svc (UNIT *uptr)
{
int32 ch;
t_stat r;
if (!tt_rd) { /* write mode? */
tt_sta = tt_sta & ~STA_BSY; /* clear busy */
if (tt_arm) SET_INT (v_TT); } /* if armed, intr */
if (uptr->flags & UNIT_KSR) { /* KSR mode? */
ch = uptr->buf & 0x7F; /* mask to 7b */
if (islower (ch)) ch = toupper (ch); } /* cvt to UC */
else ch = uptr->buf & ((tt_unit[TTO].flags & UNIT_8B)? 0xFF: 0x7F);
if (!(uptr->flags & UNIT_8B) && /* KSR or 7b? */
((ch == 0) || (ch == 0x7F))) return SCPE_OK; /* supr NULL, DEL */
if ((r = sim_putchar (ch)) != SCPE_OK) return r; /* output */
uptr->pos = uptr->pos + 1; /* incr count */
return SCPE_OK;
}
/* Reset routine */
t_stat tt_reset (DEVICE *dptr)
{
if (dptr->flags & DEV_DIS) sim_cancel (&tt_unit[TTI]); /* dis? cancel poll */
else sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* activate input */
sim_cancel (&tt_unit[TTO]); /* cancel output */
tt_rd = tt_fdpx = 1; /* read, full duplex */
tt_chp = 0; /* no char */
tt_sta = STA_BSY; /* buffer empty */
CLR_INT (v_TT); /* clear int */
CLR_ENB (v_TT); /* disable int */
tt_arm = 0; /* disarm int */
return SCPE_OK;
}
/* Make mode flags uniform */
t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
{
tt_unit[TTI].flags = (tt_unit[TTI].flags & ~(UNIT_KSR | UNIT_8B)) | val;
tt_unit[TTO].flags = (tt_unit[TTO].flags & ~(UNIT_KSR | UNIT_8B)) | val;
return SCPE_OK;
}
/* Set input break */
t_stat tt_set_break (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (tt_dev.flags & DEV_DIS) return SCPE_NOFNC;
tt_sta = tt_sta | STA_BRK;
if (tt_rd) { /* read mode? */
tt_sta = tt_sta & ~STA_BSY; /* clear busy */
if (tt_arm) SET_INT (v_TT); } /* if armed, intr */
sim_cancel (&tt_unit[TTI]); /* restart TT poll */
sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* so brk is seen */
return SCPE_OK;
}
/* Set enabled/disabled */
t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc)
{
extern DEVICE ttp_dev;
extern t_stat ttp_reset (DEVICE *dptr);
tt_dev.flags = (tt_dev.flags & ~DEV_DIS) | val;
ttp_dev.flags = (ttp_dev.flags & ~DEV_DIS) | (val ^ DEV_DIS);
tt_reset (&tt_dev);
ttp_reset (&ttp_dev);
return SCPE_OK;
}

263
Interdata/id_ttp.c Normal file
View file

@ -0,0 +1,263 @@
/* id_ttp.c: Interdata PASLA console interface
Copyright (c) 2000-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.
ttp console (on PAS)
*/
#include "id_defs.h"
#include <ctype.h>
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
#define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */
#define UNIT_8B (1 << UNIT_V_8B)
#define UNIT_UC (1 << UNIT_V_UC)
#define TTI 0
#define TTO 1
/* Status byte */
#define STA_OVR 0x80 /* overrun RO */
#define STA_PF 0x40 /* parity err RO */
#define STA_FR 0x20 /* framing err RO */
#define STA_RCV (STA_OVR|STA_PF|STA_FR)
#define SET_EX (STA_OVR|STA_PF|STA_FR)
#define STA_XMT (STA_BSY)
/* Command bytes 1,0 */
#define CMD_ECHO (0x10 << 8) /* echoplex */
#define CMD_WRT (0x02 << 8) /* write/read */
#define CMD_TYP 0x01 /* command type */
extern uint32 int_req[INTSZ], int_enb[INTSZ];
uint32 ttp_sta = 0; /* status */
uint32 ttp_cmd = 0; /* command */
uint32 ttp_kchp = 0; /* rcvr chr pend */
uint32 ttp_karm = 0; /* rcvr int armed */
uint32 ttp_tarm = 0; /* xmt int armed */
uint8 ttp_tplte[] = { 0, 1, TPL_END };
uint32 ttp (uint32 dev, uint32 op, uint32 dat);
t_stat ttpi_svc (UNIT *uptr);
t_stat ttpo_svc (UNIT *uptr);
t_stat ttp_reset (DEVICE *dptr);
t_stat ttp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ttp_set_break (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ttp_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc);
extern int32 pas_par (int32 cmd, int32 c);
/* TTP data structures */
DIB ttp_dib = { d_TTP, -1, v_TTP, ttp_tplte, &ttp, NULL };
UNIT ttp_unit[] = {
{ UDATA (&ttpi_svc, UNIT_UC, 0), KBD_POLL_WAIT },
{ UDATA (&ttpo_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }
};
REG ttp_reg[] = {
{ HRDATA (CMD, ttp_cmd, 16) },
{ HRDATA (KBUF, ttp_unit[TTI].buf, 8) },
{ DRDATA (KPOS, ttp_unit[TTI].pos, 32), PV_LEFT },
{ DRDATA (KTIME, ttp_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (KIREQ, int_req[l_TTP], i_TTP) },
{ FLDATA (KIENB, int_enb[l_TTP], i_TTP) },
{ FLDATA (KARM, ttp_karm, 0) },
{ FLDATA (CHP, ttp_kchp, 0) },
{ HRDATA (TBUF, ttp_unit[TTO].buf, 8) },
{ DRDATA (TPOS, ttp_unit[TTO].pos, 32), PV_LEFT },
{ DRDATA (TTIME, ttp_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (TIREQ, int_req[l_TTP], i_TTP + 1) },
{ FLDATA (TIENB, int_enb[l_TTP], i_TTP + 1) },
{ FLDATA (TARM, ttp_tarm, 0) },
{ HRDATA (DEVNO, ttp_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB ttp_mod[] = {
{ UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", &ttp_set_mode },
{ UNIT_UC+UNIT_8B, 0 , "7b", "7B", &ttp_set_mode },
{ UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", &ttp_set_mode },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ENABLED",
&ttp_set_enbdis, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, DEV_DIS, NULL, "DISABLED",
&ttp_set_enbdis, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "BREAK",
&ttp_set_break, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
DEVICE ttp_dev = {
"TTP", ttp_unit, ttp_reg, ttp_mod,
2, 10, 31, 1, 16, 8,
NULL, NULL, &ttp_reset,
NULL, NULL, NULL,
&ttp_dib, DEV_DIS };
/* Terminal: I/O routine */
uint32 ttp (uint32 dev, uint32 op, uint32 dat)
{
int32 xmt = dev & 1;
int32 t, old_cmd;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_RD: /* read */
ttp_kchp = 0; /* clr chr pend */
ttp_sta = ttp_sta & ~STA_OVR; /* clr overrun */
return ttp_unit[TTI].buf; /* return buf */
case IO_WD: /* write */
ttp_unit[TTO].buf = dat & 0xFF; /* store char */
ttp_sta = ttp_sta | STA_BSY; /* set busy */
sim_activate (&ttp_unit[TTO], ttp_unit[TTO].wait);
break;
case IO_SS: /* status */
if (xmt) t = ttp_sta & STA_XMT; /* xmt? Just busy */
else { /* rcv */
t = ttp_sta & STA_RCV; /* get static */
if (!ttp_kchp) t = t | STA_BSY; /* no char? busy */
if (t & SET_EX) t = t | STA_EX; } /* test for ex */
return t;
case IO_OC: /* command */
old_cmd = ttp_cmd; /* old cmd */
if (dat & CMD_TYP) { /* type 1? */
ttp_cmd = (ttp_cmd & 0xFF) | (dat << 8);
if (ttp_cmd & CMD_WRT) /* write? */
ttp_tarm = int_chg (v_TTP + 1, dat, ttp_tarm);
else ttp_karm = int_chg (v_TTP, dat, ttp_karm); }
else ttp_cmd = (ttp_cmd & ~0xFF) | dat;
break; }
return 0;
}
/* Unit service */
t_stat ttpi_svc (UNIT *uptr)
{
int32 c, out;
sim_activate (uptr, uptr->wait); /* continue poll */
ttp_sta = ttp_sta & ~STA_FR; /* clear break */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
ttp_sta = ttp_sta & ~STA_PF; /* clear parity err */
if (ttp_kchp) ttp_sta = ttp_sta | STA_OVR; /* overrun? */
if (ttp_karm) SET_INT (v_TTP);
if (c & SCPE_BREAK) { /* break? */
ttp_sta = ttp_sta | STA_FR; /* framing error */
uptr->buf = 0; } /* no character */
else { c = c & 0xFF; /* char is 8b */
out = c & 0x7F; /* echo is 7b */
if (!(uptr->flags & UNIT_8B)) { /* not 8b? */
if ((uptr->flags & UNIT_UC) && islower (out))
out = toupper (out); /* cvt to UC */
c = pas_par (ttp_cmd, out); } /* apply parity */
uptr->buf = c; /* save char */
uptr->pos = uptr->pos + 1; /* incr count */
ttp_kchp = 1; /* char pending */
if (ttp_cmd & CMD_ECHO) {
sim_putchar (out);
ttp_unit[TTO].pos = ttp_unit[TTO].pos + 1; } }
return SCPE_OK;
}
t_stat ttpo_svc (UNIT *uptr)
{
int32 c;
t_stat r;
ttp_sta = ttp_sta & ~STA_BSY; /* not busy */
if (ttp_tarm) SET_INT (v_TTP + 1); /* set intr */
if (uptr->flags & UNIT_8B) /* 8b? */
c = pas_par (ttp_cmd, uptr->buf); /* apply parity */
else { c = uptr->buf & 0x7F; /* mask char */
if ((uptr->flags & UNIT_UC) && islower (c))
c = toupper (c); } /* cvt to UC */
if (!(uptr->flags & UNIT_8B) && /* UC or 7b? */
((c == 0) || (c == 0x7F))) return SCPE_OK; /* supr NULL, DEL */
if ((r = sim_putchar (c)) != SCPE_OK) return r; /* output */
uptr->pos = uptr->pos + 1; /* incr count */
return SCPE_OK;
}
/* Reset routine */
t_stat ttp_reset (DEVICE *dptr)
{
extern DEVICE tt_dev;
if (dptr->flags & DEV_DIS) sim_cancel (&ttp_unit[TTI]);
else sim_activate (&ttp_unit[TTI], ttp_unit[TTI].wait);
sim_cancel (&ttp_unit[TTO]);
CLR_INT (v_TTP); /* clear int */
CLR_ENB (v_TTP);
CLR_INT (v_TTP + 1); /* disable int */
CLR_ENB (v_TTP + 1);
ttp_karm = ttp_tarm = 0; /* disarm int */
ttp_cmd = 0;
ttp_sta = 0;
ttp_kchp = 0;
return SCPE_OK;
}
/* Make mode flags uniform */
t_stat ttp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
{
ttp_unit[TTI].flags = (ttp_unit[TTI].flags & ~(UNIT_UC | UNIT_8B)) | val;
ttp_unit[TTO].flags = (ttp_unit[TTO].flags & ~(UNIT_UC | UNIT_8B)) | val;
return SCPE_OK;
}
/* Set input break */
t_stat ttp_set_break (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (ttp_dev.flags & DEV_DIS) return SCPE_NOFNC;
ttp_sta = ttp_sta | STA_FR;
if (ttp_karm) SET_INT (v_TTP); /* if armed, intr */
sim_cancel (&ttp_unit[TTI]); /* restart TT poll */
sim_activate (&ttp_unit[TTI], ttp_unit[TTI].wait);
return SCPE_OK;
}
/* Set enabled/disabled */
t_stat ttp_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc)
{
extern DEVICE tt_dev;
extern t_stat tt_reset (DEVICE *dptr);
ttp_dev.flags = (ttp_dev.flags & ~DEV_DIS) | val;
tt_dev.flags = (tt_dev.flags & ~DEV_DIS) | (val ^ DEV_DIS);
ttp_reset (&ttp_dev);
tt_reset (&tt_dev);
return SCPE_OK;
}

311
Interdata/id_uvc.c Normal file
View file

@ -0,0 +1,311 @@
/* id_uvc.c: Interdata universal clock
Copyright (c) 2001-2002, 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.
pic precision incremental clock
lfc line frequency clock
*/
#include "id_defs.h"
#include <ctype.h>
/* Device definitions */
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diag mode */
#define UNIT_DIAG (1 << UNIT_V_DIAG)
#define STA_OVF 0x08 /* PIC overflow */
#define CMD_STRT 0x20 /* start */
#define PIC_V_RATE 12 /* rate */
#define PIC_M_RATE 0xF
#define PIC_RATE (PIC_M_RATE << PIC_V_RATE)
#define PIC_CTR 0x0FFF /* PIC counters */
#define GET_RATE(x) (((x) >> PIC_V_RATE) & PIC_M_RATE)
#define GET_CTR(x) ((x) & PIC_CTR)
#define PIC_TPS 1000
extern uint32 int_req[INTSZ], int_enb[INTSZ];
int32 pic_db = 0; /* output buf */
int32 pic_ric = 0; /* reset count */
int32 pic_cic = 0; /* current count */
uint32 pic_save = 0; /* saved time */
uint32 pic_ovf = 0; /* overflow */
uint32 pic_rdp = 0;
uint32 pic_wdp = 0;
uint32 pic_cnti = 0; /* instr/timer */
uint32 pic_arm = 0; /* int arm */
uint16 pic_time[4] = { 1, 10, 100, 1000 }; /* delays */
static int32 pic_map[16] = { /* map rate to delay */
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
DEVICE pic_dev;
uint32 pic (uint32 dev, uint32 op, uint32 dat);
t_stat pic_svc (UNIT *uptr);
t_stat pic_reset (DEVICE *dptr);
void pic_sched (t_bool strt);
uint32 pic_rd_cic (void);
int32 lfc_tps = 120; /* ticks per */
uint32 lfc_arm = 0; /* int arm */
DEVICE lfc_dev;
uint32 lfc (uint32 dev, uint32 op, uint32 dat);
t_stat lfc_svc (UNIT *uptr);
t_stat lfc_reset (DEVICE *dptr);
/* PIC data structures
pic_dev PIC device descriptor
pic_unit PIC unit descriptor
pic_reg PIC register list
*/
DIB pic_dib = { d_PIC, -1, v_PIC, NULL, &pic, NULL };
UNIT pic_unit = { UDATA (&pic_svc, 0, 0), 1000 };
REG pic_reg[] = {
{ HRDATA (BUF, pic_db, 16) },
{ HRDATA (RIC, pic_ric, 16) },
{ HRDATA (CIC, pic_cic, 12) },
{ DRDATA (SAVE, pic_save, 32), REG_HRO + PV_LEFT },
{ FLDATA (RDP, pic_rdp, 0) },
{ FLDATA (WDP, pic_wdp, 0) },
{ FLDATA (OVF, pic_ovf, 0) },
{ FLDATA (IREQ, int_req[l_PIC], i_PIC) },
{ FLDATA (IENB, int_enb[l_PIC], i_PIC) },
{ FLDATA (IARM, pic_arm, 0) },
{ BRDATA (TIME, pic_time, 10, 16, 4), REG_NZ + PV_LEFT },
{ HRDATA (DEVNO, pic_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB pic_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
{ UNIT_DIAG, 0, NULL, "NORMAL", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
DEVICE pic_dev = {
"PIC", &pic_unit, pic_reg, pic_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &pic_reset,
NULL, NULL, NULL,
&pic_dib, DEV_DISABLE };
/* LFC data structures
lfc_dev LFC device descriptor
lfc_unit LFC unit descriptor
lfc_reg LFC register list
*/
DIB lfc_dib = { d_LFC, -1, v_LFC, NULL, &lfc, NULL };
UNIT lfc_unit = { UDATA (&lfc_svc, 0, 0), 8333 };
REG lfc_reg[] = {
{ FLDATA (IREQ, int_req[l_LFC], i_LFC) },
{ FLDATA (IENB, int_enb[l_LFC], i_LFC) },
{ FLDATA (IARM, lfc_arm, 0) },
{ DRDATA (TIME, lfc_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, lfc_tps, 8), REG_NZ + PV_LEFT },
{ HRDATA (DEVNO, lfc_dib.dno, 8), REG_HRO },
{ NULL } };
MTAB lfc_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
DEVICE lfc_dev = {
"LFC", &lfc_unit, lfc_reg, lfc_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &lfc_reset,
NULL, NULL, NULL,
&lfc_dib, DEV_DISABLE };
/* Precision clock: IO routine */
uint32 pic (uint32 dev, uint32 op, uint32 dat)
{
int32 t;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return HW; /* HW capable */
case IO_RH: /* read halfword */
pic_rdp = 0; /* clr ptr */
return pic_rd_cic ();
case IO_RD: /* read */
t = pic_rd_cic (); /* get cic */
if (pic_rdp) t = t & DMASK8; /* 2nd? get lo */
else t = (t >> 8) & DMASK8; /* 1st? get hi */
pic_rdp = pic_rdp ^ 1; /* flip byte ptr */
return t;
case IO_WH: /* write halfword */
pic_wdp = 0; /* clr ptr */
pic_db = dat;
break;
case IO_WD: /* write */
if (pic_wdp) pic_db = (pic_db & 0xFF00) | dat;
else pic_db = (pic_db & 0xFF) | (dat << 8);
pic_wdp = pic_wdp ^ 1; /* flip byte ptr */
break;
case IO_SS: /* sense status */
if (pic_ovf) { /* overflow? */
pic_ovf = 0; /* clear flag */
CLR_INT (v_PIC); /* clear intr */
return STA_OVF; }
return 0;
case IO_OC: /* output cmd */
pic_arm = int_chg (v_PIC, dat, pic_arm); /* upd int ctrl */
if (dat & CMD_STRT) { /* start? */
pic_ric = pic_db; /* new ric */
pic_cic = GET_CTR (pic_ric); /* new cic */
pic_ovf = 0; /* clear flag */
sim_cancel (&pic_unit); /* stop clock */
pic_rdp = pic_wdp = 0; /* init ptrs */
if (pic_ric & PIC_RATE) pic_sched (TRUE); /* any rate? */
} /* end if start */
break; } /* end case */
return 0;
}
/* Unit service */
t_stat pic_svc (UNIT *uptr)
{
t_bool rate_chg = FALSE;
if (pic_cnti) pic_cic = -1; /* one shot? */
pic_cic = pic_cic - 1; /* decrement */
if (pic_cic < 0) { /* overflow? */
if (pic_wdp) pic_ovf = 1; /* broken wr? set flag */
if (pic_arm) SET_INT (v_PIC); /* if armed, intr */
if (GET_RATE (pic_ric) != GET_RATE (pic_db)) /* rate change? */
rate_chg = TRUE;
pic_ric = pic_db; /* new ric */
pic_cic = GET_CTR (pic_ric); /* new cic */
if ((pic_ric & PIC_RATE) == 0) return SCPE_OK; }
pic_sched (rate_chg);
return SCPE_OK;
}
/* Schedule next interval
If rate < 1ms, or diagnostic mode, count instructions
If rate = 1ms, and not diagnostic mode, use timer
*/
void pic_sched (t_bool strt)
{
int32 r, t;
pic_save = sim_grtime (); /* save start */
r = pic_map[GET_RATE (pic_ric)]; /* get mapped rate */
t = pic_time[r]; /* get delay */
if ((r == 3) && !(pic_unit.flags & UNIT_DIAG)) { /* timer? */
pic_cnti = 0; /* clr mode */
if (strt) t = sim_rtcn_init (t, TMR_PIC); /* init or */
else t = sim_rtcn_calb (PIC_TPS, TMR_PIC); } /* calibrate */
else { pic_cnti = 1; /* set mode */
t = t * (pic_cic + 1); /* interval */
if (t == 1) t++; } /* for diagn */
sim_activate (&pic_unit, t); /* activate */
return;
}
/* Read (interpolated) current interval */
uint32 pic_rd_cic (void)
{
if (sim_is_active (&pic_unit) && pic_cnti) { /* running, one shot? */
uint32 delta = sim_grtime () - pic_save; /* interval */
uint32 tm = pic_time[pic_map[GET_RATE (pic_ric)]]; /* ticks/intv */
delta = delta / tm; /* ticks elapsed */
if (delta >= ((uint32) pic_cic)) return 0; /* cap value */
return pic_cic - delta; }
return pic_cic;
}
/* Reset routine */
t_stat pic_reset (DEVICE *dptr)
{
sim_cancel (&pic_unit); /* cancel unit */
pic_ric = pic_cic = 0;
pic_db = 0;
pic_ovf = 0; /* clear state */
pic_cnti = 0;
pic_rdp = pic_wdp = 0;
CLR_INT (v_PIC); /* clear int */
CLR_ENB (v_PIC); /* disable int */
pic_arm = 0; /* disarm int */
return SCPE_OK;
}
/* Line clock: IO routine */
uint32 lfc (uint32 dev, uint32 op, uint32 dat)
{
int32 t;
switch (op) { /* case IO op */
case IO_ADR: /* select */
return BY; /* byte only */
case IO_OC: /* command */
lfc_arm = int_chg (v_LFC, dat, lfc_arm); /* upd int ctrl */
if (lfc_arm && !sim_is_active (&lfc_unit)) { /* starting? */
t = sim_rtcn_init (lfc_unit.wait, TMR_LFC);
sim_activate (&lfc_unit, t); } /* init clock */
break; }
return 0;
}
/* Unit service */
t_stat lfc_svc (UNIT *uptr)
{
int32 t;
if (lfc_arm) { /* armed? */
SET_INT (v_LFC); /* req intr */
if (pic_unit.flags & UNIT_DIAG) t = uptr->wait; /* diag? fixed delay */
else t = sim_rtcn_calb (lfc_tps, TMR_LFC); /* else calibrate */
sim_activate (uptr, t); } /* reactivate */
return SCPE_OK;
}
/* Reset routine */
t_stat lfc_reset (DEVICE *dptr)
{
sim_cancel (&lfc_unit); /* cancel unit */
CLR_INT (v_LFC); /* clear int */
CLR_ENB (v_LFC); /* disable int */
lfc_arm = 0; /* disarm int */
return SCPE_OK;
}

View file

@ -26,7 +26,7 @@ t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat ttx_setmod (UNIT *uptr, int32 value);
t_stat ttx_setmod (UNIT *uptr, int32 value, char *cptr, void *desc);
void translate_in();
int32 translate_out(int32 c);
int32 putseq(char *seq);
@ -386,7 +386,7 @@ sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ttx_setmod (UNIT *uptr, int32 value)
t_stat ttx_setmod (UNIT *uptr, int32 value, char *cptr, void *desc)
{
tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | value;
tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | value;

View file

@ -89,8 +89,8 @@ case iopS: /* start */
dev_done = dev_done & ~INT_CLK; /* clear done, int */
int_req = int_req & ~INT_CLK;
if (!sim_is_active (&clk_unit)) /* not running? */
sim_activate (&clk_unit, /* activate */
sim_rtc_init (clk_time[clk_sel])); /* init calibr */
sim_activate (&clk_unit, /* activate */
sim_rtc_init (clk_time[clk_sel])); /* init calibr */
break;
case iopC: /* clear */
dev_busy = dev_busy & ~INT_CLK; /* clear busy */

View file

@ -348,14 +348,14 @@ if (int_req > INT_PENDING) { /* interrupt? */
PCQ_ENTRY; /* save old PC */
M[INT_SAV] = PC;
if (int_req & INT_STK) { /* stack overflow? */
int_req = int_req & ~INT_STK; /* clear */
MA = STK_JMP; } /* jmp @3 */
int_req = int_req & ~INT_STK; /* clear */
MA = STK_JMP; } /* jmp @3 */
else MA = INT_JMP; /* intr: jmp @1 */
for (i = 0, indf = 1; indf && (i < ind_max); i++) {
indf = IND_STEP (MA); } /* indirect loop */
indf = IND_STEP (MA); } /* indirect loop */
if (i >= ind_max) {
reason = STOP_IND_INT;
break; }
reason = STOP_IND_INT;
break; }
PC = MA; } /* end interrupt */
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
@ -375,96 +375,96 @@ if (IR & I_OPR) { /* operate? */
dstAC = I_GETDST (IR);
switch (I_GETCRY (IR)) { /* decode carry */
case 0: /* load */
src = AC[srcAC] | C;
break;
src = AC[srcAC] | C;
break;
case 1: /* clear */
src = AC[srcAC];
break;
src = AC[srcAC];
break;
case 2: /* set */
src = AC[srcAC] | CBIT;
break;
src = AC[srcAC] | CBIT;
break;
case 3: /* complement */
src = AC[srcAC] | (C ^ CBIT);
break; } /* end switch carry */
src = AC[srcAC] | (C ^ CBIT);
break; } /* end switch carry */
switch (I_GETALU (IR)) { /* decode ALU */
case 0: /* COM */
src = src ^ DMASK;
break;
src = src ^ DMASK;
break;
case 1: /* NEG */
src = ((src ^ DMASK) + 1) & CMASK;
break;
src = ((src ^ DMASK) + 1) & CMASK;
break;
case 2: /* MOV */
break;
break;
case 3: /* INC */
src = (src + 1) & CMASK;
break;
src = (src + 1) & CMASK;
break;
case 4: /* ADC */
src = ((src ^ DMASK) + AC[dstAC]) & CMASK;
break;
src = ((src ^ DMASK) + AC[dstAC]) & CMASK;
break;
case 5: /* SUB */
src = ((src ^ DMASK) + AC[dstAC] + 1) & CMASK;
break;
src = ((src ^ DMASK) + AC[dstAC] + 1) & CMASK;
break;
case 6: /* ADD */
src = (src + AC[dstAC]) & CMASK;
break;
src = (src + AC[dstAC]) & CMASK;
break;
case 7: /* AND */
src = src & (AC[dstAC] | CBIT);
break; } /* end switch oper */
src = src & (AC[dstAC] | CBIT);
break; } /* end switch oper */
/* Operate, continued */
switch (I_GETSHF (IR)) { /* decode shift */
case 0: /* nop */
break;
break;
case 1: /* L */
src = ((src << 1) | (src >> 16)) & CMASK;
break;
src = ((src << 1) | (src >> 16)) & CMASK;
break;
case 2: /* R */
src = ((src >> 1) | (src << 16)) & CMASK;
break;
src = ((src >> 1) | (src << 16)) & CMASK;
break;
case 3: /* S */
src = ((src & 0377) << 8) | ((src >> 8) & 0377) |
(src & CBIT);
break; } /* end switch shift */
src = ((src & 0377) << 8) | ((src >> 8) & 0377) |
(src & CBIT);
break; } /* end switch shift */
switch (I_GETSKP (IR)) { /* decode skip */
case 0: /* nop */
if ((IR & I_NLD) && (cpu_unit.flags & UNIT_STK)) {
int32 indf, MA; /* Nova 3 or 4 trap */
PCQ_ENTRY; /* save old PC */
M[TRP_SAV] = (PC - 1) & AMASK;
MA = TRP_JMP; /* jmp @47 */
for (i = 0, indf = 1; indf && (i < ind_max); i++) {
indf = IND_STEP (MA); } /* resolve ind */
if (i >= ind_max) { /* indirect loop? */
reason = STOP_IND_TRP;
break; }
PC = MA; /* new PC */
break; }
break;
if ((IR & I_NLD) && (cpu_unit.flags & UNIT_STK)) {
int32 indf, MA; /* Nova 3 or 4 trap */
PCQ_ENTRY; /* save old PC */
M[TRP_SAV] = (PC - 1) & AMASK;
MA = TRP_JMP; /* jmp @47 */
for (i = 0, indf = 1; indf && (i < ind_max); i++) {
indf = IND_STEP (MA); } /* resolve ind */
if (i >= ind_max) { /* indirect loop? */
reason = STOP_IND_TRP;
break; }
PC = MA; /* new PC */
break; }
break;
case 1: /* SKP */
PC = (PC + 1) & AMASK;
break;
PC = (PC + 1) & AMASK;
break;
case 2: /* SZC */
if (src < CBIT) PC = (PC + 1) & AMASK;
break;
if (src < CBIT) PC = (PC + 1) & AMASK;
break;
case 3: /* SNC */
if (src >= CBIT) PC = (PC + 1) & AMASK;
break;
if (src >= CBIT) PC = (PC + 1) & AMASK;
break;
case 4: /* SZR */
if ((src & DMASK) == 0) PC = (PC + 1) & AMASK;
break;
if ((src & DMASK) == 0) PC = (PC + 1) & AMASK;
break;
case 5: /* SNR */
if ((src & DMASK) != 0) PC = (PC + 1) & AMASK;
break;
if ((src & DMASK) != 0) PC = (PC + 1) & AMASK;
break;
case 6: /* SEZ */
if (src <= CBIT) PC = (PC + 1) & AMASK;
break;
if (src <= CBIT) PC = (PC + 1) & AMASK;
break;
case 7: /* SBN */
if (src > CBIT) PC = (PC + 1) & AMASK;
break; } /* end switch skip */
if (src > CBIT) PC = (PC + 1) & AMASK;
break; } /* end switch skip */
if ((IR & I_NLD) == 0) { /* load? */
AC[dstAC] = src & DMASK;
C = src & CBIT; } /* end if load */
AC[dstAC] = src & DMASK;
C = src & CBIT; } /* end if load */
} /* end if operate */
/* Memory reference instructions */
@ -474,70 +474,70 @@ else if (IR < 060000) { /* mem ref? */
MA = I_GETDISP (IR); /* get disp */
switch (I_GETMODE (IR)) { /* decode mode */
case 0: /* page zero */
break;
break;
case 1: /* PC relative */
if (MA & DISPSIGN) MA = 077400 | MA;
MA = (MA + PC - 1) & AMASK;
break;
if (MA & DISPSIGN) MA = 077400 | MA;
MA = (MA + PC - 1) & AMASK;
break;
case 2: /* AC2 relative */
if (MA & DISPSIGN) MA = 077400 | MA;
MA = (MA + AC[2]) & AMASK;
break;
if (MA & DISPSIGN) MA = 077400 | MA;
MA = (MA + AC[2]) & AMASK;
break;
case 3: /* AC3 relative */
if (MA & DISPSIGN) MA = 077400 | MA;
MA = (MA + AC[3]) & AMASK;
break; } /* end switch mode */
if (MA & DISPSIGN) MA = 077400 | MA;
MA = (MA + AC[3]) & AMASK;
break; } /* end switch mode */
if (indf = IR & I_IND) { /* indirect? */
for (i = 0; indf && (i < ind_max); i++) { /* count */
indf = IND_STEP (MA); } /* resolve indirect */
if (i >= ind_max) { /* too many? */
reason = STOP_IND;
break; } }
for (i = 0; indf && (i < ind_max); i++) { /* count */
indf = IND_STEP (MA); } /* resolve indirect */
if (i >= ind_max) { /* too many? */
reason = STOP_IND;
break; } }
/* Memory reference, continued */
switch (I_GETOPAC (IR)) { /* decode op + AC */
case 001: /* JSR */
AC[3] = PC;
AC[3] = PC;
case 000: /* JMP */
PCQ_ENTRY;
PC = MA;
break;
PCQ_ENTRY;
PC = MA;
break;
case 002: /* ISZ */
src = (M[MA] + 1) & DMASK;
if (MEM_ADDR_OK (MA)) M[MA] = src;
if (src == 0) PC = (PC + 1) & AMASK;
break;
src = (M[MA] + 1) & DMASK;
if (MEM_ADDR_OK (MA)) M[MA] = src;
if (src == 0) PC = (PC + 1) & AMASK;
break;
case 003: /* DSZ */
src = (M[MA] - 1) & DMASK;
if (MEM_ADDR_OK (MA)) M[MA] = src;
if (src == 0) PC = (PC + 1) & AMASK;
break;
src = (M[MA] - 1) & DMASK;
if (MEM_ADDR_OK (MA)) M[MA] = src;
if (src == 0) PC = (PC + 1) & AMASK;
break;
case 004: /* LDA 0 */
AC[0] = M[MA];
break;
AC[0] = M[MA];
break;
case 005: /* LDA 1 */
AC[1] = M[MA];
break;
AC[1] = M[MA];
break;
case 006: /* LDA 2 */
AC[2] = M[MA];
break;
AC[2] = M[MA];
break;
case 007: /* LDA 3 */
AC[3] = M[MA];
break;
AC[3] = M[MA];
break;
case 010: /* STA 0 */
if (MEM_ADDR_OK (MA)) M[MA] = AC[0];
break;
if (MEM_ADDR_OK (MA)) M[MA] = AC[0];
break;
case 011: /* STA 1 */
if (MEM_ADDR_OK (MA)) M[MA] = AC[1];
break;
if (MEM_ADDR_OK (MA)) M[MA] = AC[1];
break;
case 012: /* STA 2 */
if (MEM_ADDR_OK (MA)) M[MA] = AC[2];
break;
if (MEM_ADDR_OK (MA)) M[MA] = AC[2];
break;
case 013: /* STA 3 */
if (MEM_ADDR_OK (MA)) M[MA] = AC[3];
break; } /* end switch */
if (MEM_ADDR_OK (MA)) M[MA] = AC[3];
break; } /* end switch */
} /* end mem ref */
/* IOT instruction */
@ -549,200 +549,199 @@ else { /* IOT */
pulse = I_GETPULSE (IR);
device = I_GETDEV (IR);
if (code == ioSKP) { /* IO skip? */
switch (pulse) { /* decode IR<8:9> */
case 0: /* skip if busy */
if ((device == DEV_CPU)? (int_req & INT_ION) != 0:
(dev_busy & dev_table[device].mask) != 0)
PC = (PC + 1) & AMASK;
break;
case 1: /* skip if not busy */
if ((device == DEV_CPU)? (int_req & INT_ION) == 0:
(dev_busy & dev_table[device].mask) == 0)
PC = (PC + 1) & AMASK;
break;
case 2: /* skip if done */
if ((device == DEV_CPU)? pwr_low != 0:
(dev_done & dev_table[device].mask) != 0)
PC = (PC + 1) & AMASK;
break;
case 3: /* skip if not done */
if ((device == DEV_CPU)? pwr_low == 0:
(dev_done & dev_table[device].mask) == 0)
PC = (PC + 1) & AMASK;
break; } /* end switch */
} /* end IO skip */
switch (pulse) { /* decode IR<8:9> */
case 0: /* skip if busy */
if ((device == DEV_CPU)? (int_req & INT_ION) != 0:
(dev_busy & dev_table[device].mask) != 0)
PC = (PC + 1) & AMASK;
break;
case 1: /* skip if not busy */
if ((device == DEV_CPU)? (int_req & INT_ION) == 0:
(dev_busy & dev_table[device].mask) == 0)
PC = (PC + 1) & AMASK;
break;
case 2: /* skip if done */
if ((device == DEV_CPU)? pwr_low != 0:
(dev_done & dev_table[device].mask) != 0)
PC = (PC + 1) & AMASK;
break;
case 3: /* skip if not done */
if ((device == DEV_CPU)? pwr_low == 0:
(dev_done & dev_table[device].mask) == 0)
PC = (PC + 1) & AMASK;
break; } /* end switch */
} /* end IO skip */
/* IOT, continued */
else if (device == DEV_MDV) {
switch (code) { /* case on opcode */
case ioNIO: /* frame ptr */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) FP = AC[dstAC] & AMASK;
if (pulse == iopC) AC[dstAC] = FP; }
break;
case ioDIA: /* load byte */
if (cpu_unit.flags & UNIT_BYT)
AC[dstAC] = (M[AC[pulse] >> 1] >>
((AC[pulse] & 1)? 0: 8)) & 0377;
else AC[dstAC] = 0;
break;
case ioDOA: /* stack ptr */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) SP = AC[dstAC] & AMASK;
if (pulse == iopC) AC[dstAC] = SP; }
break;
case ioDIB: /* push, pop */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) { /* push */
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC];
STK_CHECK (SP, 1); }
if (pulse == iopC) { /* pop */
AC[dstAC] = M[SP];
SP = DECA (SP); }
if ((pulse == iopP) && /* Nova 4 pshn */
(cpu_unit.flags & UNIT_BYT)) {
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC];
if (SP > M[042]) int_req = int_req | INT_STK ;
}
}
break;
case ioDOB: /* store byte */
if (cpu_unit.flags & UNIT_BYT) {
int32 MA, val;
MA = AC[pulse] >> 1;
val = AC[dstAC] & 0377;
if (MEM_ADDR_OK (MA)) M[MA] = (AC[pulse] & 1)?
((M[MA] & ~0377) | val):
((M[MA] & 0377) | (val << 8)); }
break;
case ioDIC: /* save, return */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) { /* save */
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[0];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[1];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[2];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = FP;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) |
(AC[3] & AMASK);
AC[3] = FP = SP & AMASK;
STK_CHECK (SP, 5); }
if (pulse == iopC) { /* retn */
PCQ_ENTRY;
SP = FP & AMASK;
C = (M[SP] << 1) & CBIT;
PC = M[SP] & AMASK;
SP = DECA (SP);
AC[3] = M[SP];
SP = DECA (SP);
AC[2] = M[SP];
SP = DECA (SP);
AC[1] = M[SP];
SP = DECA (SP);
AC[0] = M[SP];
SP = DECA (SP);
FP = AC[3] & AMASK; }
if ((pulse == iopP) && /* Nova 4 saven */
(cpu_unit.flags & UNIT_BYT)) {
int32 frameSz = M[PC] ;
PC = INCA (PC) ;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[0];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[1];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[2];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = FP;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) |
(AC[3] & AMASK);
AC[3] = FP = SP & AMASK ;
SP = (SP + frameSz) & AMASK ;
if (SP > M[042]) int_req = int_req | INT_STK;
}
}
break;
case ioDOC:
if ((dstAC == 2) && (cpu_unit.flags & UNIT_MDV)) {
uint32 mddata, uAC0, uAC1, uAC2;
uAC0 = (unsigned int32) AC[0];
uAC1 = (unsigned int32) AC[1];
uAC2 = (unsigned int32) AC[2];
if (pulse == iopP) { /* mul */
mddata = (uAC1 * uAC2) + uAC0;
AC[0] = (mddata >> 16) & DMASK;
AC[1] = mddata & DMASK; }
if (pulse == iopS) { /* div */
if ((uAC0 >= uAC2) || (uAC2 == 0))
C = CBIT;
else { C = 0;
mddata = (uAC0 << 16) | uAC1;
AC[1] = mddata / uAC2;
AC[0] = mddata % uAC2; } } }
if ((dstAC == 3) && (cpu_unit.flags & UNIT_BYT)) {
int32 mddata;
if (pulse == iopC) { /* muls */
mddata = (SEXT (AC[1]) * SEXT (AC[2])) +
SEXT (AC[0]);
AC[0] = (mddata >> 16) & DMASK;
AC[1] = mddata & DMASK; }
if (pulse == iopN) { /* divs */
if (AC[2] == 0) C = CBIT;
else { mddata = (SEXT (AC[0]) << 16) | AC[1];
AC[1] = mddata / SEXT (AC[2]);
AC[0] = mddata % SEXT (AC[2]);
if ((AC[1] > 077777) || (AC[1] < -0100000))
C = CBIT;
else C = 0;
AC[0] = AC[0] & DMASK; } } }
break; } /* end case code */
} /* end if mul/div */
switch (code) { /* case on opcode */
case ioNIO: /* frame ptr */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) FP = AC[dstAC] & AMASK;
if (pulse == iopC) AC[dstAC] = FP; }
break;
case ioDIA: /* load byte */
if (cpu_unit.flags & UNIT_BYT)
AC[dstAC] = (M[AC[pulse] >> 1] >>
((AC[pulse] & 1)? 0: 8)) & 0377;
else AC[dstAC] = 0;
break;
case ioDOA: /* stack ptr */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) SP = AC[dstAC] & AMASK;
if (pulse == iopC) AC[dstAC] = SP; }
break;
case ioDIB: /* push, pop */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) { /* push */
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC];
STK_CHECK (SP, 1); }
if (pulse == iopC) { /* pop */
AC[dstAC] = M[SP];
SP = DECA (SP); }
if ((pulse == iopP) && /* Nova 4 pshn */
(cpu_unit.flags & UNIT_BYT)) {
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC];
if (SP > M[042]) int_req = int_req | INT_STK ;
}
}
break;
case ioDOB: /* store byte */
if (cpu_unit.flags & UNIT_BYT) {
int32 MA, val;
MA = AC[pulse] >> 1;
val = AC[dstAC] & 0377;
if (MEM_ADDR_OK (MA)) M[MA] = (AC[pulse] & 1)?
((M[MA] & ~0377) | val):
((M[MA] & 0377) | (val << 8)); }
break;
case ioDIC: /* save, return */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) { /* save */
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[0];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[1];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[2];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = FP;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) |
(AC[3] & AMASK);
AC[3] = FP = SP & AMASK;
STK_CHECK (SP, 5); }
if (pulse == iopC) { /* retn */
PCQ_ENTRY;
SP = FP & AMASK;
C = (M[SP] << 1) & CBIT;
PC = M[SP] & AMASK;
SP = DECA (SP);
AC[3] = M[SP];
SP = DECA (SP);
AC[2] = M[SP];
SP = DECA (SP);
AC[1] = M[SP];
SP = DECA (SP);
AC[0] = M[SP];
SP = DECA (SP);
FP = AC[3] & AMASK; }
if ((pulse == iopP) && /* Nova 4 saven */
(cpu_unit.flags & UNIT_BYT)) {
int32 frameSz = M[PC] ;
PC = INCA (PC) ;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[0];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[1];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[2];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = FP;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) |
(AC[3] & AMASK);
AC[3] = FP = SP & AMASK ;
SP = (SP + frameSz) & AMASK ;
if (SP > M[042]) int_req = int_req | INT_STK;
}
}
break;
case ioDOC:
if ((dstAC == 2) && (cpu_unit.flags & UNIT_MDV)) {
uint32 mddata, uAC0, uAC1, uAC2;
uAC0 = (unsigned int32) AC[0];
uAC1 = (unsigned int32) AC[1];
uAC2 = (unsigned int32) AC[2];
if (pulse == iopP) { /* mul */
mddata = (uAC1 * uAC2) + uAC0;
AC[0] = (mddata >> 16) & DMASK;
AC[1] = mddata & DMASK; }
if (pulse == iopS) { /* div */
if ((uAC0 >= uAC2) || (uAC2 == 0)) C = CBIT;
else {
C = 0;
mddata = (uAC0 << 16) | uAC1;
AC[1] = mddata / uAC2;
AC[0] = mddata % uAC2; } } }
if ((dstAC == 3) && (cpu_unit.flags & UNIT_BYT)) {
int32 mddata;
if (pulse == iopC) { /* muls */
mddata = (SEXT (AC[1]) * SEXT (AC[2])) + SEXT (AC[0]);
AC[0] = (mddata >> 16) & DMASK;
AC[1] = mddata & DMASK; }
if (pulse == iopN) { /* divs */
if (AC[2] == 0) C = CBIT;
else {
mddata = (SEXT (AC[0]) << 16) | AC[1];
AC[1] = mddata / SEXT (AC[2]);
AC[0] = mddata % SEXT (AC[2]);
if ((AC[1] > 077777) || (AC[1] < -0100000))
C = CBIT;
else C = 0;
AC[0] = AC[0] & DMASK; } } }
break; } /* end case code */
} /* end if mul/div */
/* IOT, continued */
else if (device == DEV_CPU) { /* CPU control */
switch (code) { /* decode IR<5:7> */
case ioDIA: /* read switches */
AC[dstAC] = SR;
break;
case ioDIB: /* int ack */
AC[dstAC] = 0;
int_req = (int_req & ~INT_DEV) |
(dev_done & ~dev_disable);
iodata = int_req & (-int_req);
for (i = DEV_LOW; i <= DEV_HIGH; i++) {
if (iodata & dev_table[i].mask) {
AC[dstAC] = i; break; } }
break;
case ioDOB: /* mask out */
mask_out (pimask = AC[dstAC]);
break;
case ioDIC: /* io reset */
reset_all (0); /* reset devices */
break;
case ioDOC: /* halt */
reason = STOP_HALT;
break; } /* end switch code */
switch (pulse) { /* decode IR<8:9> */
case iopS: /* ion */
int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING;
break;
case iopC: /* iof */
int_req = int_req & ~INT_ION;
break; } /* end switch pulse */
} /* end CPU control */
switch (code) { /* decode IR<5:7> */
case ioDIA: /* read switches */
AC[dstAC] = SR;
break;
case ioDIB: /* int ack */
AC[dstAC] = 0;
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
iodata = int_req & (-int_req);
for (i = DEV_LOW; i <= DEV_HIGH; i++) {
if (iodata & dev_table[i].mask) {
AC[dstAC] = i; break; } }
break;
case ioDOB: /* mask out */
mask_out (pimask = AC[dstAC]);
break;
case ioDIC: /* io reset */
reset_all (0); /* reset devices */
break;
case ioDOC: /* halt */
reason = STOP_HALT;
break; } /* end switch code */
switch (pulse) { /* decode IR<8:9> */
case iopS: /* ion */
int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING;
break;
case iopC: /* iof */
int_req = int_req & ~INT_ION;
break; } /* end switch pulse */
} /* end CPU control */
else if (dev_table[device].routine) { /* normal device */
iodata = dev_table[device].routine (pulse, code, AC[dstAC]);
reason = iodata >> IOT_V_REASON;
if (code & 1) AC[dstAC] = iodata & 0177777; }
iodata = dev_table[device].routine (pulse, code, AC[dstAC]);
reason = iodata >> IOT_V_REASON;
if (code & 1) AC[dstAC] = iodata & 0177777; }
else reason = stop_dev;
} /* end if IOT */
} /* end while */
@ -763,7 +762,7 @@ int32 i;
dev_disable = 0;
for (i = DEV_LOW; i <= DEV_HIGH; i++) {
if (newmask & dev_table[i].pi)
dev_disable = dev_disable | dev_table[i].mask; }
dev_disable = dev_disable | dev_table[i].mask; }
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
return;
}

View file

@ -446,21 +446,21 @@ case ioDIA: /* DIA */
dkp_sta = dkp_sta & ~STA_DYN; /* clear dynamic */
if (uptr->flags & UNIT_ATT) dkp_sta = dkp_sta | STA_DRDY;
if (uptr->CYL >= drv_tab[dtype].cyl)
dkp_sta = dkp_sta | STA_CYL; /* bad cylinder? */
dkp_sta = dkp_sta | STA_CYL; /* bad cylinder? */
if (dkp_sta & STA_EFLGS) dkp_sta = dkp_sta | STA_ERR;
rval = dkp_sta;
break;
case ioDOA: /* DOA */
if ((dev_busy & INT_DKP) == 0) {
dkp_fccy = AC; /* save cmd, cyl */
dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS); }
dkp_fccy = AC; /* save cmd, cyl */
dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS); }
break;
case ioDIB: /* DIB */
rval = dkp_ma; /* return buf addr */
break;
case ioDOB: /* DOB */
if ((dev_busy & INT_DKP) == 0) dkp_ma =
AC & (drv_tab[dtype].new? DMASK: AMASK);
AC & (drv_tab[dtype].new? DMASK: AMASK);
break;
case ioDIC: /* DIC */
rval = dkp_ussc; /* return unit, sect */
@ -559,12 +559,12 @@ rval = SCPE_OK;
dtype = GET_DTYPE (uptr->flags); /* get drive type */
if (uptr->FUNC == FCCY_SEEK) { /* seek? */
if (uptr->CYL >= drv_tab[dtype].cyl) /* bad cylinder? */
dkp_sta = dkp_sta | STA_ERR | STA_CYL;
dkp_sta = dkp_sta | STA_ERR | STA_CYL;
dev_done = dev_done | INT_DKP; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
u = uptr - dkp_dev.units; /* get unit number */
dkp_sta = (dkp_sta | (STA_SKDN0 >> u)) /* set seek done */
& ~(STA_SEEK0 >> u); /* clear seeking */
& ~(STA_SEEK0 >> u); /* clear seeking */
return SCPE_OK; }
if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */
@ -581,11 +581,11 @@ else if (GET_CYL (dkp_fccy, dtype) != uptr->CYL) /* address error? */
else { sc = 16 - GET_COUNT (dkp_ussc); /* get sector count */
sa = GET_SA (uptr->CYL, GET_SURF (dkp_ussc, dtype),
GET_SECT (dkp_ussc, dtype), dtype); /* get disk block */
GET_SECT (dkp_ussc, dtype), dtype); /* get disk block */
xcsa = GET_SA (uptr->CYL + 1, 0, 0, dtype); /* get next cyl addr */
if ((sa + sc) > xcsa ) { /* across cylinder? */
sc = xcsa - sa; /* limit transfer */
dkp_sta = dkp_sta | STA_XCY; } /* xcyl error */
sc = xcsa - sa; /* limit transfer */
dkp_sta = dkp_sta | STA_XCY; } /* xcyl error */
bda = sa * DKP_NUMWD * sizeof (short); /* to words, bytes */
err = fseek (uptr->fileref, bda, SEEK_SET); /* position drive */
@ -610,17 +610,17 @@ else { sc = 16 - GET_COUNT (dkp_ussc); /* get sector count */
if (err = ferror (uptr->fileref)) break; } }
if (err != 0) {
perror ("DKP I/O error");
rval = SCPE_IOERR; }
perror ("DKP I/O error");
rval = SCPE_IOERR; }
clearerr (uptr->fileref);
sa = sa + sc; /* update sector addr */
newsect = sa % drv_tab[dtype].sect;
newsurf = (sa / drv_tab[dtype].sect) % drv_tab[dtype].surf;
dkp_ussc = (dkp_ussc & USSC_UNIT) | ((dkp_ussc + sc) & USSC_M_COUNT) |
((drv_tab[dtype].new)?
((newsurf << USSC_V_NSURFACE) | (newsect << USSC_V_NSECTOR)):
((newsurf << USSC_V_OSURFACE) | (newsect << USSC_V_OSECTOR)) );
((drv_tab[dtype].new)?
((newsurf << USSC_V_NSURFACE) | (newsect << USSC_V_NSECTOR)):
((newsurf << USSC_V_OSURFACE) | (newsect << USSC_V_OSECTOR)) );
dkp_sta = dkp_sta | STA_DONE; } /* set status */
dev_busy = dev_busy & ~INT_DKP; /* clear busy */
@ -661,9 +661,9 @@ if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK;
if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK;
for (i = 0; drv_tab[i].sect != 0; i++) {
if (p <= (drv_tab[i].size * (int) sizeof (short))) {
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
uptr->capac = drv_tab[i].size;
return SCPE_OK; } }
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
uptr->capac = drv_tab[i].size;
return SCPE_OK; } }
return SCPE_OK;
}

View file

@ -441,12 +441,12 @@ All drives have 256 16b words per sector. The other disk parameters are:
D44 408 4 12 5.014 4234, 6045
C111 203 10 6 3.118 4048
C114 203 20 12 12.472 4057, 2314
6225 20 2 245 2.508
6099 32 4 192 6.291
6227 20 6 245 7.526
6070 24 4 408 10.027
6103 32 8 192 12.583
4231 23 19 411 45.979
6225 245 2 20 2.508
6099 192 4 32 6.291
6227 245 6 20 7.526
6070 408 4 24 10.027
6103 192 8 32 12.583
4231 411 19 23 45.979
The moving head disk controller implements these registers:

View file

@ -164,10 +164,10 @@ if ((pulse == iopP) && ((dsk_wlk >> GET_DISK (dsk_da)) & 1)) { /* wrt lock? */
if (pulse & 1) { /* read or write? */
if (((t_addr) (dsk_da * DSK_NUMWD)) >= dsk_unit.capac) { /* inv sev? */
dev_done = dev_done | INT_DSK; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */
return rval; } /* done */
dev_done = dev_done | INT_DSK; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */
return rval; } /* done */
dsk_unit.FUNC = pulse; /* save command */
dev_busy = dev_busy | INT_DSK; /* set busy */
t = sector_map[dsk_da & DSK_MMASK] - GET_SECTOR (dsk_time);
@ -193,16 +193,16 @@ if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
da = dsk_da * DSK_NUMWD; /* calc disk addr */
if (uptr->FUNC == iopS) { /* read? */
for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */
pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */
if (MEM_ADDR_OK (pa)) M[pa] =
*(((int16 *) uptr->filebuf) + da + i); }
pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */
if (MEM_ADDR_OK (pa)) M[pa] =
*(((int16 *) uptr->filebuf) + da + i); }
dsk_ma = (dsk_ma + DSK_NUMWD) & AMASK; }
if (uptr->FUNC == iopP) { /* write? */
for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */
pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */
*(((int16 *) uptr->filebuf) + da + i) = M[pa]; }
pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */
*(((int16 *) uptr->filebuf) + da + i) = M[pa]; }
if (((t_addr) (da + i)) >= uptr->hwmark) /* past end? */
uptr->hwmark = da + i + 1; /* upd hwmark */
uptr->hwmark = da + i + 1; /* upd hwmark */
dsk_ma = (dsk_ma + DSK_NUMWD + 3) & AMASK; }
dsk_stat = 0; /* set status */

View file

@ -81,7 +81,7 @@ case iopS: /* start */
int_req = int_req & ~INT_LPT;
if ((lpt_unit.buf != 015) && (lpt_unit.buf != 014) &&
(lpt_unit.buf != 012))
return (lpt_svc (&lpt_unit) << IOT_V_REASON);
return (lpt_svc (&lpt_unit) << IOT_V_REASON);
sim_activate (&lpt_unit, lpt_unit.wait);
break;
case iopC: /* clear */

View file

@ -261,31 +261,33 @@ case iopS: /* start */
c = GET_CMD (mta_cu); /* get command */
if (dev_busy & INT_MTA) break; /* ignore if busy */
if ((uptr->USTAT & STA_RDY) == 0) { /* drive not ready? */
mta_sta = mta_sta | STA_ILL; /* illegal op */
dev_busy = dev_busy & ~INT_MTA; /* clear busy */
dev_done = dev_done | INT_MTA; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); }
mta_sta = mta_sta | STA_ILL; /* illegal op */
dev_busy = dev_busy & ~INT_MTA; /* clear busy */
dev_done = dev_done | INT_MTA; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); }
else if ((c == CU_REWIND) || (c == CU_UNLOAD)) { /* rewind, unload? */
mta_upddsta (uptr, (uptr->USTAT & /* update status */
~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW);
sim_activate (uptr, mta_rwait); /* start IO */
if (c == CU_UNLOAD) detach_unit (uptr); }
else { mta_sta = 0; /* clear errors */
dev_busy = dev_busy | INT_MTA; /* set busy */
dev_done = dev_done & ~INT_MTA; /* clear done */
int_req = int_req & ~INT_MTA; /* clear int */
if (ctype[c]) sim_activate (uptr, mta_cwait);
else { mta_upddsta (uptr, uptr->USTAT &
~(STA_BOT | STA_EOF | STA_EOT | STA_RDY));
sim_activate (uptr, mta_rwait); } }
mta_upddsta (uptr, (uptr->USTAT & /* update status */
~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW);
sim_activate (uptr, mta_rwait); /* start IO */
if (c == CU_UNLOAD) detach_unit (uptr); }
else {
mta_sta = 0; /* clear errors */
dev_busy = dev_busy | INT_MTA; /* set busy */
dev_done = dev_done & ~INT_MTA; /* clear done */
int_req = int_req & ~INT_MTA; /* clear int */
if (ctype[c]) sim_activate (uptr, mta_cwait);
else {
mta_upddsta (uptr, uptr->USTAT &
~(STA_BOT | STA_EOF | STA_EOT | STA_RDY));
sim_activate (uptr, mta_rwait); } }
mta_updcsta (uptr); /* update status */
break;
case iopC: /* clear */
for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
uptr = mta_dev.units + u; /* cancel IO */
if (sim_is_active (uptr) && !(uptr->USTAT & STA_REW)) {
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
sim_cancel (uptr); } }
uptr = mta_dev.units + u; /* cancel IO */
if (sim_is_active (uptr) && !(uptr->USTAT & STA_REW)) {
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
sim_cancel (uptr); } }
dev_busy = dev_busy & ~INT_MTA; /* clear busy */
dev_done = dev_done & ~INT_MTA; /* clear done */
int_req = int_req & ~INT_MTA; /* clear int */
@ -338,7 +340,7 @@ case CU_CMODE: /* controller mode */
case CU_DMODE: /* drive mode */
if (uptr->pos) mta_sta = mta_sta | STA_ILL; /* must be BOT */
else mta_upddsta (uptr, (mta_cu & CU_PE)? /* update drv status */
uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM);
uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM);
break;
/* Unit service, continued */
@ -350,23 +352,24 @@ case CU_READNS: /* read non-stop */
cbc = wc * 2; /* expected bc */
if (tbc & 1) mta_sta = mta_sta | STA_ODD; /* odd byte count? */
if (tbc > cbc) mta_sta = mta_sta | STA_WCO; /* too big? */
else { cbc = tbc; /* no, use it */
wc = (cbc + 1) / 2; } /* adjust wc */
else {
cbc = tbc; /* no, use it */
wc = (cbc + 1) / 2; } /* adjust wc */
i = fxread (dbuf, sizeof (int8), cbc, uptr->fileref);
for ( ; i < cbc; i++) dbuf[i] = 0;
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
if (err = ferror (uptr->fileref)) { /* error? */
MT_SET_PNU (uptr); /* pos not upd */
break; }
MT_SET_PNU (uptr); /* pos not upd */
break; }
for (i = p = 0; i < wc; i++) { /* copy buf to mem */
c1 = dbuf[p++];
c2 = dbuf[p++];
pa = MapAddr (0, mta_ma); /* map address */
if (MEM_ADDR_OK (pa)) M[pa] = (c1 << 8) | c2;
mta_ma = (mta_ma + 1) & AMASK; }
c1 = dbuf[p++];
c2 = dbuf[p++];
pa = MapAddr (0, mta_ma); /* map address */
if (MEM_ADDR_OK (pa)) M[pa] = (c1 << 8) | c2;
mta_ma = (mta_ma + 1) & AMASK; }
mta_wc = (mta_wc + wc) & DMASK;
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt));
(2 * sizeof (t_mtrlnt));
break;
case CU_WRITE: /* write */
@ -374,16 +377,17 @@ case CU_WRITE: /* write */
tbc = wc * 2; /* io byte count */
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
for (i = p = 0; i < wc; i++) { /* copy to buffer */
pa = MapAddr (0, mta_ma); /* map address */
dbuf[p++] = (M[pa] >> 8) & 0377;
dbuf[p++] = M[pa] & 0377;
mta_ma = (mta_ma + 1) & AMASK; }
pa = MapAddr (0, mta_ma); /* map address */
dbuf[p++] = (M[pa] >> 8) & 0377;
dbuf[p++] = M[pa] & 0377;
mta_ma = (mta_ma + 1) & AMASK; }
fxwrite (dbuf, sizeof (int8), tbc, uptr->fileref);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */
else { mta_wc = 0;
uptr->pos = uptr->pos + tbc + (2 * sizeof (t_mtrlnt)); }
else {
mta_wc = 0;
uptr->pos = uptr->pos + tbc + (2 * sizeof (t_mtrlnt)); }
break;
/* Unit service, continued */
@ -401,20 +405,23 @@ case CU_ERASE: /* erase */
break;
case CU_SPACEF: /* space forward */
do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
if (mta_rdlntf (uptr, &tbc, &err)) break; /* read rec lnt, err? */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); }
do {
mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
if (mta_rdlntf (uptr, &tbc, &err)) break; /* read rec lnt, err? */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); }
while (mta_wc != 0);
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
break;
case CU_SPACER: /* space reverse */
do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
if (pnu) pnu = 0; /* pos not upd? */
else { if (mta_rdlntr (uptr, &tbc, &err)) break;
uptr->pos = uptr->pos - ((tbc + 1) & ~1) -
(2 * sizeof (t_mtrlnt)); } }
do {
mta_wc = (mta_wc + 1) & DMASK; /* incr wc */
if (pnu) pnu = 0; /* pos not upd? */
else {
if (mta_rdlntr (uptr, &tbc, &err)) break;
uptr->pos = uptr->pos - ((tbc + 1) & ~1) -
(2 * sizeof (t_mtrlnt)); } }
while (mta_wc != 0);
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
break;
@ -537,9 +544,9 @@ for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
MT_CLR_PNU (uptr); /* clear pos flag */
sim_cancel (uptr); /* cancel activity */
if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY |
(uptr->USTAT & STA_PEM) |
((uptr->flags & UNIT_WPRT)? STA_WLK: 0) |
((uptr->pos)? 0: STA_BOT);
(uptr->USTAT & STA_PEM) |
((uptr->flags & UNIT_WPRT)? STA_WLK: 0) |
((uptr->pos)? 0: STA_BOT);
else uptr->USTAT = 0; }
mta_updcsta (&mta_unit[0]); /* update status */
return SCPE_OK;

View file

@ -138,8 +138,8 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
if (feof (ptr_unit.fileref)) {
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }

View file

@ -134,64 +134,64 @@ state = 0;
while ((i = getc (fileref)) != EOF) {
switch (state) {
case 0: /* leader */
count = i;
state = (count != 0);
break;
count = i;
state = (count != 0);
break;
case 1: /* high count */
csum = count = (i << 8) | count;
state = 2;
break;
csum = count = (i << 8) | count;
state = 2;
break;
case 2: /* low origin */
origin = i;
state = 3;
break;
origin = i;
state = 3;
break;
case 3: /* high origin */
origin = (i << 8) | origin;
csum = csum + origin;
state = 4;
break;
origin = (i << 8) | origin;
csum = csum + origin;
state = 4;
break;
case 4: /* low checksum */
csum = csum + i;
state = 5;
break;
csum = csum + i;
state = 5;
break;
case 5: /* high checksum */
csum = csum + (i << 8);
if (count == 1) saved_PC = origin; /* count = 1? */
if (count <= 1) { /* count = 0/1? */
if (csum & 0177777) return SCPE_CSUM;
state = 0;
break; }
if (count < 0100000) { /* count > 1 */
state = 8;
break; }
count = 0200000 - count;
state = 6;
break;
csum = csum + (i << 8);
if (count == 1) saved_PC = origin; /* count = 1? */
if (count <= 1) { /* count = 0/1? */
if (csum & 0177777) return SCPE_CSUM;
state = 0;
break; }
if (count < 0100000) { /* count > 1 */
state = 8;
break; }
count = 0200000 - count;
state = 6;
break;
case 6: /* low data */
data = i;
state = 7;
break;
data = i;
state = 7;
break;
case 7: /* high data */
data = (i << 8) | data;
csum = csum + data;
if (count > 20) { /* large block */
for (count = count - 1; count == 1; count--) {
if (origin >= MEMSIZE) return SCPE_NXM;
M[origin] = data;
origin = origin + 1; } }
if (origin >= MEMSIZE) return SCPE_NXM;
M[origin] = data;
origin = origin + 1;
count = count - 1;
if (count == 0) {
if (csum & 0177777) return SCPE_CSUM;
state = 0;
break; }
state = 6;
break;
data = (i << 8) | data;
csum = csum + data;
if (count > 20) { /* large block */
for (count = count - 1; count == 1; count--) {
if (origin >= MEMSIZE) return SCPE_NXM;
M[origin] = data;
origin = origin + 1; } }
if (origin >= MEMSIZE) return SCPE_NXM;
M[origin] = data;
origin = origin + 1;
count = count - 1;
if (count == 0) {
if (csum & 0177777) return SCPE_CSUM;
state = 0;
break; }
state = 6;
break;
case 8: /* error block */
if (i == 0377) state = 0;
break; } /* end switch */
if (i == 0377) state = 0;
break; } /* end switch */
} /* end while */
/* Ok to find end of tape between blocks or in error state */
@ -542,10 +542,11 @@ case 0: /* absolute */
break;
case 1: /* PC rel */
if (disp & dsign) {
if (cflag) fprintf (of, "%-o", (addr - (dmax - disp)) & AMASK);
else fprintf (of, ".-%-o", dmax - disp); }
else { if (cflag) fprintf (of, "%-o", (addr + disp) & AMASK);
else fprintf (of, ".+%-o", disp); }
if (cflag) fprintf (of, "%-o", (addr - (dmax - disp)) & AMASK);
else fprintf (of, ".-%-o", dmax - disp); }
else {
if (cflag) fprintf (of, "%-o", (addr + disp) & AMASK);
else fprintf (of, ".+%-o", disp); }
break;
case 2: /* AC2 rel */
if (disp & dsign) fprintf (of, "-%-o,2", dmax - disp);
@ -610,67 +611,67 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
switch (j) { /* switch on class */
case I_V_NPN: /* no operands */
fprintf (of, "%s", opcode[i]); /* opcode */
break;
fprintf (of, "%s", opcode[i]); /* opcode */
break;
case I_V_R: /* reg only */
fprintf (of, "%s %-o", opcode[i], dst);
break;
fprintf (of, "%s %-o", opcode[i], dst);
break;
case I_V_D: /* dev only */
if (dev_val[dv] >= 0)
fprintf (of, "%s %s", opcode[i], device[dv]);
else fprintf (of, "%s %-o", opcode[i], dev);
break;
if (dev_val[dv] >= 0)
fprintf (of, "%s %s", opcode[i], device[dv]);
else fprintf (of, "%s %-o", opcode[i], dev);
break;
case I_V_RD: /* reg, dev */
if (dev_val[dv] >= 0)
fprintf (of, "%s %-o,%s", opcode[i], dst, device[dv]);
else fprintf (of, "%s %-o,%-o", opcode[i], dst, dev);
break;
if (dev_val[dv] >= 0)
fprintf (of, "%s %-o,%s", opcode[i], dst, device[dv]);
else fprintf (of, "%s %-o,%-o", opcode[i], dst, dev);
break;
case I_V_M: /* addr only */
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, ind, mode, disp, FALSE, cflag);
break;
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, ind, mode, disp, FALSE, cflag);
break;
case I_V_RM: /* reg, addr */
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, ind, mode, disp, FALSE, cflag);
break;
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, ind, mode, disp, FALSE, cflag);
break;
case I_V_RR: /* operate */
fprintf (of, "%s %-o,%-o", opcode[i], src, dst);
if (skp) fprintf (of, ",%s", skip[skp-1]);
break;
fprintf (of, "%s %-o,%-o", opcode[i], src, dst);
if (skp) fprintf (of, ",%s", skip[skp-1]);
break;
case I_V_BY: /* byte */
fprintf (of, "%s %-o,%-o", opcode[i], byac, dst);
break;
fprintf (of, "%s %-o,%-o", opcode[i], byac, dst);
break;
case I_V_2AC: /* reg, reg */
fprintf (of, "%s %-o,%-o", opcode[i], src, dst);
break;
fprintf (of, "%s %-o,%-o", opcode[i], src, dst);
break;
case I_V_RSI: /* reg, short imm */
fprintf (of, "%s %-o,%-o", opcode[i], src + 1, dst);
break;
fprintf (of, "%s %-o,%-o", opcode[i], src + 1, dst);
break;
case I_V_LI: /* long imm */
fprintf (of, "%s %-o", opcode[i], val[1]);
return -1;
fprintf (of, "%s %-o", opcode[i], val[1]);
return -1;
case I_V_RLI: /* reg, long imm */
fprintf (of, "%s %-o,%-o", opcode[i], val[1], dst);
return -1;
fprintf (of, "%s %-o,%-o", opcode[i], val[1], dst);
return -1;
case I_V_LM: /* long addr */
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag);
return -1;
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag);
return -1;
case I_V_RLM: /* reg, long addr */
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag);
return -1;
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag);
return -1;
case I_V_FRM: /* flt reg, long addr */
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, extind, src, extdisp, TRUE, cflag);
return -1;
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, extind, src, extdisp, TRUE, cflag);
return -1;
case I_V_FST: /* flt status */
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, extind, dst, extdisp, AMASK + 1, cflag);
return -1;
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, extind, dst, extdisp, AMASK + 1, cflag);
return -1;
case I_V_XP: /* XOP */
fprintf (of, "%s %-o,%-o,%-o", opcode[i], src, dst, xop);
break; } /* end case */
fprintf (of, "%s %-o,%-o,%-o", opcode[i], src, dst, xop);
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
@ -746,8 +747,8 @@ case A_NUM+A_FL: case A_NUM+A_SI+A_FL: /* CPU, (+)num */
else if (((d >= (((int32) addr - dsign) & AMASK)) &&
(d < (((int32) addr + dsign) & AMASK))) ||
(d >= ((int32) addr + (-dsign & AMASK)))) {
val[1] = 1; /* PC rel */
val[2] = (d - addr) & (dmax - 1); }
val[1] = 1; /* PC rel */
val[2] = (d - addr) & (dmax - 1); }
else return NULL;
break;
case A_PER: case A_PER+A_FL: /* . */
@ -847,12 +848,13 @@ case I_V_RD: /* IOT reg,dev */
val[0] = val[0] | (d << I_V_DST); /* put in place */
case I_V_D: /* IOT dev */
cptr = get_glyph (cptr, gbuf, 0); /* get device */
for (i = 0; (device[i] != NULL) && (strcmp (device[i], gbuf) != 0);
i++);
for (i = 0; (device[i] != NULL) &&
(strcmp (device[i], gbuf) != 0); i++);
if (device[i] != NULL) val[0] = val[0] | dev_val[i];
else { d = get_uint (gbuf, 8, I_M_DEV, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DEV); }
else {
d = get_uint (gbuf, 8, I_M_DEV, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DEV); }
break;
case I_V_RM: /* reg, addr */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
@ -869,11 +871,11 @@ case I_V_RR: /* operate */
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST);
if (*cptr != 0) { /* skip? */
cptr = get_glyph (cptr, gbuf, 0); /* get skip */
for (i = 0; (skip[i] != NULL) &&
(strcmp (skip[i], gbuf) != 0); i++) ;
if (skip[i] == NULL) return SCPE_ARG;
val[0] = val[0] | (i + 1); } /* end for */
cptr = get_glyph (cptr, gbuf, 0); /* get skip */
for (i = 0; (skip[i] != NULL) &&
(strcmp (skip[i], gbuf) != 0); i++) ;
if (skip[i] == NULL) return SCPE_ARG;
val[0] = val[0] | (i + 1); } /* end for */
break;
case I_V_BY: /* byte */
cptr = get_2reg (cptr, 0, amd); /* get 2 reg */

View file

@ -1,6 +1,6 @@
/* nova_tt.c: NOVA console terminal simulator
Copyright (c) 1993-2002, Robert M. Supnik
Copyright (c) 1993-2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@
tti terminal input
tto terminal output
05-Jan-02 RMS Fixed calling sequence for setmod
03-Oct-02 RMS Added DIBs
30-May-02 RMS Widened POS to 32b
30-Nov-01 RMS Added extended SET/SHOW support
@ -46,7 +47,7 @@ t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr);
t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr, void *desc);
/* TTI data structures
@ -210,7 +211,7 @@ sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr)
t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr, void *desc)
{
tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | val;
tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | val;

View file

@ -1,6 +1,6 @@
/* nova_tt1.c: NOVA second terminal simulator
Copyright (c) 1993-2002, Robert M. Supnik
Copyright (c) 1993-2003, Robert M. Supnik
Written by Bruce Ray and used with his gracious permission.
Permission is hereby granted, free of charge, to any person obtaining a
@ -27,6 +27,7 @@
tti1 second terminal input
tto1 second terminal output
05-Jan-03 RMS Fixed calling sequence for setmod
03-Oct-02 RMS Added DIBs
22-Aug-02 RMS Updated for changes in sim_tmxr
30-May-02 RMS Widened POS to 32b
@ -58,7 +59,7 @@ t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr);
t_stat tti1_reset (DEVICE *dptr);
t_stat tto1_reset (DEVICE *dptr);
t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr);
t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat tti1_attach (UNIT *uptr, char *cptr);
t_stat tti1_detach (UNIT *uptr);
t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
@ -259,7 +260,7 @@ sim_cancel (&tto1_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr)
t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr, void *desc)
{
tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | val;
tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | val;

View file

@ -25,6 +25,7 @@
cpu PDP-1 central processor
05-Dec-02 RMS Added drum support
06-Oct-02 RMS Revised for V2.10
20-Aug-02 RMS Added DECtape support
30-Dec-01 RMS Added old PC queue
@ -262,6 +263,7 @@ extern int32 tti (int32 inst, int32 dev, int32 IO);
extern int32 tto (int32 inst, int32 dev, int32 IO);
extern int32 lpt (int32 inst, int32 dev, int32 IO);
extern int32 dt (int32 inst, int32 dev, int32 IO);
extern int32 drm (int32 inst, int32 dev, int32 IO);
int32 sc_map[512] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */
@ -413,14 +415,15 @@ op = ((IR >> 13) & 037); /* get opcode */
if ((op < 032) && (op != 007)) { /* mem ref instr */
MA = (MA & EPCMASK) | (IR & DAMASK); /* direct address */
if (IR & IA) { /* indirect addr? */
if (extm) MA = M[MA] & AMASK; /* if ext, one level */
else { for (i = 0; i < ind_max; i++) { /* count indirects */
t = M[MA]; /* get indirect word */
MA = (MA & EPCMASK) | (t & DAMASK);
if ((t & IA) == 0) break; }
if (i >= ind_max) { /* indirect loop? */
reason = STOP_IND;
break; } } } }
if (extm) MA = M[MA] & AMASK; /* if ext, one level */
else { /* multi-level */
for (i = 0; i < ind_max; i++) { /* count indirects */
t = M[MA]; /* get indirect word */
MA = (MA & EPCMASK) | (t & DAMASK);
if ((t & IA) == 0) break; }
if (i >= ind_max) { /* indirect loop? */
reason = STOP_IND;
break; } } } }
switch (op) { /* decode IR<0:4> */
@ -437,8 +440,8 @@ case 003: /* XOR */
break;
case 004: /* XCT */
if (xct_count >= xct_max) { /* too many XCT's? */
reason = STOP_XCT;
break; }
reason = STOP_XCT;
break; }
xct_count = xct_count + 1; /* count XCT's */
IR = M[MA]; /* get instruction */
goto xct_instr; /* go execute */
@ -540,50 +543,52 @@ case 034: /* LAW */
case 026: /* MUL */
if (cpu_unit.flags & UNIT_MDV) { /* hardware? */
sign = AC ^ M[MA]; /* result sign */
IO = ABS (AC); /* IO = |AC| */
v = ABS (M[MA]); /* v = |mpy| */
for (i = AC = 0; i < 17; i++) {
if (IO & 1) AC = AC + v;
IO = (IO >> 1) | ((AC & 1) << 17);
AC = AC >> 1; }
if ((sign & 0400000) && (AC | IO)) { /* negative, > 0? */
AC = AC ^ 0777777;
IO = IO ^ 0777777; } }
else { if (IO & 1) AC = AC + M[MA]; /* multiply step */
if (AC > 0777777) AC = (AC + 1) & 0777777;
if (AC == 0777777) AC = 0;
sign = AC ^ M[MA]; /* result sign */
IO = ABS (AC); /* IO = |AC| */
v = ABS (M[MA]); /* v = |mpy| */
for (i = AC = 0; i < 17; i++) {
if (IO & 1) AC = AC + v;
IO = (IO >> 1) | ((AC & 1) << 17);
AC = AC >> 1; }
if ((sign & 0400000) && (AC | IO)) { /* negative, > 0? */
AC = AC ^ 0777777;
IO = IO ^ 0777777; } }
else { /* multiply step */
if (IO & 1) AC = AC + M[MA];
if (AC > 0777777) AC = (AC + 1) & 0777777;
if (AC == 0777777) AC = 0;
IO = (IO >> 1) | ((AC & 1) << 17);
AC = AC >> 1; }
break;
case 027: /* DIV */
if (cpu_unit.flags & UNIT_MDV) { /* hardware */
sign = AC ^ M[MA]; /* result sign */
signd = AC; /* remainder sign */
if (AC & 0400000) {
AC = AC ^ 0777777; /* AC'IO = |AC'IO| */
IO = IO ^ 0777777; }
v = ABS (M[MA]); /* v = |divr| */
if (AC >= v) break; /* overflow? */
for (i = t = 0; i < 18; i++) {
if (t) AC = (AC + v) & 0777777;
else AC = (AC - v) & 0777777;
t = AC >> 17;
if (i != 17) AC = ((AC << 1) | (IO >> 17)) & 0777777;
IO = ((IO << 1) | (t ^ 1)) & 0777777; }
if (t) AC = (AC + v) & 0777777; /* correct remainder */
t = ((signd & 0400000) && AC)? AC ^ 0777777: AC;
AC = ((sign & 0400000) && IO)? IO ^ 0777777: IO;
IO = t;
PC = INCR_ADDR (PC); } /* skip */
else { t = AC >> 17; /* divide step */
AC = ((AC << 1) | (IO >> 17)) & 0777777;
IO = ((IO << 1) | (t ^ 1)) & 0777777;
if (IO & 1) AC = AC + (M[MA] ^ 0777777);
else AC = AC + M[MA] + 1;
if (AC > 0777777) AC = (AC + 1) & 0777777;
if (AC == 0777777) AC = 0; }
sign = AC ^ M[MA]; /* result sign */
signd = AC; /* remainder sign */
if (AC & 0400000) {
AC = AC ^ 0777777; /* AC'IO = |AC'IO| */
IO = IO ^ 0777777; }
v = ABS (M[MA]); /* v = |divr| */
if (AC >= v) break; /* overflow? */
for (i = t = 0; i < 18; i++) {
if (t) AC = (AC + v) & 0777777;
else AC = (AC - v) & 0777777;
t = AC >> 17;
if (i != 17) AC = ((AC << 1) | (IO >> 17)) & 0777777;
IO = ((IO << 1) | (t ^ 1)) & 0777777; }
if (t) AC = (AC + v) & 0777777; /* correct remainder */
t = ((signd & 0400000) && AC)? AC ^ 0777777: AC;
AC = ((sign & 0400000) && IO)? IO ^ 0777777: IO;
IO = t;
PC = INCR_ADDR (PC); } /* skip */
else { /* divide step */
t = AC >> 17;
AC = ((AC << 1) | (IO >> 17)) & 0777777;
IO = ((IO << 1) | (t ^ 1)) & 0777777;
if (IO & 1) AC = AC + (M[MA] ^ 0777777);
else AC = AC + M[MA] + 1;
if (AC > 0777777) AC = (AC + 1) & 0777777;
if (AC == 0777777) AC = 0; }
break;
/* Skip and operate
@ -624,115 +629,120 @@ case 033:
sc = sc_map[IR & 0777]; /* map shift count */
switch ((IR >> 9) & 017) { /* case on IR<5:8> */
case 001: /* RAL */
AC = ((AC << sc) | (AC >> (18 - sc))) & 0777777;
break;
AC = ((AC << sc) | (AC >> (18 - sc))) & 0777777;
break;
case 002: /* RIL */
IO = ((IO << sc) | (IO >> (18 - sc))) & 0777777;
break;
IO = ((IO << sc) | (IO >> (18 - sc))) & 0777777;
break;
case 003: /* RCL */
t = AC;
AC = ((AC << sc) | (IO >> (18 - sc))) & 0777777;
IO = ((IO << sc) | (t >> (18 - sc))) & 0777777;
break;
t = AC;
AC = ((AC << sc) | (IO >> (18 - sc))) & 0777777;
IO = ((IO << sc) | (t >> (18 - sc))) & 0777777;
break;
case 005: /* SAL */
t = (AC & 0400000)? 0777777: 0;
AC = (AC & 0400000) | ((AC << sc) & 0377777) |
(t >> (18 - sc));
break;
t = (AC & 0400000)? 0777777: 0;
AC = (AC & 0400000) | ((AC << sc) & 0377777) |
(t >> (18 - sc));
break;
case 006: /* SIL */
t = (IO & 0400000)? 0777777: 0;
IO = (IO & 0400000) | ((IO << sc) & 0377777) |
(t >> (18 - sc));
break;
t = (IO & 0400000)? 0777777: 0;
IO = (IO & 0400000) | ((IO << sc) & 0377777) |
(t >> (18 - sc));
break;
case 007: /* SCL */
t = (AC & 0400000)? 0777777: 0;
AC = (AC & 0400000) | ((AC << sc) & 0377777) |
(IO >> (18 - sc));
IO = ((IO << sc) | (t >> (18 - sc))) & 0777777;
break;
t = (AC & 0400000)? 0777777: 0;
AC = (AC & 0400000) | ((AC << sc) & 0377777) |
(IO >> (18 - sc));
IO = ((IO << sc) | (t >> (18 - sc))) & 0777777;
break;
case 011: /* RAR */
AC = ((AC >> sc) | (AC << (18 - sc))) & 0777777;
break;
AC = ((AC >> sc) | (AC << (18 - sc))) & 0777777;
break;
case 012: /* RIR */
IO = ((IO >> sc) | (IO << (18 - sc))) & 0777777;
break;
IO = ((IO >> sc) | (IO << (18 - sc))) & 0777777;
break;
case 013: /* RCR */
t = IO;
IO = ((IO >> sc) | (AC << (18 - sc))) & 0777777;
AC = ((AC >> sc) | (t << (18 - sc))) & 0777777;
break;
t = IO;
IO = ((IO >> sc) | (AC << (18 - sc))) & 0777777;
AC = ((AC >> sc) | (t << (18 - sc))) & 0777777;
break;
case 015: /* SAR */
t = (AC & 0400000)? 0777777: 0;
AC = ((AC >> sc) | (t << (18 - sc))) & 0777777;
break;
t = (AC & 0400000)? 0777777: 0;
AC = ((AC >> sc) | (t << (18 - sc))) & 0777777;
break;
case 016: /* SIR */
t = (IO & 0400000)? 0777777: 0;
IO = ((IO >> sc) | (t << (18 - sc))) & 0777777;
break;
t = (IO & 0400000)? 0777777: 0;
IO = ((IO >> sc) | (t << (18 - sc))) & 0777777;
break;
case 017: /* SCR */
t = (AC & 0400000)? 0777777: 0;
IO = ((IO >> sc) | (AC << (18 - sc))) & 0777777;
AC = ((AC >> sc) | (t << (18 - sc))) & 0777777;
break;
t = (AC & 0400000)? 0777777: 0;
IO = ((IO >> sc) | (AC << (18 - sc))) & 0777777;
AC = ((AC >> sc) | (t << (18 - sc))) & 0777777;
break;
default: /* undefined */
reason = stop_inst;
break; } /* end switch shifts */
reason = stop_inst;
break; } /* end switch shifts */
break;
/* IOT */
case 035:
if (IR & IO_WAIT) { /* wait? */
if (ioh) { /* I/O halt? */
if (ioc) ioh = 0; /* comp pulse? done */
else { sim_interval = 0; /* force event */
PC = DECR_ADDR (PC); } /* re-execute */
break; } /* skip iot */
ioh = 1; /* turn on halt */
PC = DECR_ADDR (PC); } /* re-execute */
if (ioh) { /* I/O halt? */
if (ioc) ioh = 0; /* comp pulse? done */
else { /* wait more */
sim_interval = 0; /* force event */
PC = DECR_ADDR (PC); } /* re-execute */
break; } /* skip iot */
ioh = 1; /* turn on halt */
PC = DECR_ADDR (PC); } /* re-execute */
dev = IR & 077; /* get dev addr */
io_data = IO; /* default data */
switch (dev) { /* case on dev */
case 000: /* I/O wait */
break;
break;
case 001:
if (IR & 003700) io_data = dt (IR, dev, IO); /* DECtape */
else io_data = ptr (IR, dev, IO); /* paper tape rdr */
break;
if (IR & 003700) io_data = dt (IR, dev, IO); /* DECtape */
else io_data = ptr (IR, dev, IO); /* paper tape rdr */
break;
case 002: case 030: /* paper tape rdr */
io_data = ptr (IR, dev, IO);
break;
io_data = ptr (IR, dev, IO);
break;
case 003: /* typewriter */
io_data = tto (IR, dev, IO);
break;
io_data = tto (IR, dev, IO);
break;
case 004: /* keyboard */
io_data = tti (IR, dev, IO);
break;
io_data = tti (IR, dev, IO);
break;
case 005: case 006: /* paper tape punch */
io_data = ptp (IR, dev, IO);
break;
io_data = ptp (IR, dev, IO);
break;
case 033: /* check status */
io_data = iosta | ((sbs & SB_ON)? IOS_SQB: 0);
break;
io_data = iosta | ((sbs & SB_ON)? IOS_SQB: 0);
break;
case 045: /* line printer */
io_data = lpt (IR, dev, IO);
break;
io_data = lpt (IR, dev, IO);
break;
case 054: /* seq brk off */
sbs = sbs & ~SB_ON;
break;
sbs = sbs & ~SB_ON;
break;
case 055: /* seq brk on */
sbs = sbs | SB_ON;
break;
sbs = sbs | SB_ON;
break;
case 056: /* clear seq brk */
sbs = sbs & ~SB_IP;
break;
sbs = sbs & ~SB_IP;
break;
case 061: case 062: case 063: case 064: /* drum */
io_data = drm (IR, dev, IO);
break;
case 074: /* extend mode */
extm = (IR >> 11) & 1; /* set from IR<6> */
break;
extm = (IR >> 11) & 1; /* set from IR<6> */
break;
default: /* undefined */
reason = stop_inst;
break; } /* end switch dev */
reason = stop_inst;
break; } /* end switch dev */
IO = io_data & 0777777;
if (io_data & IOT_SKP) PC = INCR_ADDR (PC); /* skip? */
if (io_data >= IOT_REASON) reason = io_data >> IOT_V_REASON;
break;
default: /* undefined */

View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
05-Dec-02 RMS Added IOT skip support (required by drum)
14-Apr-99 RMS Changed t_addr to unsigned
The PDP-1 was Digital's first computer. The system design evolved during
@ -67,7 +68,9 @@
/* IOT subroutine return codes */
#define IOT_V_REASON 18 /* reason */
#define IOT_V_SKP 18 /* skip */
#define IOT_SKP (1 << IOT_V_SKP)
#define IOT_V_REASON (IOT_V_SKP + 1) /* reason */
#define IOT_REASON (1 << IOT_V_REASON)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: PDP-1 Simulator Usage
Date: 15-Nov-2002
Date: 15-Dec-2002
COPYRIGHT NOTICE
@ -47,6 +47,7 @@ sim/ sim_defs.h
sim/pdp1/ pdp1_defs.h
pdp1_cpu.c
pdp1_drm.c
pdp1_dt.c
pdp1_lp.c
pdp1_stddev.c
@ -63,6 +64,7 @@ CPU PDP-1 CPU with up to 64KW of memory
PTR,PTP integral paper tape reader/punch
TTY console typewriter
LPT Type 62 line printer
DRM Type 24 serial drum
DT Type 550 Microtape (DECtape)
The PDP-1 simulator implements the following unique stop conditions:
@ -299,7 +301,32 @@ operate correctly.
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
2.4 Symbolic Display and Input
2.4 Type 24 Serial Drum (DRM)
The serial drum (DRM) implements these registers:
name size comments
DA 9 drum address (sector number)
MA 16 current memory address
INT 1 interrupt pending flag
DONE 1 device done flag
ERR 1 error flag
WLK 32 write lock switches
TIME 24 rotational latency, per word
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
Drum data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.5 Symbolic Display and Input
The PDP-1 simulator implements symbolic display and input. Display is
controlled by command line switches:
@ -359,7 +386,7 @@ Finally, the LAW instruction has the format
where immediate is in the range 0 to 07777.
2.5 Character Sets
2.6 Character Sets
The PDP-1's console was a Frieden Flexowriter; its character encoding
was known as FIODEC. The PDP-1's line printer used a modified Hollerith

169
PDP1/pdp1_drm.c Normal file
View file

@ -0,0 +1,169 @@
/* pdp1_drm.c: drum/fixed head disk simulator
Copyright (c) 1993-2002, 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.
drm Type 24 serial drum
05-Dec-02 RMS Cloned from pdp18b_drm.c
*/
#include "pdp1_defs.h"
#include <math.h>
/* Constants */
#define DRM_NUMWDS 256 /* words/sector */
#define DRM_NUMSC 2 /* sectors/track */
#define DRM_NUMTR 256 /* tracks/drum */
#define DRM_NUMDK 1 /* drum/controller */
#define DRM_NUMWDT (DRM_NUMWDS * DRM_NUMSC) /* words/track */
#define DRM_SIZE (DRM_NUMDK * DRM_NUMTR * DRM_NUMWDT) /* words/drum */
#define DRM_SMASK ((DRM_NUMTR * DRM_NUMSC) - 1) /* sector mask */
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
#define DRM_READ 000 /* read */
#define DRM_WRITE 010 /* write */
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DRM_NUMWDT)))
extern int32 M[];
extern int32 iosta, sbs;
extern int32 stop_inst;
extern UNIT cpu_unit;
int32 drm_da = 0; /* track address */
int32 drm_ma = 0; /* memory address */
int32 drm_err = 0; /* error flag */
int32 drm_wlk = 0; /* write lock */
int32 drm_time = 10; /* inter-word time */
int32 drm_stopioe = 1; /* stop on error */
t_stat drm_svc (UNIT *uptr);
t_stat drm_reset (DEVICE *dptr);
/* DRM data structures
drm_dev DRM device descriptor
drm_unit DRM unit descriptor
drm_reg DRM register list
*/
UNIT drm_unit =
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
DRM_SIZE) };
REG drm_reg[] = {
{ ORDATA (DA, drm_da, 9) },
{ ORDATA (MA, drm_ma, 16) },
{ FLDATA (DONE, iosta, IOS_V_DRM) },
{ FLDATA (ERR, drm_err, 0) },
{ ORDATA (WLK, drm_wlk, 32) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, drm_stopioe, 0) },
{ NULL } };
DEVICE drm_dev = {
"DRM", &drm_unit, drm_reg, NULL,
1, 8, 20, 1, 8, 18,
NULL, NULL, &drm_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE };
/* IOT routines */
int32 drm (int32 IR, int32 dev, int32 IO)
{
int32 t;
int32 pulse = (IR >> 6) & 037;
if (drm_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | IO; /* stop if requested */
if ((pulse != 001) & (pulse != 011)) /* invalid pulse? */
return (stop_inst << IOT_V_REASON) | IO; /* stop if requested */
switch (dev) { /* switch on device */
case 061: /* DWR, DRD */
drm_ma = IO & 0177777; /* load mem addr */
drm_unit.FUNC = pulse & DRM_WRITE; /* save function */
break;
case 062: /* DBL, DCN */
if (pulse & 010) drm_da = IO & DRM_SMASK; /* load sector # */
iosta = iosta & ~IOS_DRM; /* clear flags */
drm_err = 0;
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t <= 0) t = t + DRM_NUMWDT; /* wrap around? */
break;
case 063: /* DTD */
if (iosta & IOS_DRM) return (IO | IOT_SKP); /* skip if done */
case 064: /* DSE, DSP */
if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
return (IO | IOT_SKP);
}
return IO;
}
/* Unit service
This code assumes the entire drum is buffered.
*/
t_stat drm_svc (UNIT *uptr)
{
int32 i;
t_addr da;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */
iosta = iosta | IOS_DRM; /* set done */
sbs = sbs | SB_RQ; /* req intr */
return IORETURN (drm_stopioe, SCPE_UNATT); }
da = drm_da * DRM_NUMWDS; /* compute dev addr */
for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
if (uptr->FUNC == DRM_READ) {
if (MEM_ADDR_OK (drm_ma)) /* read, check nxm */
M[drm_ma] = *(((int32 *) uptr->filebuf) + da); }
else {
if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1;
else {
*(((int32 *) uptr->filebuf) + da) = M[drm_ma];
if (da >= uptr->hwmark) uptr->hwmark = da + 1; } }
drm_ma = (drm_ma + 1) & 0177777; } /* incr mem addr */
drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
iosta = iosta | IOS_DRM; /* set done */
sbs = sbs | SB_RQ; /* req intr */
return SCPE_OK;
}
/* Reset routine */
t_stat drm_reset (DEVICE *dptr)
{
drm_da = drm_ma = drm_err = 0;
iosta = iosta & ~IOS_DRM;
sim_cancel (&drm_unit);
return SCPE_OK;
}

View file

@ -356,7 +356,7 @@ if (pulse == 004) { /* MLC */
(fnc >= FNC_WMRK) || /* write mark? */
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WLK)) ||
((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK)))
dt_seterr (uptr, DTB_SEL); /* select err */
dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); }
if (pulse == 005) { /* MRD */
IO = (IO & ~DMASK) | dtdb;
@ -367,10 +367,10 @@ if (pulse == 006) { /* MWR */
if (pulse == 007) { /* MRS */
dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */
if (uptr) { /* valid unit? */
mot = DTS_GETMOT (uptr->STATE); /* get motion */
if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */
if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700))
dtsb = dtsb | DTB_GO; } /* accel? go */
mot = DTS_GETMOT (uptr->STATE); /* get motion */
if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */
if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700))
dtsb = dtsb | DTB_GO; } /* accel? go */
IO = (IO & ~DMASK) | dtsb; }
DT_UPDINT;
return IO;
@ -446,17 +446,17 @@ if (new_mving & ~prev_mving) { /* start? */
if (prev_mving & ~new_mving) { /* stop? */
if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* stop current */
sim_activate (uptr, dt_dctime); } /* schedule decel */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* stop current */
sim_activate (uptr, dt_dctime); } /* schedule decel */
DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */
return; }
if (prev_dir ^ new_dir) { /* dir chg? */
if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* stop current */
sim_activate (uptr, dt_dctime); } /* schedule decel */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* stop current */
sim_activate (uptr, dt_dctime); } /* schedule decel */
DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */
DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */
DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */
@ -522,25 +522,26 @@ case FNC_MOVE: /* move */
return; /* done */
case FNC_SRCH: /* search */
if (dir) newpos = DT_BLK2LN ((DT_QFEZ (uptr)?
DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE;
DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE;
else newpos = DT_BLK2LN ((DT_QREZ (uptr)?
0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1);
0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1);
if (dt_log & LOG_MS) printf ("[DT%d: searching %s]\n", unum,
(dir? "backward": "forward"));
(dir? "backward": "forward"));
break;
case FNC_WRIT: /* write */
case FNC_READ: /* read */
case FNC_RALL: /* read all */
case FNC_WALL: /* write all */
if (DT_QEZ (uptr)) { /* in "ok" end zone? */
if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE;
else newpos = DT_EZLIN + (DT_WSIZE - 1); }
else { newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE;
if (!dir) newpos = newpos + (DT_WSIZE - 1); }
if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE;
else newpos = DT_EZLIN + (DT_WSIZE - 1); }
else {
newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE;
if (!dir) newpos = newpos + (DT_WSIZE - 1); }
if ((dt_log & LOG_RA) || ((dt_log & LOG_BL) && (blk == dt_logblk)))
printf ("[DT%d: read all block %d %s%s\n",
unum, blk, (dir? "backward": "forward"),
((dtsa & DTA_MODE)? " continuous]": "]"));
printf ("[DT%d: read all block %d %s%s\n",
unum, blk, (dir? "backward": "forward"),
((dtsa & DTA_MODE)? " continuous]": "]"));
break;
default:
dt_seterr (uptr, DTB_SEL); /* bad state */
@ -603,7 +604,7 @@ if (((int32) uptr->pos < 0) ||
uptr->STATE = uptr->pos = 0;
unum = uptr - dt_dev.units;
if (unum == DTA_GETUNIT (dtsa)) /* if selected, */
dt_seterr (uptr, DTB_SEL); /* error */
dt_seterr (uptr, DTB_SEL); /* error */
return TRUE; }
return FALSE;
}
@ -633,9 +634,9 @@ t_addr ba;
switch (mot) {
case DTS_DECF: case DTS_DECR: /* decelerating */
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */
uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */
if (uptr->STATE) /* not stopped? */
sim_activate (uptr, dt_actime); /* must be reversing */
sim_activate (uptr, dt_actime); /* must be reversing */
return SCPE_OK;
case DTS_ACCF: case DTS_ACCR: /* accelerating */
dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
@ -671,8 +672,8 @@ case DTS_OFR: /* off reel */
case FNC_SRCH: /* search */
if (dtsb & DTB_DTF) { /* DTF set? */
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */
dtdb = blk; /* store block # */
dtsb = dtsb | DTB_DTF; /* set DTF */
@ -682,27 +683,28 @@ case FNC_SRCH: /* search */
case FNC_READ: case FNC_RALL:
if (dtsb & DTB_DTF) { /* DTF set? */
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
dtdb = bptr[ba]; /* get tape word */
dtsb = dtsb | DTB_DTF; } /* set flag */
else { ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1;
wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */
if ((wrd == 0) || /* skip 1st, last */
(wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break;
if ((fnc == FNC_READ) && /* read, skip if not */
(wrd != DT_CSMWD) && /* fwd, rev cksum */
(wrd != ma)) break;
dtdb = dt_gethdr (uptr, blk, relpos);
if (wrd == (dir? DT_CSMWD: ma)) /* at end csum? */
dtsb = dtsb | DTB_BEF; /* end block */
else dtsb = dtsb | DTB_DTF; } /* else next word */
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
dtdb = bptr[ba]; /* get tape word */
dtsb = dtsb | DTB_DTF; } /* set flag */
else {
ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1;
wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */
if ((wrd == 0) || /* skip 1st, last */
(wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break;
if ((fnc == FNC_READ) && /* read, skip if not */
(wrd != DT_CSMWD) && /* fwd, rev cksum */
(wrd != ma)) break;
dtdb = dt_gethdr (uptr, blk, relpos);
if (wrd == (dir? DT_CSMWD: ma)) /* at end csum? */
dtsb = dtsb | DTB_BEF; /* end block */
else dtsb = dtsb | DTB_DTF; } /* else next word */
if (dir) dtdb = dt_comobv (dtdb);
break;
@ -710,27 +712,28 @@ case FNC_READ: case FNC_RALL:
case FNC_WRIT: case FNC_WALL:
if (dtsb & DTB_DTF) { /* DTF set? */
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
if (dir) bptr[ba] = dt_comobv (dtdb); /* get data word */
else bptr[ba] = dtdb;
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1))
dtsb = dtsb | DTB_BEF; /* end block */
else dtsb = dtsb | DTB_DTF; } /* else next word */
else { wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */
if ((wrd == 0) || /* skip 1st, last */
(wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break;
if ((fnc == FNC_WRIT) && /* wr, skip if !csm */
(wrd != ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1)))
break;
dtsb = dtsb | DTB_DTF; } /* set flag */
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
if (dir) bptr[ba] = dt_comobv (dtdb); /* get data word */
else bptr[ba] = dtdb;
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1))
dtsb = dtsb | DTB_BEF; /* end block */
else dtsb = dtsb | DTB_DTF; } /* else next word */
else {
wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */
if ((wrd == 0) || /* skip 1st, last */
(wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break;
if ((fnc == FNC_WRIT) && /* wr, skip if !csm */
(wrd != ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1)))
break;
dtsb = dtsb | DTB_DTF; } /* set flag */
break;
default:
@ -823,16 +826,17 @@ UNIT *uptr;
for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */
uptr = dt_dev.units + i;
if (sim_is_running) { /* CAF? */
prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */
if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */
if (dt_setpos (uptr)) continue; /* update pos */
sim_cancel (uptr);
sim_activate (uptr, dt_dctime); /* sched decel */
DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
} }
else { sim_cancel (uptr); /* sim reset */
uptr->STATE = 0;
uptr->LASTT = sim_grtime (); } }
prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */
if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */
if (dt_setpos (uptr)) continue; /* update pos */
sim_cancel (uptr);
sim_activate (uptr, dt_dctime); /* sched decel */
DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
} }
else {
sim_cancel (uptr); /* sim reset */
uptr->STATE = 0;
uptr->LASTT = sim_grtime (); } }
dtsa = dtsb = 0; /* clear status */
DT_UPDINT; /* reset interrupt */
return SCPE_OK;
@ -939,8 +943,8 @@ if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
if (sim_is_active (uptr)) {
sim_cancel (uptr);
if ((unum == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) {
dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
DT_UPDINT; }
dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
DT_UPDINT; }
uptr->STATE = uptr->pos = 0; }
bptr = uptr->filebuf; /* file buffer */
if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */

View file

@ -89,10 +89,10 @@ if (lpt_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | data; /* stop if requested */
if ((inst & 0700) == 0100) { /* fill buf */
if (bptr < BPTR_MAX) { /* limit test ptr */
i = bptr * 3; /* cvt to chr ptr */
lpt_buf[i] = lpt_trans[(data >> 12) & 077];
lpt_buf[i + 1] = lpt_trans[(data >> 6) & 077];
lpt_buf[i + 2] = lpt_trans[data & 077]; }
i = bptr * 3; /* cvt to chr ptr */
lpt_buf[i] = lpt_trans[(data >> 12) & 077];
lpt_buf[i + 1] = lpt_trans[(data >> 6) & 077];
lpt_buf[i + 2] = lpt_trans[data & 077]; }
bptr = (bptr + 1) & BPTR_MASK;
return data; }
lpt_rpls = 0;
@ -133,22 +133,22 @@ ioc = ioc | lpt_rpls; /* restart */
if (lpt_iot & 020) { /* space? */
iosta = iosta | IOS_SPC; /* set flag */
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 */
if (ferror (lpt_unit.fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
lpt_iot = 0; } /* clear state */
else { iosta = iosta | IOS_PNT; /* print */
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);
fputs (lpt_buf, lpt_unit.fileref); /* print buffer */
if (ferror (lpt_unit.fileref)) { /* test error */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
bptr = 0;
for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
lpt_iot = 010; } /* set state */

View file

@ -28,6 +28,8 @@
tti keyboard
tto teleprinter
22-Dec-02 RMS Added break support
29-Nov-02 RMS Fixed output flag initialization (found by Derek Peschel)
21-Nov-02 RMS Changed typewriter to half duplex (found by Derek Peschel)
06-Oct-02 RMS Revised for V2.10
30-May-02 RMS Widened POS to 32b
@ -217,8 +219,8 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
if (feof (ptr_unit.fileref)) {
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
@ -346,6 +348,7 @@ if (tti_hold & CW) { /* char waiting? */
tty_buf = tti_hold & TT_WIDTH; /* return char */
tti_hold = 0; } /* not waiting */
else { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp;
if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */
temp = temp & 0177;
if (temp == 0177) temp = '\b'; /* rubout? bs */
sim_putchar (temp); /* echo */
@ -353,10 +356,11 @@ else { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp;
in = ascii_to_fiodec[temp]; /* translate char */
if (in == 0) return SCPE_OK; /* no xlation? */
if ((in & BOTH) || ((in & UC) == (tty_uc & UC)))
tty_buf = in & TT_WIDTH;
else { tty_uc = in & UC; /* shift case */
tty_buf = tty_uc? FIODEC_UC: FIODEC_LC;
tti_hold = in | CW; } } /* set 2nd waiting */
tty_buf = in & TT_WIDTH;
else { /* must shift */
tty_uc = in & UC; /* new case */
tty_buf = tty_uc? FIODEC_UC: FIODEC_LC;
tti_hold = in | CW; } } /* set 2nd waiting */
iosta = iosta | IOS_TTI; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
PF = PF | 040; /* set prog flag 1 */
@ -395,7 +399,7 @@ tty_buf = 0; /* clear buffer */
tty_uc = 0; /* clear case */
tti_hold = 0; /* clear hold buf */
tto_rpls = 0; /* clear reset pulse */
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_cancel (&tty_unit[TTO]); /* stop printer */
return SCPE_OK;

View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
05-Dec-02 RMS Added drum support
21-Nov-02 RMS Changed typewriter to half duplex
20-Aug-02 RMS Added DECtape support
17-Sep-01 RMS Removed multiconsole support
@ -32,16 +33,19 @@
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
20-Oct-97 RMS Fixed endian-dependence in RIM loader
(found by Michael Somos)
(found by Michael Somos)
*/
#include "pdp1_defs.h"
#include <ctype.h>
extern DEVICE cpu_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE tty_dev;
extern DEVICE lpt_dev, dt_dev;
extern DEVICE lpt_dev;
extern DEVICE dt_dev;
extern DEVICE drm_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern int32 M[];
@ -72,6 +76,7 @@ DEVICE *sim_devices[] = {
&tty_dev,
&lpt_dev,
&dt_dev,
&drm_dev,
NULL };
const char *sim_stop_messages[] = {
@ -110,12 +115,12 @@ for (;;) {
if ((val = getword (fileref)) < 0) return SCPE_FMT;
if (((val & 0770000) == 0320000) || /* DIO? */
((val & 0770000) == 0240000)) { /* DAC? - incorrect */
origin = val & 07777;
if ((val = getword (fileref)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
origin = val & 07777;
if ((val = getword (fileref)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
else if ((val & 0770000) == 0600000) { /* JMP? */
PC = val & 007777;
break; }
PC = val & 007777;
break; }
}
return SCPE_OK; /* done */
}
@ -268,9 +273,9 @@ int32 i, j;
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((j == class) && (opc_val[i] & inst)) { /* same class? */
inst = inst & ~opc_val[i]; /* mask bit set? */
fprintf (of, (sp? " %s": "%s"), opcode[i]);
sp = 1; } }
inst = inst & ~opc_val[i]; /* mask bit set? */
fprintf (of, (sp? " %s": "%s"), opcode[i]);
sp = 1; } }
return sp;
}
@ -318,35 +323,35 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
switch (j) { /* case on class */
case I_V_NPN: /* no operands */
fprintf (of, "%s", opcode[i]); /* opcode */
break;
fprintf (of, "%s", opcode[i]); /* opcode */
break;
case I_V_IOT: /* IOT */
disp = (inst - opc_val[i]) & 017777;
if (disp == IA) fprintf (of, "%s I", opcode[i]);
else if (disp) fprintf (of, "%s %-o", opcode[i], disp);
else fprintf (of, "%s", opcode[i]);
break;
disp = (inst - opc_val[i]) & 017777;
if (disp == IA) fprintf (of, "%s I", opcode[i]);
else if (disp) fprintf (of, "%s %-o", opcode[i], disp);
else fprintf (of, "%s", opcode[i]);
break;
case I_V_LAW: /* LAW */
cflag = 0; /* fall thru to MRF */
cflag = 0; /* fall thru to MRF */
case I_V_MRF: /* mem ref */
fprintf (of, "%s%s%-o", opcode[i],
((inst & IA)? " I ": " "), (cflag? ma: disp));
break;
fprintf (of, "%s%s%-o", opcode[i],
((inst & IA)? " I ": " "), (cflag? ma: disp));
break;
case I_V_MRI: /* mem ref no ind */
fprintf (of, "%s %-o", opcode[i], (cflag? ma: disp));
break;
fprintf (of, "%s %-o", opcode[i], (cflag? ma: disp));
break;
case I_V_OPR: /* operates */
sp = fprint_opr (of, inst & 007700, j, 0);
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
break;
sp = fprint_opr (of, inst & 007700, j, 0);
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
break;
case I_V_SKP: /* skips */
sp = fprint_opr (of, inst & 007700, j, 0);
if (opcode[i]) sp = fprintf (of, (sp? " %s": "%s"), opcode[i]);
if (inst & IA) fprintf (of, sp? " I": "I");
break;
sp = fprint_opr (of, inst & 007700, j, 0);
if (opcode[i]) sp = fprintf (of, (sp? " %s": "%s"), opcode[i]);
if (inst & IA) fprintf (of, sp? " I": "I");
break;
case I_V_SHF: /* shifts */
fprintf (of, "%s %-d", opcode[i], sc_map[inst & 0777]);
break; } /* end case */
fprintf (of, "%s %-d", opcode[i], sc_map[inst & 0777]);
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
@ -422,8 +427,8 @@ case I_V_LAW: /* LAW */
case I_V_MRF: case I_V_MRI: /* mem ref */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
if ((j != I_V_MRI) && strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | IA;
cptr = get_glyph (cptr, gbuf, 0); }
val[0] = val[0] | IA;
cptr = get_glyph (cptr, gbuf, 0); }
d = get_uint (gbuf, 8, AMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (d <= DAMASK) val[0] = val[0] | d;
@ -439,19 +444,20 @@ case I_V_SHF: /* shift */
break;
case I_V_NPN: case I_V_IOT: case I_V_OPR: case I_V_SKP:
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] != NULL) {
k = opc_val[i] & 0777777;
if ((k != IA) && (((k ^ val[0]) & 0760000) != 0))
return SCPE_ARG;
val[0] = val[0] | k; }
else { d = get_sint (gbuf, &sign, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (sign == 0) val[0] = val[0] + d;
else if (sign < 0) val[0] = val[0] - d;
else val[0] = val[0] | d; } }
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0); i++) ;
if (opcode[i] != NULL) {
k = opc_val[i] & 0777777;
if ((k != IA) && (((k ^ val[0]) & 0760000) != 0))
return SCPE_ARG;
val[0] = val[0] | k; }
else {
d = get_sint (gbuf, &sign, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (sign == 0) val[0] = val[0] + d;
else if (sign < 0) val[0] = val[0] - d;
else val[0] = val[0] | d; } }
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
return SCPE_OK;

View file

@ -607,7 +607,7 @@ if (!ITS) its_1pr = 0; /* ~ITS, clr 1-proc */
abortval = setjmp (save_env); /* set abort hdlr */
if ((abortval > 0) || pager_pi) { /* stop or pi err? */
if (pager_pi && (abortval == PAGE_FAIL))
abortval = STOP_PAGINT; /* stop for pi err */
abortval = STOP_PAGINT; /* stop for pi err */
saved_PC = pager_PC & AMASK; /* failing instr PC */
set_ac_display (ac_cur); /* set up AC display */
pcq_r->qptr = pcq_p; /* update pc q ptr */
@ -623,19 +623,20 @@ else if (abortval == PAGE_FAIL) { /* page fail */
rlog = 0; /* clear log */
if (pager_tc) flags = pager_flags; /* trap? get flags */
if (T20) { /* TOPS-20 */
WriteP (upta + UPT_T20_PFL, pager_word);/* write page fail wd */
WriteP (upta + UPT_T20_OFL, XWD (flags, 0));
WriteP (upta + UPT_T20_OPC, pager_PC);
mb = ReadP (upta + UPT_T20_NPC); }
else { a10 ea; /* TOPS-10 or ITS */
if (ITS) { /* ITS? */
ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3);
if (its_1pr) flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; } /* clear 1-proc */
else ea = upta + UPT_T10_PAG;
WriteP (ea, pager_word); /* write page fail wd */
WriteP (ADDA (ea, 1), XWD (flags, pager_PC));
mb = ReadP (ADDA (ea, 2)); }
WriteP (upta + UPT_T20_PFL, pager_word); /* write page fail wd */
WriteP (upta + UPT_T20_OFL, XWD (flags, 0));
WriteP (upta + UPT_T20_OPC, pager_PC);
mb = ReadP (upta + UPT_T20_NPC); }
else {
a10 ea; /* TOPS-10 or ITS */
if (ITS) { /* ITS? */
ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3);
if (its_1pr) flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; } /* clear 1-proc */
else ea = upta + UPT_T10_PAG;
WriteP (ea, pager_word); /* write page fail wd */
WriteP (ADDA (ea, 1), XWD (flags, pager_PC));
mb = ReadP (ADDA (ea, 2)); }
JUMP (mb); /* set new PC */
set_newflags (mb, FALSE); /* set new flags */
pi_eval (); } /* eval pi system */
@ -667,30 +668,29 @@ if (qintr) {
int32 vec, uba;
pager_pi = TRUE; /* flag in pi seq */
if (vec = pi_ub_vec (qintr, &uba)) { /* Unibus interrupt? */
mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */
if (mb == 0) ABORT (STOP_ZERINT); /* invalid? stop */
inst = ReadE ((((a10) mb) + (vec / 4)) & AMASK);
if (inst == 0)
ABORT (STOP_ZERINT); }
mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */
if (mb == 0) ABORT (STOP_ZERINT); /* invalid? stop */
inst = ReadE ((((a10) mb) + (vec / 4)) & AMASK);
if (inst == 0) ABORT (STOP_ZERINT); }
else inst = ReadP (epta + EPT_PIIT + (2 * qintr));
op = GET_OP (inst); /* get opcode */
ac = GET_AC (inst); /* get ac */
if (its_1pr && ITS) { /* 1-proc set? */
flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; } /* clear 1-proc */
flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; } /* clear 1-proc */
if (op == OP_JSR) { /* JSR? */
ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */
WriteE (ea, FLPC); /* save flags+PC, exec */
JUMP (INCA (ea)); /* PC = ea + 1 */
set_newflags (0, FALSE); } /* set new flags */
ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */
WriteE (ea, FLPC); /* save flags+PC, exec */
JUMP (INCA (ea)); /* PC = ea + 1 */
set_newflags (0, FALSE); } /* set new flags */
else if ((op == OP_JRST) && (ac == AC_XPCW)) { /* XPCW? */
ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */
WriteE (ea, XWD (flags, 0)); /* write flags, exec */
WriteE (ADDA (ea, 1), PC); /* write PC, exec */
rs[0] = ReadE (ADDA (ea, 2)); /* read new flags */
rs[1] = ReadE (ADDA (ea, 3)); /* read new PC */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], FALSE); } /* set new flags */
ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */
WriteE (ea, XWD (flags, 0)); /* write flags, exec */
WriteE (ADDA (ea, 1), PC); /* write PC, exec */
rs[0] = ReadE (ADDA (ea, 2)); /* read new flags */
rs[1] = ReadE (ADDA (ea, 3)); /* read new PC */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], FALSE); } /* set new flags */
else ABORT (STOP_ILLINT); /* invalid instr */
pi_act = pi_act | pi_l2bit[qintr]; /* set level active */
pi_eval (); /* eval pi system */
@ -712,7 +712,7 @@ if (TSTF (F_T1 | F_T2) && PAGING) {
pager_tc = TRUE; /* in a trap sequence */
pager_flags = flags; /* save flags */
ea = (TSTF (F_USR)? upta + UPT_TRBASE: epta + EPT_TRBASE)
+ GET_TRAPS (flags);
+ GET_TRAPS (flags);
inst = ReadP (ea); /* get trap instr */
CLRF (F_T1 | F_T2); } /* clear flags */
@ -720,7 +720,7 @@ if (TSTF (F_T1 | F_T2) && PAGING) {
else { if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
ABORT (STOP_IBKPT); } /* stop simulation */
ABORT (STOP_IBKPT); } /* stop simulation */
/* Ready (at last) to get an instruction */
@ -790,12 +790,12 @@ case 0037:
/* case 0100: MUUO /* UJEN */
/* case 0101: MUUO /* unassigned */
case 0102: if (ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */
inst = Read (ea, MM_OPND);
pflgs = pflgs | ac; goto XCT; }
inst = Read (ea, MM_OPND);
pflgs = pflgs | ac; goto XCT; }
goto MUUO;
case 0103: if (ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */
inst = Read (ea, MM_OPND);
pflgs = pflgs | ac; goto XCT; }
inst = Read (ea, MM_OPND);
pflgs = pflgs | ac; goto XCT; }
goto MUUO;
/* case 0104: MUUO /* JSYS (T20) */
case 0105: AC(ac) = adjsp (AC(ac), ea); break; /* ADJSP */
@ -919,9 +919,9 @@ case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */
case 0253: AOBAC; if (TL (AC(ac))) JUMP (ea); break; /* AOBJN */
/* case 0254: /* shown later /* JRST */
case 0255: if (flags & (ac << 14)) { /* JFCL */
JUMP (ea); CLRF (ac << 14); } break;
JUMP (ea); CLRF (ac << 14); } break;
case 0256: if (xct_cnt++ >= xct_max) /* XCT */
ABORT (STOP_XCT);
ABORT (STOP_XCT);
inst = Read (ea, MM_OPND);
if (ac && !TSTF (F_USR) && !ITS) pflgs = pflgs | ac;
goto XCT;
@ -1263,16 +1263,17 @@ case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */
default:
MUUO: its_2pr = 0; /* clear trap */
if (T20) { /* TOPS20? */
int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18));
WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */
flags & ~(F_T2 | F_T1), tf)); /* traps clear */
WriteP (upta + UPT_MUPC, PC); /* store PC */
WriteP (upta + UPT_T20_UEA, ea); /* store eff addr */
WriteP (upta + UPT_T20_CTX, UBRWORD); } /* store context */
else { WriteP (upta + UPT_MUUO, UUOWORD); /* store instr word */
WriteP (upta + UPT_MUPC, XWD ( /* store flags,,PC */
flags & ~(F_T2 | F_T1), PC)); /* traps clear */
WriteP (upta + UPT_T10_CTX, UBRWORD); } /* store context */
int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18));
WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */
flags & ~(F_T2 | F_T1), tf)); /* traps clear */
WriteP (upta + UPT_MUPC, PC); /* store PC */
WriteP (upta + UPT_T20_UEA, ea); /* store eff addr */
WriteP (upta + UPT_T20_CTX, UBRWORD); } /* store context */
else { /* TOPS10/ITS */
WriteP (upta + UPT_MUUO, UUOWORD); /* store instr word */
WriteP (upta + UPT_MUPC, XWD ( /* store flags,,PC */
flags & ~(F_T2 | F_T1), PC)); /* traps clear */
WriteP (upta + UPT_T10_CTX, UBRWORD); } /* store context */
ea = upta + (TSTF (F_USR)? UPT_UNPC: UPT_ENPC) +
(pager_tc? UPT_NPCT: 0); /* calculate vector */
mb = ReadP (ea); /* new flags, PC */
@ -1292,69 +1293,69 @@ MUUO: its_2pr = 0; /* clear trap */
case 0254: /* JRST */
i = jrst_tab[ac]; /* get subop flags */
if ((i == 0) || ((i == JRST_E) && TSTF (F_USR)) ||
((i == JRST_UIO) && TSTF (F_USR) && !TSTF (F_UIO)))
goto MUUO; /* not legal */
((i == JRST_UIO) && TSTF (F_USR) && !TSTF (F_UIO)))
goto MUUO; /* not legal */
switch (ac) { /* case on subopcode */
case 000: /* JRST 0 = jump */
case 001: /* JRST 1 = portal */
JUMP (ea);
break;
JUMP (ea);
break;
case 002: /* JRST 2 = JRSTF */
mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */
JUMP (ea); /* set new PC */
set_newflags (mb, TRUE); /* set new flags */
break;
mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */
JUMP (ea); /* set new PC */
set_newflags (mb, TRUE); /* set new flags */
break;
case 004: /* JRST 4 = halt */
JUMP (ea); /* old_PC = halt + 1 */
pager_PC = PC; /* force right PC */
ABORT (STOP_HALT); /* known to be exec */
break;
JUMP (ea); /* old_PC = halt + 1 */
pager_PC = PC; /* force right PC */
ABORT (STOP_HALT); /* known to be exec */
break;
case 005: /* JRST 5 = XJRSTF */
RD2; /* read doubleword */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], TRUE); /* set new flags */
break;
RD2; /* read doubleword */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], TRUE); /* set new flags */
break;
case 006: /* JRST 6 = XJEN */
RD2; /* read doubleword */
pi_dismiss (); /* page ok, dismiss */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], FALSE); /* known to be exec */
break;
RD2; /* read doubleword */
pi_dismiss (); /* page ok, dismiss */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], FALSE); /* known to be exec */
break;
case 007: /* JRST 7 = XPCW */
ea = ADDA (i = ea, 2); /* new flags, PC */
RD2; /* read, test page fail */
ReadM (INCA (i), MM_OPND); /* test PC write */
Write (i, XWD (flags, 0), MM_OPND); /* write flags */
Write (INCA (i), PC, MM_OPND); /* write PC */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], FALSE); /* known to be exec */
break;
ea = ADDA (i = ea, 2); /* new flags, PC */
RD2; /* read, test page fail */
ReadM (INCA (i), MM_OPND); /* test PC write */
Write (i, XWD (flags, 0), MM_OPND); /* write flags */
Write (INCA (i), PC, MM_OPND); /* write PC */
JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], FALSE); /* known to be exec */
break;
case 010: /* JRST 10 = dismiss */
pi_dismiss (); /* dismiss int */
JUMP (ea); /* set new PC */
break;
pi_dismiss (); /* dismiss int */
JUMP (ea); /* set new PC */
break;
case 012: /* JRST 12 = JEN */
mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */
JUMP (ea); /* set new PC */
set_newflags (mb, TRUE); /* set new flags */
pi_dismiss (); /* dismiss int */
break;
mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */
JUMP (ea); /* set new PC */
set_newflags (mb, TRUE); /* set new flags */
pi_dismiss (); /* dismiss int */
break;
case 014: /* JRST 14 = SFM */
Write (ea, XWD (flags, 0), MM_OPND);
break;
Write (ea, XWD (flags, 0), MM_OPND);
break;
case 015: /* JRST 15 = XJRST */
if (!T20) goto MUUO; /* only in TOPS20 */
JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */
break; } /* end case subop */
if (!T20) goto MUUO; /* only in TOPS20 */
JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */
break; } /* end case subop */
break; } /* end case op */
if (its_2pr) { /* 1-proc trap? */
its_1pr = its_2pr = 0; /* clear trap */
if (ITS) { /* better be ITS */
WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */
mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */
JUMP (mb); /* set PC */
set_newflags (mb, TRUE); } /* set new flags */
WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */
mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */
JUMP (mb); /* set PC */
set_newflags (mb, TRUE); } /* set new flags */
} /* end if 2-proc */
} /* end for */
@ -1490,15 +1491,17 @@ int32 sc = LIT8 (ea);
if (sc > 71) AC(ac) = AC(p1) = 0;
else if (ea & RSIGN) {
if (sc >= 36) {
AC(p1) = AC(ac) >> (sc - 36);
AC(ac) = 0; }
else { AC(p1) = ((AC(p1) >> sc) | (AC(ac) << (36 - sc))) & DMASK;
AC(ac) = AC(ac) >> sc; } }
AC(p1) = AC(ac) >> (sc - 36);
AC(ac) = 0; }
else {
AC(p1) = ((AC(p1) >> sc) | (AC(ac) << (36 - sc))) & DMASK;
AC(ac) = AC(ac) >> sc; } }
else { if (sc >= 36) {
AC(ac) = (AC(p1) << (sc - 36)) & DMASK;
AC(p1) = 0; }
else { AC(ac) = ((AC(ac) << sc) | (AC(p1) >> (36 - sc))) & DMASK;
AC(p1) = (AC(p1) << sc) & DMASK; } }
AC(ac) = (AC(p1) << (sc - 36)) & DMASK;
AC(p1) = 0; }
else {
AC(ac) = ((AC(ac) << sc) | (AC(p1) >> (36 - sc))) & DMASK;
AC(p1) = (AC(p1) << sc) & DMASK; } }
return;
}
@ -1530,10 +1533,10 @@ d10 fill = sign? ONES: 0;
d10 so;
if (sc == 0) return val;
if (sc > 35) sc = 35; /* cap sc at 35 */
if (sc > 35) sc = 35; /* cap sc at 35 */
if (ea & RSIGN)
return (((val >> sc) | (fill << (36 - sc))) & DMASK);
so = val >> (35 - sc); /* bits lost left + sign */
so = val >> (35 - sc); /* bits lost left + sign */
if (so != (sign? bytemask[sc + 1]: 0)) SETF (F_AOV | F_T1);
return (sign | ((val << sc) & MMASK));
}
@ -1552,22 +1555,24 @@ AC(ac) = CLRS (AC(ac)); /* clear signs */
AC(p1) = CLRS (AC(p1));
if (ea & RSIGN) {
if (sc >= 35) { /* right 36..70 */
AC(p1) = ((AC(ac) >> (sc - 35)) | (fill << (70 - sc))) & DMASK;
AC(ac) = fill; }
else { AC(p1) = sign | /* right 1..35 */
(((AC(p1) >> sc) | (AC(ac) << (35 - sc))) & MMASK);
AC(ac) = ((AC(ac) >> sc) | (fill << (35 - sc))) & DMASK; } }
AC(p1) = ((AC(ac) >> (sc - 35)) | (fill << (70 - sc))) & DMASK;
AC(ac) = fill; }
else {
AC(p1) = sign | /* right 1..35 */
(((AC(p1) >> sc) | (AC(ac) << (35 - sc))) & MMASK);
AC(ac) = ((AC(ac) >> sc) | (fill << (35 - sc))) & DMASK; } }
else { if (sc >= 35) { /* left 36..70 */
so = AC(p1) >> (70 - sc); /* bits lost left */
if ((AC(ac) != (sign? MMASK: 0)) ||
(so != (sign? bytemask[sc - 35]: 0))) SETF (F_AOV | F_T1);
AC(ac) = sign | ((AC(p1) << (sc - 35)) & MMASK);
AC(p1) = sign; }
else { so = AC(ac) >> (35 - sc); /* bits lost left */
if (so != (sign? bytemask[sc]: 0)) SETF (F_AOV | F_T1);
AC(ac) = sign |
(((AC(ac) << sc) | (AC(p1) >> (35 - sc))) & MMASK);
AC(p1) = sign | ((AC(p1) << sc) & MMASK); } }
so = AC(p1) >> (70 - sc); /* bits lost left */
if ((AC(ac) != (sign? MMASK: 0)) ||
(so != (sign? bytemask[sc - 35]: 0))) SETF (F_AOV | F_T1);
AC(ac) = sign | ((AC(p1) << (sc - 35)) & MMASK);
AC(p1) = sign; }
else {
so = AC(ac) >> (35 - sc); /* bits lost left */
if (so != (sign? bytemask[sc]: 0)) SETF (F_AOV | F_T1);
AC(ac) = sign |
(((AC(ac) << sc) | (AC(p1) >> (35 - sc))) & MMASK);
AC(p1) = sign | ((AC(p1) << sc) & MMASK); } }
return;
}
@ -1713,14 +1718,14 @@ if (s) {
left = (36 - p) / s; /* bytes to left of p */
bywrd = left + (p / s); /* bytes per word */
if (bywrd == 0) { /* zero bytes? */
SETF (F_AOV | F_T1 | F_DCK); /* set flags */
return; } /* abort operation */
SETF (F_AOV | F_T1 | F_DCK); /* set flags */
return; } /* abort operation */
newby = left + SXT (val); /* adjusted byte # */
wdadj = newby / bywrd; /* word adjustment */
byadj = (newby >= 0)? newby % bywrd: -((-newby) % bywrd);
if (byadj <= 0) {
byadj = byadj + bywrd; /* make adj positive */
wdadj = wdadj - 1; }
byadj = byadj + bywrd; /* make adj positive */
wdadj = wdadj - 1; }
p = (36 - ((int32) byadj) * s) - ((36 - p) % s); /* new p */
bp = (PUT_P (bp, p) & LMASK) | ((bp + wdadj) & RMASK); }
AC(ac) = bp;
@ -1745,14 +1750,14 @@ int32 flg, t;
AC(ac) = XWD (srca + lnt, dsta + lnt);
for (flg = 0; dsta <= ea; flg++) { /* loop */
if (flg && (t = test_int ())) { /* timer event? */
AC(ac) = XWD (srca, dsta); /* AC for intr */
ABORT (t); }
AC(ac) = XWD (srca, dsta); /* AC for intr */
ABORT (t); }
if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
Read (srca & AMASK, MM_BSTK); } /* force trap */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
Read (srca & AMASK, MM_BSTK); } /* force trap */
if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
ReadM (dsta & AMASK, MM_OPND); } /* force trap */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
ReadM (dsta & AMASK, MM_OPND); } /* force trap */
srcv = Read (srca & AMASK, MM_BSTK); /* read */
Write (dsta & AMASK, srcv, MM_OPND); /* write */
srca = srca + 1; /* incr addr */
@ -1779,19 +1784,19 @@ int32 flg, t;
AC(ac) = XWD (srca + lnt, dsta + lnt);
for (flg = 0; dsta <= ea; flg++) { /* loop */
if (flg && (t = test_int ())) { /* timer event? */
AC(ac) = XWD (srca, dsta); /* AC for intr */
ABORT (t); }
AC(ac) = XWD (srca, dsta); /* AC for intr */
ABORT (t); }
if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
Read (srca & AMASK, MM_BSTK); } /* force trap */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
Read (srca & AMASK, MM_BSTK); } /* force trap */
if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
ReadM (dsta & AMASK, MM_OPND); } /* force trap */
AC(ac) = XWD (srca, dsta); /* AC for page fail */
ReadM (dsta & AMASK, MM_OPND); } /* force trap */
srcv = Read (srca & AMASK, MM_BSTK); /* read */
if (dir) dstv = ((srcv << 10) & BYTE1) | ((srcv >> 6) & BYTE2) |
((srcv << 12) & BYTE3) | ((srcv >> 4) & BYTE4);
((srcv << 12) & BYTE3) | ((srcv >> 4) & BYTE4);
else dstv = ((srcv & BYTE1) >> 10) | ((srcv & BYTE2) << 6) |
((srcv & BYTE3) >> 12) | ((srcv & BYTE4) << 4);
((srcv & BYTE3) >> 12) | ((srcv & BYTE4) << 4);
Write (dsta & AMASK, dstv, MM_OPND); /* write */
srca = srca + 1; /* incr addr */
dsta = dsta + 1; }

View file

@ -1,6 +1,6 @@
/* pdp10_defs.h: PDP-10 simulator definitions
Copyright (c) 1993-2002, Robert M Supnik
Copyright (c) 1993-2003, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
09-Jan-03 RMS Added DEUNA/DELUA support
29-Sep-02 RMS Added variable vector, RX211 support
22-Apr-02 RMS Removed magtape record length error
20-Jan-02 RMS Added multiboard DZ11 support
@ -637,6 +638,8 @@ typedef struct pdp_dib DIB;
#define IOLN_UBCS3 001
#define IOBA_UBMNT3 (IO_UBA3 + 0763101) /* Unibus 3 maint reg */
#define IOLN_UBMNT3 001
#define IOBA_XU (IO_UBA3 + 0774510) /* DEUNA/DELUA */
#define IOLN_XU 010
#define IOBA_RY (IO_UBA3 + 0777170) /* RX211 */
#define IOLN_RY 004
#define IOBA_TU (IO_UBA3 + 0772440) /* RH11/tape */
@ -672,6 +675,7 @@ typedef struct pdp_dib DIB;
#define INT_V_RP 6 /* RH11/RP,RM drives */
#define INT_V_TU 7 /* RH11/TM03/TU45 */
#define INT_V_XU 15 /* DEUNA/DELUA */
#define INT_V_DZRX 16 /* DZ11 */
#define INT_V_DZTX 17
#define INT_V_RY 18 /* RX211 */
@ -681,6 +685,7 @@ typedef struct pdp_dib DIB;
#define INT_RP (1u << INT_V_RP)
#define INT_TU (1u << INT_V_TU)
#define INT_XU (1u << INT_V_XU)
#define INT_DZRX (1u << INT_V_DZRX)
#define INT_DZTX (1u << INT_V_DZTX)
#define INT_RY (1u << INT_V_RY)
@ -690,6 +695,7 @@ typedef struct pdp_dib DIB;
#define IPL_RP 6 /* int levels */
#define IPL_TU 6
#define IPL_XU 5
#define IPL_DZRX 5
#define IPL_DZTX 5
#define IPL_RY 5
@ -708,6 +714,7 @@ typedef struct pdp_dib DIB;
#define VEC_Q 0000 /* vector base */
#define VEC_PTR 0070 /* interrupt vectors */
#define VEC_PTP 0074
#define VEC_XU 0120
#define VEC_TU 0224
#define VEC_RP 0254
#define VEC_RY 0264

View file

@ -1,14 +1,14 @@
To: Users
From: Bob Supnik
Subj: PDP-10 Simulator Usage
Date: 15-Nov-2002
Date: 15-Jan-2003
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik
Copyright (c) 1993-2002, Robert M Supnik
Original code published in 1993-2003, written by Robert M Supnik
Copyright (c) 1993-2003, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -45,10 +45,12 @@ sim/ dec_dz.h
sim_rev.h
sim_sock.h
sim_tmxr.h
sim_ether.h
scp.c
scp_tty.c
sim_sock.c
sim_tmxr.c
sim_ether.c
sim/pdp10/ pdp10_defs.h
pdp10_cpu.c
@ -65,6 +67,7 @@ sim/pdp10/ pdp10_defs.h
pdp10_xtnd.c
sim/pdp11/ pdp11_ry.c
pdp11_xu.c
2. PDP-10 Features
@ -85,6 +88,7 @@ LP20 LP20 line printer
RP RH11/RP04/RP05/RP06/RP07/RM03/RM05/RM80 controller with
eight drives
TU RH11/TM02/TU45 controller with eight drives
XU DEUNA/DELUA Ethernet controller
The PTR, PTP, and RX211 are initially set DISABLED. The DZ11 and LP20 can
also be set DISABLED. Some devices support the SET ADDRESS command, which
@ -563,7 +567,12 @@ Error handling is as follows:
RX02 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.13 Symbolic Display and Input
2.13 DEUNA/DELUA Ethernet Controller (XU)
XU simulates the DEUNA/DELUA Ethernet controller. The current implementation
is a stub and is permanently disabled.
2.14 Symbolic Display and Input
The PDP-10 simulator implements symbolic display and input. Display is
controlled by command line switches:

View file

@ -25,6 +25,7 @@
fe KS10 console front end
22-Dec-02 RMS Added break support
30-May-02 RMS Widened COUNT to 32b
30-Nov-01 RMS Added extended SET/SHOW support
23-Oct-01 RMS New IO page address constants
@ -128,6 +129,7 @@ int32 temp;
sim_activate (&fei_unit, fei_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */
fei_unit.buf = temp & 0177;
fei_unit.pos = fei_unit.pos + 1;
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */

View file

@ -371,9 +371,9 @@ DIB *dibp;
for (i = 0; dibp = dib_tab[i]; i++ ) {
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
dibp->rd (&val, pa, READ);
pi_eval ();
return ((d10) val); } }
dibp->rd (&val, pa, READ);
pi_eval ();
return ((d10) val); } }
UBNXM_FAIL (pa, READ);
}
@ -386,9 +386,9 @@ DIB *dibp;
for (i = 0; dibp = dib_tab[i]; i++ ) {
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
dibp->wr ((int32) val, pa, mode);
pi_eval ();
return; } }
dibp->wr ((int32) val, pa, mode);
pi_eval ();
return; } }
UBNXM_FAIL (pa, mode);
}
@ -414,8 +414,8 @@ lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
*buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);
}
return 0;
@ -431,8 +431,8 @@ lim = ba + (bc & ~01);
for ( ; ba < lim; ba = ba + 2) { /* by words */
pa10 = Map_Addr10 (ba, ub); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
*buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
}
return 0;
@ -448,8 +448,8 @@ lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) |
(((d10) *buf++) << ubashf[ba & 3]); }
return 0;
@ -466,8 +466,8 @@ lim = ba + (bc & ~01);
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
val = *buf++; /* get data */
if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val;
else M[pa10] = (M[pa10] & 0600000777777) | (val << 18);
@ -483,9 +483,9 @@ int32 i, lvl;
for (i = lvl = 0; i < UBANUM; i++) {
if (int_req & ubabr76[i])
lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];
lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];
if (int_req & ubabr54[i])
lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])]; }
lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])]; }
return lvl;
}
@ -502,15 +502,15 @@ int32 i, masked_irq;
for (i = masked_irq = 0; i < UBANUM; i++) {
if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */
(masked_irq = int_req & ubabr76[i])) break;
(masked_irq = int_req & ubabr76[i])) break;
if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */
(masked_irq = int_req & ubabr54[i])) break; }
(masked_irq = int_req & ubabr54[i])) break; }
*uba = (i << 1) + 1; /* store uba # */
for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */
if ((masked_irq >> i) & 1) {
int_req = int_req & ~(1u << i); /* clear req */
if (int_ack[i]) return int_ack[i]();
return int_vec[i]; } } /* return vector */
int_req = int_req & ~(1u << i); /* clear req */
if (int_ack[i]) return int_ack[i]();
return int_vec[i]; } } /* return vector */
return 0;
}

View file

@ -272,17 +272,17 @@ update_lpcs (0); /* update csr's */
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
case 00: /* LPCSA */
if (access == WRITEB) data = (pa & 1)?
(lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data;
(lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data;
if (data & CSA_ECLR) { /* error clear? */
lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */
lpcsb = lpcsb & ~CSB_ECLR; /* clear err */
sim_cancel (&lp20_unit); } /* cancel I/O */
lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */
lpcsb = lpcsb & ~CSB_ECLR; /* clear err */
sim_cancel (&lp20_unit); } /* cancel I/O */
if (data & CSA_INIT) lp20_reset (&lp20_dev); /* init? */
if (data & CSA_GO) { /* go set? */
if ((lpcsa & CSA_GO) == 0) { /* not set before? */
if (lpcsb & CSB_ERR) lpcsb = lpcsb | CSB_GOE;
lpcsum = 0; /* clear checksum */
sim_activate (&lp20_unit, lp20_unit.time); } }
if ((lpcsa & CSA_GO) == 0) { /* not set before? */
if (lpcsb & CSB_ERR) lpcsb = lpcsb | CSB_GOE;
lpcsum = 0; /* clear checksum */
sim_activate (&lp20_unit, lp20_unit.time); } }
else sim_cancel (&lp20_unit); /* go clr, stop DMA */
lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW);
break;
@ -290,31 +290,32 @@ case 01: /* LPCSB */
break; /* ignore writes to TEST */
case 02: /* LPBA */
if (access == WRITEB) data = (pa & 1)?
(lpba & 0377) | (data << 8): (lpba & ~0377) | data;
(lpba & 0377) | (data << 8): (lpba & ~0377) | data;
lpba = data;
break;
case 03: /* LPBC */
if (access == WRITEB) data = (pa & 1)?
(lpbc & 0377) | (data << 8): (lpbc & ~0377) | data;
(lpbc & 0377) | (data << 8): (lpbc & ~0377) | data;
lpbc = data & BC_MASK;
lpcsa = lpcsa & ~CSA_DONE;
break;
case 04: /* LPPAGC */
if (access == WRITEB) data = (pa & 1)?
(lppagc & 0377) | (data << 8): (lppagc & ~0377) | data;
(lppagc & 0377) | (data << 8): (lppagc & ~0377) | data;
lppagc = data & PAGC_MASK;
break;
case 05: /* LPRDAT */
if (access == WRITEB) data = (pa & 1)?
(lprdat & 0377) | (data << 8): (lprdat & ~0377) | data;
(lprdat & 0377) | (data << 8): (lprdat & ~0377) | data;
lprdat = data & RDAT_MASK;
txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */
break;
case 06: /* LPCOLC/LPCBUF */
if ((access == WRITEB) && (pa & 1)) /* odd byte */
lpcolc = data & 0377;
else { lpcbuf = data & 0377; /* even byte, word */
if (access == WRITE) lpcolc = (data >> 8) & 0377; }
lpcolc = data & 0377;
else {
lpcbuf = data & 0377; /* even byte, word */
if (access == WRITE) lpcolc = (data >> 8) & 0377; }
break;
case 07: /* LPCSUM/LPPDAT */
break; } /* read only */
@ -371,9 +372,9 @@ if ((fnc == FNC_PR) && (dvlnt == 0)) {
for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
if (Map_ReadW (ba, 2, &wd10, MAP)) { /* get word, err? */
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
update_lpcs (CSA_ERR); /* set done */
break; }
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
update_lpcs (CSA_ERR); /* set done */
break; }
lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */
lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */
switch (fnc) { /* switch on function */
@ -381,8 +382,8 @@ for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
/* Translation RAM load */
case FNC_RAM: /* RAM load */
txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK;
break;
txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK;
break;
/* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by
a start (354 to 356) and stop (357) byte pair. If the number of bytes
@ -390,48 +391,48 @@ for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
*/
case FNC_DVU: /* DVU load */
if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */
dvld = dvlnt = 0; /* reset lnt */
else if (lpcbuf == 0357) { /* stop DVU load? */
dvptr = 0; /* reset ptr */
if (dvld & 1) dvlnt = 0; } /* if odd, invalid */
else if (dvld == 0) { /* even state? */
temp = lpcbuf & DV_DMASK;
dvld = 1; }
else if (dvld == 1) { /* odd state? */
if (dvlnt < DV_SIZE) davfu[dvlnt++] =
temp | ((lpcbuf & DV_DMASK) << 6);
dvld = 0; }
break;
if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */
dvld = dvlnt = 0; /* reset lnt */
else if (lpcbuf == 0357) { /* stop DVU load? */
dvptr = 0; /* reset ptr */
if (dvld & 1) dvlnt = 0; } /* if odd, invalid */
else if (dvld == 0) { /* even state? */
temp = lpcbuf & DV_DMASK;
dvld = 1; }
else if (dvld == 1) { /* odd state? */
if (dvlnt < DV_SIZE) davfu[dvlnt++] =
temp | ((lpcbuf & DV_DMASK) << 6);
dvld = 0; }
break;
/* Print characters */
case FNC_PR: /* print */
lprdat = txram[lpcbuf]; /* get RAM char */
txst = (TX_GETFL (lprdat) << 1) | /* get state */
((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */
if (lprdat & TX_DELH) lpcsa = lpcsa | CSA_DELH;
else lpcsa = lpcsa & ~CSA_DELH;
lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */
switch (txcase[txst]) { /* case on state */
case TX_CHR: /* take char */
cont = lp20_print (lpcbuf);
break;
case TX_RAM: /* take translation */
cont = lp20_print (lprdat);
break;
case TX_DVU: /* DAVFU action */
if (lprdat & TX_SLEW)
cont = lp20_adv (lprdat & TX_VMASK, TRUE);
else cont = lp20_davfu (lprdat & TX_VMASK);
break;
case TX_INT: /* interrupt */
lpcsa = lpcsa | CSA_UNDF; /* set flag */
cont = FALSE; /* force stop */
break; } /* end case char state */
lprdat = txram[lpcbuf]; /* get RAM char */
txst = (TX_GETFL (lprdat) << 1) | /* get state */
((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */
if (lprdat & TX_DELH) lpcsa = lpcsa | CSA_DELH;
else lpcsa = lpcsa & ~CSA_DELH;
lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */
switch (txcase[txst]) { /* case on state */
case TX_CHR: /* take char */
cont = lp20_print (lpcbuf);
break;
case TX_RAM: /* take translation */
cont = lp20_print (lprdat);
break;
case TX_DVU: /* DAVFU action */
if (lprdat & TX_SLEW)
cont = lp20_adv (lprdat & TX_VMASK, TRUE);
else cont = lp20_davfu (lprdat & TX_VMASK);
break;
case TX_INT: /* interrupt */
lpcsa = lpcsa | CSA_UNDF; /* set flag */
cont = FALSE; /* force stop */
break; } /* end case char state */
break;
case FNC_TST: /* test */
break; } /* end case function */
break; } /* end case function */
} /* end for */
lpba = ba & 0177777;
lpcsa = (lpcsa & ~CSA_UAE) | ((ba >> (16 - CSA_V_UAE)) & CSA_UAE);
@ -467,12 +468,12 @@ if (lppdat == 015) lpcolc = 0; /* CR? reset col cntr */
else if (lppdat == 011) { /* TAB? simulate */
lppdat = ' '; /* with spaces */
if (lpcolc >= 128) {
r = lp20_adv (1, TRUE); /* eol? adv carriage */
rpt = 8; } /* adv to col 9 */
r = lp20_adv (1, TRUE); /* eol? adv carriage */
rpt = 8; } /* adv to col 9 */
else rpt = 8 - (lpcolc & 07); } /* else adv 1 to 8 */
else { if (lppdat < 040) lppdat = ' '; /* cvt non-prnt to spc */
if (lpcolc >= LP_WIDTH) /* line full? */
r = lp20_adv (1, TRUE); } /* adv carriage */
r = lp20_adv (1, TRUE); } /* adv carriage */
for (i = 0; i < rpt; i++) putc (lppdat, lp20_unit.fileref);
lp20_unit.pos = lp20_unit.pos + rpt;
lpcolc = lpcolc + rpt;
@ -490,10 +491,11 @@ lp20_unit.pos = lp20_unit.pos + cnt; /* print 'n' newlines */
if (dvuadv) dvptr = (dvptr + cnt) % dvlnt; /* update DAVFU ptr */
if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else {
lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
return TRUE;
}
@ -506,15 +508,16 @@ for (i = 0; i < dvlnt; i++) { /* search DAVFU */
dvptr = dvptr + 1; /* adv DAVFU ptr */
if (dvptr >= dvlnt) dvptr = 0; /* wrap at end */
if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */
if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */
if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */
putc ('\f', lp20_unit.fileref); /* print form feed */
lp20_unit.pos = lp20_unit.pos + 1;
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */
if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */
putc ('\f', lp20_unit.fileref); /* print form feed */
lp20_unit.pos = lp20_unit.pos + 1;
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else {
lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
} /* end for */
dvlnt = 0; /* DAVFU error */
return FALSE;

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