Notes For V3.1-0

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

1. New Features in 3.1-0

1.1 SCP and libraries

- Added simulated Ethernet support for VMS, FreeBSD, Mac OS/X.
- Added status return to tmxr_putc_ln.
- Added sim_putchar_s to handle possible output stalls.

1.2 All DECtapes

- Added "DECtape off reel" error stop.

1.3 All Asynchronous Consoles

- Added support for output congestion stall if using a Telnet connection.

1.4 PDP-1

- Added Type 23 parallel drum support.

1.5 PDP-8

- Added instruction history.
- Added TSC8-75 option support for ETOS.
- Added TD8E DECtape support.

1.6 PDP-18b

- Added instruction history.
- Changed PDP-9, PDP-15 API default to enabled.

1.7 PDP-11

- Added support for 18b only Qbus devices.
- Formalized bus and addressing definitions.
- Added control to enable/disable autoconfiguration.
- Added stub support for second Unibus Ethernet controller.

1.7 Interdata 32b

- Added instruction history.

1.8 Eclipse

- Added floating point support.
- Added programmable interval timer support.

1.9 H316

- Added DMA/DMC support.
- Added fixed head disk support.
- Added moving head disk support.
- Added magtape support.

1.10 IBM 1130 (Brian Knittel)

- Added support for physical card reader, using the Cardread
interface (www.ibm1130.org/sim/downloads).
- Added support for physical printer (flushes output buffer after
each line).

2. Bugs Fixed in 3.1-0

2.1 SCP and libraries

- Fixed numerous bugs in Ethernet library.

2.2 All DECtapes

- Fixed reverse checksum value in 'read all' mode.
- Simplified (and sped up) timing.

2.3 PDP-8

- Fixed bug in RX28 read status (found by Charles Dickman).
- Fixed RX28 double density write.

2.4 PDP-18b

- Fixed autoincrement bug in PDP-4, PDP-7, PDP-9.

2.5 PDP-11/VAX

- Revised RQ MB->LBN conversion for greater accuracy.
- Fixed bug in IO configuration (found by David Hittner).
- Fixed bug with multiple RQ RAUSER drives.
- Fixed bug in second Qbus Ethernet controller interrupts.

2.6 Nova/Eclipse

- Fixed bugs in DKP flag clear, map setup, map usage (Charles Owen).
- Fixed bug in MT, reset completes despite I/O reset (Charles Owen).
- Fixed bug in MT, space operations return word count (Charles Owen).

2.7 IBM 1130 (Brian Knittel)

- Fixed bug in setting carry bit in subtract and subtract double.
- Fixed timing problem in console printer simulation.

2.8 1620

- Fixed bug in branch digit (found by Dave Babcock).

3. New Features in 3.0 vs prior releases

3.1 SCP and Libraries

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

3.2 All magtapes

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

3.3 VAX

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

3.4 PDP-1

- Added block loader format support to LOAD.
- Changed BOOT PTR to allow loading of all of the first bank of memory.
- The LOAD command takes an optional argument specifying the memory field
  to be loaded.
- The PTR BOOT command takes its starting memory field from the TA (address
  switch) register.

3.5 PDP-18b Family

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

4. Bugs Fixed in 3.0 vs prior releases

4.1 SCP and Libraries

- Fixed end of file problem in dep, idep.
- Fixed handling of trailing spaces in dep, idep.

4.2 VAX

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

4.3 1401

- Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS.
- Fixed MCE bug, BS off by 1 if zero suppress.
- Fixed chaining bug, D lost if return to SCP.
- Fixed H branch, branch occurs after continue.
- Added check for invalid 8 character MCW, LCA.
- Fixed magtape load-mode end of record response.
- Revised fetch to model hardware more closely.
- Fixed tape read end-of-record handling based on real 1401.
- Added diagnostic read (space forward).

4.4 Nova

- Fixed DSK variable size interaction with restore.
- Fixed bug in DSK set size routine.

4.5 PDP-1

- Fixed DT variable size interaction with restore.
- Updated CPU, line printer, standard devices to detect indefinite I/O wait.
- Fixed incorrect logical, missing activate, break in drum simulator.
- Fixed bugs in instruction decoding, overprinting for line printer.
- Fixed system hang if continue after PTR error.
- Fixed PTR to start/stop on successive rpa instructions.

4.6 PDP-11

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

4.7 PDP-18B

- Fixed DT, RF variable size interaction with restore.
- Fixed MT bug in MTTR.
- Fixed bug in PDP-4 line printer overprinting.
- Fixed bug in PDP-15 memory protect/skip interaction.
- Fixed bug in RF set size routine.
- Increased PTP TIME for PDP-15 operating systems.
- Fixed priorities in PDP-15 API (differs from PDP-9).
- Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9).
- Fixed bug in CAF, clears API subsystem.

4.8 PDP-8

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

4.9 HP2100

- Fixed bug in DP (13210A controller only), DQ read status.
- Fixed bug in DP, DQ seek complete.
- Fixed DR drum sizes.
- Fixed DR variable capacity interaction with SAVE/RESTORE.

4.10 GRI

- Fixed bug in SC queue pointer management.

4.11 PDP-10

- Fixed bug in RP read header.

4.12 Ibm1130

- Fixed bugs found by APL 1130.

4.13 Altairz80

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

4.14 1620

- Fixed bug in immediate index add (found by Michael Short).
This commit is contained in:
Bob Supnik 2003-12-31 11:49:00 -08:00 committed by Mark Pizzolato
parent b2101ecdd4
commit 1da2d9452d
140 changed files with 17663 additions and 16338 deletions

View file

@ -1,43 +1,110 @@
Notes For V3.0-2
Notes For V3.1-0
RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially
debugged. Do NOT enable these features for normal operations.
1. New Features in 3.0-2
1. New Features in 3.1-0
1.1 PDP-1
1.1 SCP and libraries
- The LOAD command takes an optional argument specifying the memory field
to be loaded.
- The PTR BOOT command takes its starting memory field from the TA (address
switch) register.
- Added simulated Ethernet support for VMS, FreeBSD, Mac OS/X.
- Added status return to tmxr_putc_ln.
- Added sim_putchar_s to handle possible output stalls.
2. Bugs Fixed in 3.0-2
1.2 All DECtapes
- Added "DECtape off reel" error stop.
1.3 All Asynchronous Consoles
- Added support for output congestion stall if using a Telnet connection.
1.4 PDP-1
- Added Type 23 parallel drum support.
1.5 PDP-8
- Added instruction history.
- Added TSC8-75 option support for ETOS.
- Added TD8E DECtape support.
1.6 PDP-18b
- Added instruction history.
- Changed PDP-9, PDP-15 API default to enabled.
1.7 PDP-11
- Added support for 18b only Qbus devices.
- Formalized bus and addressing definitions.
- Added control to enable/disable autoconfiguration.
- Added stub support for second Unibus Ethernet controller.
1.7 Interdata 32b
- Added instruction history.
1.8 Eclipse
- Added floating point support.
- Added programmable interval timer support.
1.9 H316
- Added DMA/DMC support.
- Added fixed head disk support.
- Added moving head disk support.
- Added magtape support.
1.10 IBM 1130 (Brian Knittel)
- Added support for physical card reader, using the Cardread
interface (www.ibm1130.org/sim/downloads).
- Added support for physical printer (flushes output buffer after
each line).
2. Bugs Fixed in 3.1-0
2.1 SCP and libraries
- Fixed end of file problem in dep, idep.
- Fixed handling of trailing spaces in dep, idep.
- Fixed numerous bugs in Ethernet library.
2.2 PDP-1
2.2 All DECtapes
- Fixed system hang if continue after PTR error.
- Fixed PTR to start/stop on successive rpa instructions.
- Fixed reverse checksum value in 'read all' mode.
- Simplified (and sped up) timing.
2.3 PDP 18b family
2.3 PDP-8
- Fixed priorities in PDP-15 API (differs from PDP-9).
- Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9).
- Fixed bug in CAF, clears API subsystem.
- Fixed bug in RX28 read status (found by Charles Dickman).
- Fixed RX28 double density write.
2.4 1401
2.4 PDP-18b
- Fixed tape read end-of-record handling based on real 1401.
- Added diagnostic read (space forward).
- Fixed autoincrement bug in PDP-4, PDP-7, PDP-9.
2.5 1620
2.5 PDP-11/VAX
- Fixed bug in immediate index add (found by Michael Short).
- Revised RQ MB->LBN conversion for greater accuracy.
- Fixed bug in IO configuration (found by David Hittner).
- Fixed bug with multiple RQ RAUSER drives.
- Fixed bug in second Qbus Ethernet controller interrupts.
2.6 Nova/Eclipse
- Fixed bugs in DKP flag clear, map setup, map usage (Charles Owen).
- Fixed bug in MT, reset completes despite I/O reset (Charles Owen).
- Fixed bug in MT, space operations return word count (Charles Owen).
2.7 IBM 1130 (Brian Knittel)
- Fixed bug in setting carry bit in subtract and subtract double.
- Fixed timing problem in console printer simulation.
2.8 1620
- Fixed bug in branch digit (found by Dave Babcock).
3. New Features in 3.0 vs prior releases
@ -47,7 +114,7 @@ debugged. Do NOT enable these features for normal operations.
- Changed RESTORE to unconditionally detach files.
- Added E11 and TPC format support to magtape library.
- Fixed bug in SHOW CONNECTIONS.
- Added USE_ADDR64 support
- Added USE_ADDR64 support.
3.2 All magtapes
@ -68,6 +135,10 @@ debugged. Do NOT enable these features for normal operations.
- Added block loader format support to LOAD.
- Changed BOOT PTR to allow loading of all of the first bank of memory.
- The LOAD command takes an optional argument specifying the memory field
to be loaded.
- The PTR BOOT command takes its starting memory field from the TA (address
switch) register.
3.5 PDP-18b Family
@ -79,7 +150,12 @@ debugged. Do NOT enable these features for normal operations.
4. Bugs Fixed in 3.0 vs prior releases
4.1 VAX
4.1 SCP and Libraries
- Fixed end of file problem in dep, idep.
- Fixed handling of trailing spaces in dep, idep.
4.2 VAX
- Fixed CVTfi bug: integer overflow not set if exponent out of range
- Fixed EMODx bugs:
@ -91,7 +167,7 @@ debugged. Do NOT enable these features for normal operations.
fast host processors (fixes from Mark Pizzolato).
- Fixed bug in user disk size (found by Chaskiel M Grundman).
4.2 1401
4.3 1401
- Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS.
- Fixed MCE bug, BS off by 1 if zero suppress.
@ -100,20 +176,24 @@ debugged. Do NOT enable these features for normal operations.
- Added check for invalid 8 character MCW, LCA.
- Fixed magtape load-mode end of record response.
- Revised fetch to model hardware more closely.
- Fixed tape read end-of-record handling based on real 1401.
- Added diagnostic read (space forward).
4.3 Nova
4.4 Nova
- Fixed DSK variable size interaction with restore.
- Fixed bug in DSK set size routine.
4.4 PDP-1
4.5 PDP-1
- Fixed DT variable size interaction with restore.
- Updated CPU, line printer, standard devices to detect indefinite I/O wait.
- Fixed incorrect logical, missing activate, break in drum simulator.
- Fixed bugs in instruction decoding, overprinting for line printer.
- Fixed system hang if continue after PTR error.
- Fixed PTR to start/stop on successive rpa instructions.
4.5 PDP-11
4.6 PDP-11
- Fixed DT variable size interaction with restore.
- Fixed bug in MMR1 update (found by Tim Stark).
@ -127,7 +207,7 @@ debugged. Do NOT enable these features for normal operations.
o Added explicit runt and giant packet processing.
- Fixed bug in user disk size (found by Chaskiel M Grundman).
4.6 PDP-18B
4.7 PDP-18B
- Fixed DT, RF variable size interaction with restore.
- Fixed MT bug in MTTR.
@ -135,32 +215,40 @@ debugged. Do NOT enable these features for normal operations.
- Fixed bug in PDP-15 memory protect/skip interaction.
- Fixed bug in RF set size routine.
- Increased PTP TIME for PDP-15 operating systems.
- Fixed priorities in PDP-15 API (differs from PDP-9).
- Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9).
- Fixed bug in CAF, clears API subsystem.
4.7 PDP-8
4.8 PDP-8
- Fixed DT, DF, RF, RX variable size interaction with restore.
- Fixed MT bug in SKTR.
- Fixed bug in DF, RF set size routine.
4.8 HP2100
4.9 HP2100
- Fixed bug in DP (13210A controller only), DQ read status.
- Fixed bug in DP, DQ seek complete.
- Fixed DR drum sizes.
- Fixed DR variable capacity interaction with SAVE/RESTORE.
4.9 GRI
4.10 GRI
- Fixed bug in SC queue pointer management.
4.10 PDP-10
4.11 PDP-10
- Fixed bug in RP read header.
4.11 Ibm1130
4.12 Ibm1130
- Fixed bugs found by APL 1130.
4.12 Altairz80
4.13 Altairz80
- Fixed bug in real-time clock on Windows host.
4.14 1620
- Fixed bug in immediate index add (found by Michael Short).

View file

@ -8,7 +8,7 @@ DELQA (M7516) and DEQNA (M7504) Q-bus ethernet cards for the SIMH emulator.
The XQ emulator uses the Sim_Ether module to execute host-specific ethernet
packet reads and writes, since all operating systems talk to real ethernet
cards/controllers differently. The host-dependant Sim_Ether module currently
supports Windows, Linux, NetBSD, and OpenBSD.
supports Windows, Linux, NetBSD, OpenBSD, FreeBSD, OS/X, and Alpha VMS.
Currently, the Sim_Ether module sets the selected ethernet card into
promiscuous mode to gather all packets, then filters out the packets that it
@ -20,53 +20,138 @@ 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 direct or hub(repeater) segment.
Using the libpcap/WinPcap interface, the simulated computer cannot "talk" to
the host computer via the selected interface, since the packets are not
reflected back to the host. The workaround for this is to use a second NIC in
the host and connect them both into the same network; then the host and the
simulator can communicate over the physical LAN.
Universal TUN/TAP support provides another solution for the above dual-NIC
problem for systems that support Universal TUN/TAP. Since the TUN/TAP interface
is at a different network level, the host can create a TAP device for the
simulator and then bridge or route packets between the TAP device and the real
network interface. Note that the TAP device and any bridging or routing must be
established before running the simulator; SIMH does not create, bridge, or
route TAP devices for you.
-------------------------------------------------------------------------------
Windows notes:
1. The Windows-specific code uses the WinPCAP 3.0 package from
http://winpcap.polito.it. This package for windows simulates the libpcap
package that is freely available for unix systems.
package that is freely available for un*x systems.
2. You must *install* the WinPCAP runtime package.
3. 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. 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.
4. WinPCAP loops packet writes back into the read queue. This causes problems
since the XQ controller is not expecting to read it's own packet. A fix
to the packet read filter was added to reject packets from the current MAC,
but this defeats DECNET's duplicate node number detection scheme. A more
correct fix for WinPCAP will be explored as time allows.
the WinPCAP documentation for details on the static loading workaround.
4. If you want to use TAP devices, they must be created before running SIMH.
(TAP component from the OpenVPN project; http://openvpn.sourceforge.net)
5. Compaq PATHWORKS 32 v7.2 also enabled bridging for the ethernet adapters
when the DECNET and LAT drivers were installed; TAP was not needed.
Building on Windows:
1. Install WinPCAP 3.0.
1. Install WinPCAP 3.0 runtime and the WinPCAP Developer's kit.
2. Put the required .h files (bittypes,devioctl,ip6_misc,packet32,pcap,
pcap-stdinc).h from the WinPCAP 3.0 developer's kit in the compiler's path
3. Put the required .lib files (packet,wpcap).lib from the WinPCAP 3.0
developer's kit in the linker's path
4. If you're using Borland C++, use COFF2OMF to convert the .lib files into
a format that can be used by the compiler.
5. Define USE_NETWORK if you want the network functionality.
6. Build it!
-------------------------------------------------------------------------------
Linux, NetBSD, and OpenBSD notes:
Linux, {Free|Net|Open}BSD, OS/X, and Un*x notes:
1. You must run SIMH(scp) as root so that the ethernet card can be set into
promiscuous mode by the driver. Alternative methods for avoiding the
'run as root' requirement will be welcomed.
Building on Linux, NetBSD, and OpenBSD:
1. Get/install the libpcap package for your unix version. http://rpmfind.net
might be a useful site for finding the linux variants.
2. Use Make USE_NETWORK=1 if you want the network functionality.
2. If you want to use TAP devices, they must be created before running SIMH.
Linux, {Free|Net|Open}BSD, OS/X, Un*x notes:
1. Get/make/install the libpcap package for your operating system. Sources:
Linux : search for your variant on http://rpmfind.net
OS/X : Apple Developer's site?
Others : http://sourceforge.net/projects/libpcap/
2. Use 'make USE_NETWORK=1' if you want the network functionality.
3. Build it!
-------------------------------------------------------------------------------
OpenVMS Alpha notes:
1. Ethernet support will only work on Alpha VMS 7.3-1 or later, which is
when required VCI promiscuous mode support was added. Hobbyists can
get the required version of VMS from the OpenVMS Alpha Hobbyist Kit 3.0.
Running a simulator built with ethernet support on a version of VMS prior
to 7.3-1 will behave as if there is no ethernet support built in due to
the inability of the software to set the PCAPVCM into promiscuous mode.
An example display of fully functional ethernet support:
sim> SHOW XQ ETH
ETH devices:
0 we0 (VMS Device: _EWA0:)
1 we1 (VMS Device: _EWB0:)
An example display when the simulator was built without ethernet support
or is not running the required version of VMS:
sim> SHOW XQ ETH
ETH devices:
no network devices are available
2. You must place the PCAPVCM.EXE execlet in SYS$LOADABLE_IMAGES before
running a simulator with ethernet support.
3. You must have CMKRNL privilege to SHOW or ATTACH an ethernet device;
alternatively, you can INSTALL the simulator with CMKRNL privilege.
4. If you use a second adapter to communicate to the host, SOME protocol
that creates an I/O structure (SCS, DECNET, TCP) must be running on the
adapter prior trying to connect with SIMH, or the host may crash.
The execlet is not written to create an I/O structure for the device.
Building on OpenVMS Alpha:
1. Build the PCAP library and execlet. They are in the [.PCAP-VMS]
directory in the simh source distribution. The following builds
both the pcap library and the pcap execlet:
$ set def [.pcap-vms]
$ @build_all
Building VCI version of pcap...
Building the PCAP VCM execlet...
In order to use it, place PCAPVCM.EXE in the
SYS$LOADABLE_IMAGES directory.
%DCL-I-SUPERSEDE, previous value of PCAPVCM$OBJ has been superseded
To use the PCAPVCM.EXE execlet you must copy it to
the SYS$LOADABLE_IMAGES directory.
Build done...
2. To build the simulators with ethernet support, you
need to build them with MMS or MMK as follows:
$ MMx/MACRO=("__ALPHA__=1", "__PCAP__=1")
-------------------------------------------------------------------------------
VAX simulator support:
An OpenVMS VAX v7.2 system with DECNET Phase IV, MultiNet 4.4a, and LAT 5.3 has
been successfully run. Other testers have reported success booting NetBSD also.
been successfully run. Other testers have reported success booting NetBSD and
OpenVMS VAX 5.5-2 also.
PDP11 simulator support:
@ -88,15 +173,14 @@ Things planned for future releases:
-------------------------------------------------------------------------------
Things which I need help with:
1. Porting Sim_Ether packet driver to other host platforms, especially VMS.
2. Information about Remote MOP processing
3. VAX/PDP-11 hardware diagnotics image files and docs, to test XQ thoroughly.
4. Feedback on operation with other VAX/PDP-11 OS's.
1. Information about Remote MOP processing
2. VAX/PDP-11 hardware diagnotics image files and docs, to test XQ thoroughly.
3. Feedback on operation with other VAX/PDP-11 OS's.
-------------------------------------------------------------------------------
Please send all patches, questions, feedback, clarifications, and help to:
dhittner AT northropgrumman DOT com
david DOT hittner AT ngc DOT com
Thanks, and Enjoy!!
Dave
@ -106,33 +190,46 @@ Dave
Change Log
===============================================================================
26-Nov-03 Release:
1. Added VMS support to Sim_Ether; created pcap-vms port (Anders Ahgren)
2. Added DECNET duplicate detection for Windows (Mark Pizzolato)
3. Added BPF filtering to increase efficiency (Mark Pizzolato)
4. Corrected XQ Runt processing (Mark Pizzolato)
5. Corrected XQ Software Reset (Mark Pizzolato)
6. Corrected XQ Multicast/Promiscuous mode setting/resetting (Mark Pizzolato)
7. Added Universal TUN/TAP support (Mark Pizzolato)
8. Added FreeBSD support (Edward Brocklesby)
9. Corrected interrupts on XQB device (David Hittner)
-------------------------------------------------------------------------------
05-Jun-03 Release:
1. Added SET/SHOW XQ STATS
2. Added SHOW XQ FILTERS
3. Added ability to split received packet into multiple buffers
4. Added explicit runt & giant packet processing
1. Added SET/SHOW XQ STATS (David Hittner)
2. Added SHOW XQ FILTERS (David Hittner)
3. Added ability to split rcv packets into multiple buffers (David Hittner)
4. Added explicit runt & giant packet processing (David Hittner)
-------------------------------------------------------------------------------
30-May-03 Release:
1. Corrected bug in xq_setmac introduced in v3.0 (multiple people)
2. Made XQ receive buffer allocation dynamic to reduce scp executable size
3. Optimized some structs, removed legacy variables (Mark Pizzolato)
4. Changed #ifdef WIN32 to _WIN32 for consistancy
1. Corrected bug in xq_setmac introduced in v3.0 (multiple people)
2. Made XQ rcv buffer allocation dynamic to reduce scp size (David Hittner)
3. Optimized some structs, removed legacy variables (Mark Pizzolato)
4. Changed #ifdef WIN32 to _WIN32 for consistancy (Mark Pizzolato)
-------------------------------------------------------------------------------
06-May-03 Release:
1. Added second XQ controller
2. Added SIMH v3.0 compatibility
3. Removed SET ADDRESS functionality
1. Added second XQ controller (David Hittner)
2. Added SIMH v3.0 compatibility (David Hittner)
3. Removed SET ADDRESS functionality (David Hittner)
-------------------------------------------------------------------------------
10-Apr-03 Release:
1. Added preliminary support for RSTS/E
2. Added PDP-11 bootrom load via CSR flags
3. Support for SPARC linux (thanks to Mark Pizzolato)
1. Added preliminary support for RSTS/E (David Hittner)
2. Added PDP-11 bootrom load via CSR flags (David Hittner)
3. Support for SPARC linux (Mark Pizzolato)
-------------------------------------------------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* gri_stddev.c: GRI-909 standard devices
Copyright (c) 2001-2003, Robert M Supnik
Copyright (c) 2001-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -29,6 +29,7 @@
hsp S42-006 high speed punch
rtc real time clock
29-Dec-03 RMS Added support for console backpressure
25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support
01-Nov-02 RMS Added 7b/8B support to terminal
@ -246,12 +247,14 @@ t_stat tto_svc (UNIT *uptr)
int32 c;
t_stat r;
dev_done = dev_done | INT_TTO; /* set ready */
if (tto_unit.flags & UNIT_KSR) { /* KSR? */
c = tto_unit.buf & 0177; /* force 7b */
if (islower (c)) c = toupper (c); } /* cvt to UC */
else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
if ((r = sim_putchar (c)) != SCPE_OK) return r; /* output */
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */
dev_done = dev_done | INT_TTO; /* set ready */
tto_unit.pos = tto_unit.pos + 1;
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* h316_cpu.c: Honeywell 316/516 CPU simulator
Copyright (c) 1999-2003, Robert M. Supnik
Copyright (c) 1999-2004, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
cpu H316/H516 CPU
31-Dec-03 RMS Fixed bug in cpu_set_hist
24-Oct-03 RMS Added DMA/DMC support, instruction history
30-Dec-01 RMS Added old PC queue
03-Nov-01 RMS Fixed NOHSA modifier
30-Nov-01 RMS Added extended SET/SHOW support
@ -167,10 +169,10 @@
2. Interrupts. Interrupts are maintained by two parallel variables:
dev_ready device ready flags
dev_enable device interrupt enable flags
dev_int device interrupt flags
dev_enb device interrupt enable flags
In addition, dev_ready contains the interrupt enable and interrupt no
In addition, dev_int contains the interrupt enable and interrupt no
defer flags. If interrupt enable and interrupt no defer are set, and
at least one interrupt request is pending, then an interrupt occurs.
The order of flags in these variables corresponds to the order
@ -194,8 +196,6 @@
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
#define PCQ_TOP pcq[pcq_p]
#define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */
#define UNIT_MSIZE (1u << UNIT_V_MSIZE)
#define m7 0001000 /* for generics */
#define m8 0000400
#define m9 0000200
@ -207,6 +207,20 @@
#define m15 0000002
#define m16 0000001
#define HIST_PC 0x40000000
#define HIST_C 0x20000000
#define HIST_EA 0x10000000
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
int32 pc;
int32 ir;
int32 ar;
int32 br;
int32 xr;
int32 ea;
int32 opnd; };
uint16 M[MAXMEMSIZE] = { 0 }; /* memory */
int32 saved_AR = 0; /* A register */
int32 saved_BR = 0; /* B register */
@ -219,27 +233,44 @@ int32 extoff_pending = 0; /* extend off pending */
int32 dp = 0; /* double mode */
int32 sc = 0; /* shift count */
int32 ss[4]; /* sense switches */
int32 dev_ready = 0; /* dev ready */
int32 dev_enable = 0; /* dev enable */
int32 dev_int = 0; /* dev ready */
int32 dev_enb = 0; /* dev enable */
int32 ind_max = 8; /* iadr nest limit */
int32 stop_inst = 1; /* stop on ill inst */
int32 stop_dev = 2; /* stop on ill dev */
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
int32 dlog = 0; /* debug log */
int32 turnoff = 0;
uint32 dma_nch = DMA_MAX; /* number of chan */
uint32 dma_ad[DMA_MAX] = { 0 }; /* DMA addresses */
uint32 dma_wc[DMA_MAX] = { 0 }; /* DMA word count */
uint32 dma_eor[DMA_MAX] = { 0 }; /* DMA end of range */
uint32 chan_req = 0; /* channel requests */
uint32 chan_map[DMA_MAX + DMC_MAX] = { 0 }; /* chan->dev map */
int32 (*iotab[DEV_MAX])(int32 inst, int32 fnc, int32 dat, int32 dev) = { NULL };
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
extern int32 sim_int_char;
extern int32 sim_interval;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern FILE *sim_log;
extern DEVICE *sim_devices[];
t_bool devtab_init (void);
int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev);
int32 undio (int32 inst, int32 fnc, int32 dat, int32 dev);
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_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc);
extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
@ -252,7 +283,9 @@ extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
cpu_mod CPU modifiers list
*/
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_EXT,
DIB cpu_dib = { DMA, IOBUS, 1, &dmaio };
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_EXT+UNIT_HSA+UNIT_DMC,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -270,19 +303,23 @@ REG cpu_reg[] = {
{ FLDATA (SS2, ss[1], 0) },
{ FLDATA (SS3, ss[2], 0) },
{ FLDATA (SS4, ss[3], 0) },
{ FLDATA (ION, dev_ready, INT_V_ON) },
{ FLDATA (INODEF, dev_ready, INT_V_NODEF) },
{ ORDATA (DEVRDY, dev_ready, 16), REG_RO },
{ ORDATA (DEVENB, dev_enable, 16), REG_RO },
{ FLDATA (MPERDY, dev_ready, INT_V_MPE) },
{ FLDATA (MPEENB, dev_enable, INT_V_MPE) },
{ FLDATA (ION, dev_int, INT_V_ON) },
{ FLDATA (INODEF, dev_int, INT_V_NODEF) },
{ ORDATA (DEVINT, dev_int, 16), REG_RO },
{ ORDATA (DEVENB, dev_enb, 16), REG_RO },
{ ORDATA (CHREQ, chan_req, DMA_MAX + DMC_MAX) },
{ BRDATA (DMAAD, dma_ad, 8, 16, DMA_MAX) },
{ BRDATA (DMAWC, dma_wc, 8, 16, DMA_MAX) },
{ BRDATA (DMAEOR, dma_eor, 8, 1, DMA_MAX) },
{ ORDATA (DMANCH, dma_nch, 3), REG_HRO },
{ FLDATA (MPERDY, dev_int, INT_V_MPE) },
{ FLDATA (MPEENB, dev_enb, INT_V_MPE) },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ FLDATA (STOP_DEV, stop_dev, 1) },
{ DRDATA (INDMAX, ind_max, 8), REG_NZ + PV_LEFT },
{ BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO + REG_CIRC },
{ ORDATA (PCQP, pcq_p, 6), REG_HRO },
{ ORDATA (WRU, sim_int_char, 8) },
{ FLDATA (DLOG, dlog, 0), REG_HIDDEN },
{ NULL } };
MTAB cpu_mod[] = {
@ -296,47 +333,42 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
{ MTAB_XTD | MTAB_VDV, 0, "channels", "CHANNELS",
&cpu_set_nchan, &cpu_show_nchan, NULL },
{ UNIT_DMC, 0, "no DMC", "NODMC", NULL },
{ UNIT_DMC, UNIT_DMC, "DMC", "DMC", NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DMA1", NULL,
NULL, &cpu_show_dma, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DMA2", NULL,
NULL, &cpu_show_dma, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 2, "DMA3", NULL,
NULL, &cpu_show_dma, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 3, "DMA4", NULL,
NULL, &cpu_show_dma, NULL },
{ 0 } };
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 8, 15, 1, 8, 16,
&cpu_ex, &cpu_dep, &cpu_reset,
NULL, NULL, NULL };
/* I/O dispatch */
int32 undio (int32 op, int32 func, int32 AR);
extern int32 ptrio (int32 op, int32 func, int32 AR);
extern int32 ptpio (int32 op, int32 func, int32 AR);
extern int32 lptio (int32 op, int32 func, int32 AR);
extern int32 ttyio (int32 op, int32 func, int32 AR);
extern int32 clkio (int32 op, int32 func, int32 AR);
int32 (*iotab[64])() = {
&undio, &ptrio, &ptpio, &lptio, &ttyio, &undio, &undio, &undio,
&undio, &undio, &undio, &undio, &undio, &undio, &undio, &undio,
&clkio, &undio, &undio, &undio, &undio, &undio, &undio, &undio,
&undio, &undio, &undio, &undio, &undio, &undio, &undio, &undio,
&undio, &undio, &undio, &undio, &undio, &undio, &undio, &undio,
&undio, &undio, &undio, &undio, &undio, &undio, &undio, &undio,
&undio, &undio, &undio, &undio, &undio, &undio, &undio, &undio,
&undio, &undio, &undio, &undio, &undio, &undio, &undio, &undio };
NULL, NULL, NULL,
&cpu_dib, 0 };
t_stat sim_instr (void)
{
extern UNIT clk_unit;
int32 AR, BR, MB, Y, t1, t2, t3, skip;
int32 AR, BR, MB, Y, t1, t2, t3, skip, dev;
uint32 ut;
t_stat reason;
t_stat Ea (int32 inst, int32 *addr);
void Write (int32 val, int32 addr);
void Write (int32 addr, int32 val);
int32 Add16 (int32 val1, int32 val2);
int32 Add31 (int32 val1, int32 val2);
int32 Operate (int32 MB, int32 AR);
#define Read(x) M[(x)]
#define Read(ad) M[(ad)]
#define GETDBL_S(h,l) (((h) << 15) | ((l) & MMASK))
#define GETDBL_U(h,l) (((h) << 16) | (l))
#define PUTDBL_S(x) AR = ((x) >> 15) & DMASK; \
@ -349,12 +381,12 @@ int32 Operate (int32 MB, int32 AR);
/* Restore register state */
if (devtab_init ()) return SCPE_STOP; /* init tables */
AR = saved_AR & DMASK; /* restore reg */
BR = saved_BR & DMASK;
XR = saved_XR & DMASK;
PC = PC & ((cpu_unit.flags & UNIT_EXT)? X_AMASK: NX_AMASK); /* mask PC */
reason = 0;
turnoff = 0;
sim_rtc_init (clk_unit.wait); /* init calibration */
/* Main instruction fetch/decode loop */
@ -363,14 +395,59 @@ while (reason == 0) { /* loop until halted */
if (sim_interval <= 0) { /* check clock queue */
if (reason = sim_process_event ()) break; }
if ((dev_ready & (INT_PENDING | dev_enable)) > INT_PENDING) { /* int req? */
/* Channel breaks (DMA and DMC) */
if (chan_req) { /* channel request? */
int32 i, t, ch, dev, st, end, ad, dmcad;
t_stat r;
for (i = 0, ch = chan_req; ch != 0; i++, ch = ch >> 1) {
if (ch & 1) { /* req on chan i? */
dev = chan_map[i]; /* get dev for chan */
if (iotab[dev] == &undio) return SCPE_IERR;
chan_req = chan_req & ~(1 << i); /* clear req */
if (Q_DMA (i)) st = dma_ad[i]; /* DMA? */
else { /* DMC */
dmcad = DMC_BASE + ((i - DMC_V_DMC1) << 1);
st = Read (dmcad); } /* DMC ctrl word */
ad = st & X_AMASK; /* get curr addr */
if (st & DMA_IN) { /* input? */
t = iotab[dev] (ioINA, 0, 0, dev); /* input word */
if ((t & IOT_SKIP) == 0) return STOP_DMAER;
if (r = (t >> IOT_V_REASON)) return r;
Write (ad, t & DMASK); } /* write to mem */
else { /* no, output */
t = iotab[dev] (ioOTA, 0, Read (ad), dev); /* output word */
if ((t & IOT_SKIP) == 0) return STOP_DMAER;
if (r = (t >> IOT_V_REASON)) return r; }
if (Q_DMA (i)) { /* DMA? */
dma_ad[i] = (dma_ad[i] & DMA_IN) | ((ad + 1) & X_AMASK);
dma_wc[i] = (dma_wc[i] + 1) & 077777; /* update wc */
if (dma_wc[i] == 0) { /* done? */
dma_eor[i] = 1; /* set end of range */
t = iotab[dev] (ioEND, 0, 0, dev); /* send end range */
if (r = (t >> IOT_V_REASON)) return r; } }
else { /* DMC */
st = (st & DMA_IN) | ((ad + 1) & X_AMASK);
Write (dmcad, st); /* update start */
end = Read (dmcad + 1); /* get end */
if (((ad ^ end) & X_AMASK) == 0) { /* start == end? */
t = iotab[dev] (ioEND, 0, 0, dev); /* send end range */
if (r = (t >> IOT_V_REASON)) return r; } }
} /* end if chan i */
} /* end for */
} /* end if chan_req */
/* Interrupts */
if ((dev_int & (INT_PENDING | dev_enb)) > INT_PENDING) { /* int req? */
pme = ext; /* save extend */
if (cpu_unit.flags & UNIT_EXT) ext = 1; /* ext opt? extend on */
dev_ready = dev_ready & ~INT_ON; /* intr off */
turnoff = 0;
if (dlog && sim_log) fprintf (sim_log, "Interrupt\n");
dev_int = dev_int & ~INT_ON; /* intr off */
MB = 0120000 | M_INT; } /* inst = JST* 63 */
/* Instruction fetch */
else { if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
@ -378,16 +455,17 @@ else { if (sim_brk_summ &&
Y = PC; /* set mem addr */
MB = Read (Y); /* fetch instr */
PC = NEWA (Y, Y + 1); /* incr PC */
dev_ready = dev_ready | INT_NODEF; }
dev_int = dev_int | INT_NODEF; }
sim_interval = sim_interval - 1;
if (dlog && sim_log && !turnoff) { /* cycle log? */
int32 op = I_GETOP (MB) & 017; /* core opcode */
t_value val = MB;
fprintf (sim_log, "A= %06o C= %1o P= %05o (", AR, C, PC);
fprint_sym (sim_log, Y, &val, &cpu_unit, SWMASK ('M'));
fprintf (sim_log, ")");
if ((op == 0) || (op == 014)) fprintf (sim_log, "\n"); }
if (hst_lnt) { /* instr hist? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt) hst_p = 0;
hst[hst_p].pc = Y | HIST_PC | (C? HIST_C: 0); /* fill slots */
hst[hst_p].ir = MB;
hst[hst_p].ar = AR;
hst[hst_p].br = BR;
hst[hst_p].xr = XR; }
/* Memory reference instructions */
@ -397,12 +475,6 @@ case 001: case 021: case 041: case 061: /* JMP */
if (reason = Ea (MB, &Y)) break; /* eff addr */
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 */
if (extoff_pending) ext = extoff_pending = 0; /* cond ext off */
break;
@ -423,10 +495,10 @@ 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 */
if ((Y & 1) == 0) Write (Y, AR); /* if even, store A */
Write (Y | 1, BR); /* store B */
sc = 0; }
else Write (AR, Y); /* no, store word */
else Write (Y, AR); /* no, store word */
break;
case 005: case 025: case 045: case 065: /* ERA */
@ -461,7 +533,7 @@ case 007: case 027: case 047: case 067: /* SUB */
case 010: case 030: case 050: case 070: /* JST */
if (reason = Ea (MB, &Y)) break; /* eff addr */
MB = NEWA (Read (Y), PC); /* merge old PC */
Write (MB, Y);
Write (Y, MB);
PCQ_ENTRY;
PC = NEWA (PC, Y + 1); /* set new PC */
break;
@ -476,20 +548,20 @@ case 011: case 031: case 051: case 071: /* CAS */
case 012: case 032: case 052: case 072: /* IRS */
if (reason = Ea (MB, &Y)) break; /* eff addr */
MB = (Read (Y) + 1) & DMASK; /* incr, rewrite */
Write (MB, Y);
Write (Y, MB);
if (MB == 0) PC = NEWA (PC, PC + 1); /* skip if zero */
break;
case 013: case 033: case 053: case 073: /* IMA */
if (reason = Ea (MB, &Y)) break; /* eff addr */
MB = Read (Y);
Write (AR, Y); /* A to mem */
Write (Y, AR); /* A to mem */
AR = MB; /* mem to A */
break;
case 015: case 055: /* STX */
if (reason = Ea (MB & ~IDX, &Y)) break; /* eff addr */
Write (XR, Y); /* store XR */
Write (Y, XR); /* store XR */
break;
case 035: case 075: /* LDX */
@ -525,35 +597,32 @@ case 017: case 037: case 057: case 077: /* DIV */
/* I/O instructions */
case 014: /* OCP */
t2 = iotab[MB & DEVMASK] (ioOCP, I_GETFNC (MB), AR);
dev = MB & DEVMASK;
t2 = iotab[dev] (ioOCP, I_GETFNC (MB), AR, dev);
reason = t2 >> IOT_V_REASON;
turnoff = 0;
break;
case 034: /* SKS */
t2 = iotab[MB & DEVMASK] (ioSKS, I_GETFNC (MB), AR);
dev = MB & DEVMASK;
t2 = iotab[dev] (ioSKS, I_GETFNC (MB), AR, dev);
reason = t2 >> IOT_V_REASON;
if (t2 & IOT_SKIP) { /* skip? */
PC = NEWA (PC, PC + 1);
turnoff = 0; }
if (t2 & IOT_SKIP) PC = NEWA (PC, PC + 1); /* skip? */
break;
case 054: /* INA */
dev = MB & DEVMASK;
if (MB & INCLRA) AR = 0;
t2 = iotab[MB & DEVMASK] (ioINA, I_GETFNC (MB), AR);
t2 = iotab[dev] (ioINA, I_GETFNC (MB & ~INCLRA), AR, dev);
reason = t2 >> IOT_V_REASON;
if (t2 & IOT_SKIP) { /* skip? */
PC = NEWA (PC, PC + 1);
turnoff = 0; }
if (t2 & IOT_SKIP) PC = NEWA (PC, PC + 1); /* skip? */
AR = t2 & DMASK; /* data */
break;
case 074: /* OTA */
t2 = iotab[MB & DEVMASK] (ioOTA, I_GETFNC (MB), AR);
dev = MB & DEVMASK;
t2 = iotab[dev] (ioOTA, I_GETFNC (MB), AR, dev);
reason = t2 >> IOT_V_REASON;
if (t2 & IOT_SKIP) { /* skip? */
PC = NEWA (PC, PC + 1);
turnoff = 0; }
if (t2 & IOT_SKIP) PC = NEWA (PC, PC + 1); /* skip? */
break;
/* Control */
@ -571,8 +640,7 @@ case 000:
ext = 1;
extoff_pending = 0; } /* DXA */
else extoff_pending = 1; }
if (MB & m12) /* RMP */
dev_ready = dev_ready & ~INT_MPE;
if (MB & m12) CLR_INT (INT_MPE); /* RMP */
if (MB & m11) { /* SCA, INK */
if (MB & m15) /* INK */
AR = (C << 15) | (dp << 14) | (pme << 13) | (sc & 037);
@ -594,9 +662,9 @@ case 000:
BR = AR;
AR = sc; }
if (MB & m8) /* ENB */
dev_ready = (dev_ready | INT_ON) & ~INT_NODEF;
dev_int = (dev_int | INT_ON) & ~INT_NODEF;
if (MB & m7) /* INH */
dev_ready = dev_ready & ~INT_ON;
dev_int = dev_int & ~INT_ON;
break;
/* Shift
@ -841,15 +909,17 @@ else { /* non-extend */
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? */
fprintf (sim_log, " EA= %06o [%06o]\n", Y, M[Y]);
if (hst_lnt) { /* history? */
hst[hst_p].pc = hst[hst_p].pc | HIST_EA;
hst[hst_p].ea = Y;
hst[hst_p].opnd = Read (Y); }
if (i >= ind_max) return STOP_IND; /* too many ind? */
return SCPE_OK;
}
/* Write memory */
void Write (int32 val, int32 addr)
void Write (int32 addr, int32 val)
{
if (((addr == 0) || (addr >= 020)) && MEM_ADDR_OK (addr))
M[addr] = val;
@ -878,10 +948,34 @@ return r;
/* Unimplemented I/O device */
int32 undio (int32 op, int32 fnc, int32 val)
int32 undio (int32 op, int32 fnc, int32 val, int32 dev)
{
return ((stop_dev << IOT_V_REASON) | val);
}
/* DMA control */
int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
int32 ch = (fnc - 1) & 03;
switch (inst) { /* case on opcode */
case ioOCP: /* OCP */
if ((fnc >= 001) && (fnc <= 004)) { /* load addr ctr */
dma_ad[ch] = dat;
dma_wc[ch] = 0;
dma_eor[ch] = 0; }
else if ((fnc >= 011) && (fnc <= 014)) /* load range ctr */
dma_wc[ch] = (dma_wc[ch] | dat) & 077777;
else return IOBADFNC (dat); /* undefined */
break;
case ioINA: /* INA */
if ((fnc >= 011) && (fnc <= 014)) {
if (dma_eor[ch]) return dat; /* end range? nop */
return IOSKIP (0100000 | dma_wc[ch]); } /* return range */
else return IOBADFNC (dat); }
return dat;
}
/* Undefined operate instruction. This code is reached when the
opcode does not correspond to a standard operate instruction.
@ -1027,12 +1121,16 @@ return ARx;
t_stat cpu_reset (DEVICE *dptr)
{
int32 i;
saved_AR = saved_BR = saved_XR = 0;
C = 0;
dp = 0;
ext = pme = extoff_pending = 0;
dev_ready = dev_ready & ~INT_PENDING;
dev_enable = 0;
dev_int = dev_int & ~INT_PENDING;
dev_enb = 0;
for (i = 0; i < DMA_MAX; i++) dma_ad[i] = dma_wc[i] = dma_eor[i] = 0;
chan_req = 0;
pcq_r = find_reg ("PCQ", NULL, dptr);
if (pcq_r) pcq_r->qptr = 0;
else return SCPE_IERR;
@ -1086,3 +1184,216 @@ MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}
t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i, newmax;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
newmax = get_uint (cptr, 10, DMA_MAX, &r); /* get new max */
if ((r != SCPE_OK) || (newmax == dma_nch)) return r; /* err or no chg? */
dma_nch = newmax; /* set new max */
for (i = newmax; i <DMA_MAX; i++) { /* reset chan */
dma_ad[i] = dma_wc[i] = dma_eor[i] = 0;
chan_req = chan_req & ~(1 << i); }
return SCPE_OK;
}
/* Show DMA channels */
t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc)
{
if (dma_nch) fprintf (st, "DMA channels = %d", dma_nch);
else fprintf (st, "no DMA channels");
return SCPE_OK;
}
/* Show channel state */
t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc)
{
if ((val < 0) || (val >= DMA_MAX)) return SCPE_IERR;
fputs ((dma_ad[val] & DMA_IN)? "Input": "Output", st);
fprintf (st, ", addr = %06o, count = %06o, ", dma_ad[val] & X_AMASK, dma_wc[val]);
fprintf (st, "end of range %s\n", (dma_eor[val]? "set": "clear"));
return SCPE_OK;
}
/* Set I/O device to IOBUS / DMA channel / DMC channel */
t_stat io_set_iobus (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
if (val || cptr || (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;
dibp->chan = 0;
return SCPE_OK;
}
t_stat io_set_dma (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newc;
t_stat r;
if ((cptr == NULL) || (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;
if (dma_nch == 0) return SCPE_NOFNC;
newc = get_uint (cptr, 10, DMA_MAX, &r); /* get new */
if ((r != SCPE_OK) || (newc == 0) || (newc > dma_nch)) return SCPE_ARG;
dibp->chan = (newc - DMA_MIN) + DMA_V_DMA1 + 1; /* store */
return SCPE_OK;
}
t_stat io_set_dmc (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newc;
t_stat r;
if ((cptr == NULL) || (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;
if (!(cpu_unit.flags & UNIT_DMC)) return SCPE_NOFNC;
newc = get_uint (cptr, 10, DMC_MAX, &r); /* get new */
if ((r != SCPE_OK) || (newc == 0)) return SCPE_ARG;
dibp->chan = (newc - DMC_MIN) + DMC_V_DMC1 + 1; /* store */
return SCPE_OK;
}
/* Show channel configuration */
t_stat io_show_chan (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) return SCPE_IERR;
if (dibp->chan == 0) fprintf (st, "IO bus");
else if (dibp->chan < (DMC_V_DMC1 + 1))
fprintf (st, "DMA channel %d", dibp->chan);
else fprintf (st, "DMC channel %d", dibp->chan - DMC_V_DMC1);
return SCPE_OK;
}
/* Set up I/O dispatch and channel maps */
t_bool devtab_init (void)
{
DEVICE *dptr;
DIB *dibp;
uint32 i, j, dno, chan;
for (i = 0; i < DEV_MAX; i++) iotab[i] = NULL;
for (i = 0; i < (DMA_MAX + DMC_MAX); i++) chan_map[i] = 0;
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->dev; /* device number */
for (j = 0; j < dibp->num; j++) { /* repeat for slots */
if (iotab[dno + j]) { /* conflict? */
printf ("%s device number conflict, devno = %02o\n", sim_dname (dptr), dno + j);
if (sim_log) fprintf (sim_log,
"%s device number conflict, devno = %02o\n", sim_dname (dptr), dno + j);
return TRUE; }
iotab[dno + j] = dibp->io; /* set I/O routine */
} /* end for */
if (dibp->chan) { /* DMA/DMC? */
chan = dibp->chan - 1;
if ((chan >= 0) && (chan < DMC_V_DMC1) && (chan >= dma_nch)) {
printf ("%s configured for DMA channel %d\n", sim_dname (dptr), chan + 1);
if (sim_log) fprintf (sim_log,
"%s configured for DMA channel %d\n", sim_dname (dptr), chan + 1);
return TRUE; }
if ((chan >= DMC_V_DMC1) && !(cpu_unit.flags & UNIT_DMC)) {
printf ("%s configured for DMC, option disabled\n", sim_dname (dptr));
if (sim_log) fprintf (sim_log,
"%s configured for DMC, option disabled\n", sim_dname (dptr));
return TRUE; }
if (chan_map[chan]) { /* channel conflict? */
printf ("%s DMA/DMC channel conflict, devno = %02o\n", sim_dname (dptr), dno);
if (sim_log) fprintf (sim_log,
"%s DMA/DMC channel conflict, devno = %02o\n", sim_dname (dptr), dno);
return TRUE; }
chan_map[chan] = dno; } /* channel back map */
} /* end for */
for (i = 0; i < DEV_MAX; i++) { /* fill in blanks */
if (iotab[i] == NULL) iotab[i] = &undio; }
return FALSE;
}
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 cr, k, di, op;
t_value sim_eval;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
static uint8 has_opnd[16] = {
0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 };
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
fprintf (st, "PC C A B X ea IR\n\n");
di = hst_p; /* work forward */
for (k = 0; k < hst_lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
cr = (h->pc & HIST_C)? 1: 0; /* carry */
fprintf (st, "%05o %o %06o %06o %06o ",
h->pc & X_AMASK, cr, h->ar, h->br, h->xr);
if (h->pc & HIST_EA) fprintf (st, "%05o ", h->ea);
else fprintf (st, " ");
sim_eval = h->ir;
if ((fprint_sym (st, h->pc & X_AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %06o", h->ir);
op = I_GETOP (h->ir) & 017; /* base op */
if (has_opnd[op]) fprintf (st, " [%06o]", h->opnd);
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -23,9 +23,13 @@
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.
24-Oct-03 RMS Added DMA/DMC support
25-Apr-03 RMS Revised for extended file support
*/
#ifndef _H316_DEFS_H_
#define _H316_DEFS_H_ 0
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
@ -35,6 +39,10 @@
#define STOP_HALT 3 /* HALT */
#define STOP_IBKPT 4 /* breakpoint */
#define STOP_IND 5 /* indirect loop */
#define STOP_DMAER 6 /* DMA error */
#define STOP_MTWRP 7 /* MT write protected */
#define STOP_DPOVR 8 /* DP write overrun */
#define STOP_DPFMT 9 /* DP invalid format */
/* Memory */
@ -56,10 +64,14 @@
/* CPU options */
#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */
#define UNIT_V_EXT (UNIT_V_UF + 1) /* extended mem */
#define UNIT_V_HSA (UNIT_V_UF + 2) /* high speed arith */
#define UNIT_V_DMC (UNIT_V_UF + 3) /* DMC */
#define UNIT_MSIZE (1u << UNIT_V_MSIZE)
#define UNIT_EXT (1u << UNIT_V_EXT)
#define UNIT_HSA (1u << UNIT_V_HSA)
#define UNIT_DMC (1u << UNIT_V_DMC)
/* Instruction format */
@ -84,8 +96,42 @@
#define ioSKS 1 /* skip if set */
#define ioINA 2 /* input to A */
#define ioOTA 3 /* output from A */
#define ioEND 4 /* channel end */
/* I/O devices */
/* Device information block */
struct h316_dib {
uint32 dev; /* device number */
uint32 chan; /* dma/dmc channel */
uint32 num; /* number of slots */
int32 (*io) (int32 inst, int32 fnc, int32 dat, int32 dev); };
typedef struct h316_dib DIB;
/* DMA/DMC channel numbers */
#define IOBUS 0 /* IO bus */
#define DMA_MIN 1 /* 4 DMA channels */
#define DMA_MAX 4
#define DMC_MIN 1 /* 16 DMC channels */
#define DMC_MAX 16
#define DMA1 (DMA_MIN)
#define DMC1 (DMA_MAX+DMC_MIN)
/* DMA/DMC bit assignments in channel request word */
#define DMA_V_DMA1 0 /* DMA channels */
#define DMC_V_DMC1 4 /* DMC channels */
#define SET_CH_REQ(x) chan_req = chan_req | (1 << (x))
#define Q_DMA(x) (((x) >= 0) && ((x) < DMC_V_DMC1))
/* DMA/DMC definitions */
#define DMA_IN 0100000 /* input flag */
#define DMC_BASE 020 /* DMC memory base */
/* I/O device codes */
#define PTR 001 /* paper tape reader */
#define PTP 002 /* paper tape punch */
@ -93,11 +139,11 @@
#define TTY 004 /* console */
#define CDR 005 /* card reader */
#define MT 010 /* mag tape data */
#define KEYS 020 /* keys (CPU) */
#define CLK_KEYS 020 /* clock/keys (CPU) */
#define FHD 022 /* fixed head disk */
#define DMA 024 /* DMA control */
#define DP 025 /* moving head disk */
#define OPT 034 /* SKS/OCP option */
#define DEV_MAX 64
/* Interrupt flags, definitions correspond to SMK bits */
@ -119,7 +165,7 @@
#define IOT_V_REASON 17
#define IOT_V_SKIP 16
#define IOT_SKIP (1u << IOT_V_SKIP)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
#define IORETURN(f,v) (((f)? (v): SCPE_OK) << IOT_V_REASON)
#define IOBADFNC(x) (((stop_inst) << IOT_V_REASON) | (x))
#define IOSKIP(x) (IOT_SKIP | (x))
@ -137,8 +183,17 @@
#define INT_ON (1u << INT_V_ON)
#define INT_PENDING (INT_ON | INT_NODEF)
#define SET_READY(x) dev_ready = dev_ready | (x)
#define CLR_READY(x) dev_ready = dev_ready & ~(x)
#define TST_READY(x) ((dev_ready & (x)) != 0)
#define CLR_ENABLE(x) dev_enable = dev_enable & ~(x)
#define TST_INTREQ(x) ((dev_ready & dev_enable & (x)) != 0)
#define SET_INT(x) dev_int = dev_int | (x)
#define CLR_INT(x) dev_int = dev_int & ~(x)
#define TST_INT(x) ((dev_int & (x)) != 0)
#define CLR_ENB(x) dev_enb = dev_enb & ~(x)
#define TST_INTREQ(x) ((dev_int & dev_enb & (x)) != 0)
/* Prototypes */
t_stat io_set_iobus (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat io_set_dma (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat io_set_dmc (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat io_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc);
#endif

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: H316 Simulator Usage
Date: 15-Jul-2003
Date: 15-Nov-2003
COPYRIGHT NOTICE
@ -41,15 +41,20 @@ The H316 requires the following files:
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tape.h
sim_tmxr.h
scp.c
scp_tty.c
sim_sock.c
sim_tape.c
sim_tmxr.c
sim/h316/ h316_defs.h
h316_cpu.c
h316_fhd.c
h316_lp.c
h316_mt.c
h316_dp.c
h316_stddev.c
h316_sys.c
@ -66,6 +71,9 @@ PTP 316/516-52 paper tape punch
TTY 316/516-33 console terminal
CLK 316/516-12 real time clock
LPT 316/516 line printer
FHD 4400 fixed head disk
DP 4623/4653/4720 disk pack controller with eight drives
MT 4100 seven track magtape with four drives
The H316/H516 simulator implements several unique stop conditions:
@ -73,12 +81,19 @@ The H316/H516 simulator implements several unique stop conditions:
- reference to an undefined I/O device, and STOP_DEV is set
- more than INDMAX indirect references are detected during
memory reference address decoding
- DMA/DMC direction does not agree with I/O device operation
- a write operation is initiated on a write locked magtape
unit (hangs the real system)
- a disk write overruns the specified record size (destroys
the rest of the track on the real system)
- a disk track has an illegal format
The H316/H516 loader is not implemented.
2.1 CPU
CPU options include choice of instruction set and memory size.
CPU options include choice of instruction set, memory size, DMC option,
and number of DMA channels.
SET CPU HSA high speed arithmetic instructions
SET CPU NOHSA no high speed arithmetic instructions
@ -88,10 +103,19 @@ CPU options include choice of instruction set and memory size.
SET CPU 16K set memory size = 16K
SET CPU 24K set memory size = 24K
SET CPU 32K set memory size = 32K
SET CPU DMC enable DMC option
SET CPU NODMC disable DMC option
SET CPU DMA=n set number of DMA channels to n (0-4)
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 32K.
portion of memory is lost. Initial memory size is 32K. The HSA and DMC
options are enabled, and four DMA channels are configured.
The CPU includes special show commands to display the state of the DMA
channels:
SHOW CPU DMAn show DMA channel n
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
@ -114,6 +138,10 @@ control registers for the interrupt system.
INTREQ 16 interrupt requests
DEVRDY 16 device ready flags (read only)
DEVENB 16 device interrupt enable flags (read only)
CHREQ 20 DMA/DMC channel requests
DMAAD[0:3] 16 DMA channel current address, channels 1-4
DMAWC[0:3] 15 DMA channel word count, channels 1-4
DMAEOR[0:3] 1 DMA end of range flag, channels 1-4
STOP_INST 1 stop on undefined instruction
STOP_DEV 1 stop on undefined device
INDMAX 1 indirect address limit
@ -230,12 +258,21 @@ The clock implements these registers:
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.2.5 316/516 Line Printer (LPT)
2.3 316/516 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The line printer can be connected to the IO bus, a DMC channel, or
a DMA channel:
SET LPT IOBUS connect to IO bus
SET LPT DMC=n connect to DMC channel n (1-16)
SET LPT DMA=n connect to DMA channel n (1-4)
By default, the line printer is connected to the IO bus.
The line printer implements these registers:
name size comments
@ -243,8 +280,10 @@ The line printer implements these registers:
WDPOS 6 word position in current scan
DRPOS 6 drum position
CRPOS 1 carriage position
XFER 1 transfer ready flag
PRDN 1 print done flag
RDY 1 ready flag
EOR 1 (DMA/DMC) end of range flag
DMA 1 transfer using DMA/DMC
INTREQ 1 device interrupt request
ENABLE 1 device interrupt enable
SVCST 2 service state
@ -265,7 +304,207 @@ Error handling is as follows:
OS I/O error x report error and stop
2.3 Symbolic Display and Input
2.4 4400 Fixed Head Disk (FHD)
Fixed head disk options include the ability to set the number of
surfaces to a fixed value between 1 and 16, or to autosize the number
of surfaces from the attached file:
SET FHD 1S one surface (98K)
SET FHD 2S two platters (196K)
:
SET FHD 16S sixteen surfaces (1568K)
SET FHD AUTOSIZE autosized on attach
The default is one surface.
The fixed head disk can be connected to the IO bus, a DMC channel, or
a DMA channel:
SET FHD IOBUS connect to IO bus
SET FHD DMC=n connect to DMC channel n (1-16)
SET FHD DMA=n connect to DMA channel n (1-4)
By default, the fixed head disk is connected to the IO bus.
The fixed head disk implements these registers:
name size comments
CW1 16 control word 1 (read write, surface, track)
CW2 16 control word 2 (character address)
BUF 16 data buffer
BUSY 1 controller busy flag
RDY 1 transfer ready flag
DTE 1 data transfer error flag
ACE 1 access error flag
EOR 1 (DMA/DMC) end of range
DMA 1 transfer using DMA/DMC
CSUM 1 transfer parity checksum
INTREQ 1 device interrupt request
ENABLE 1 device interrupt enable
TIME 24 delay between words
STOP_IOE 1 stop on I/O error
The fixed head disk does not support the BOOT command.
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
Fixed head disk data files are buffered in memory; therefore, end of file
and OS I/O errors cannot occur.
2.5 4100 7-track Magnetic Tape (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 be set ONLINE or OFFLINE, and WRITEENABLED or write LOCKED.
The magtape controller can be connected to the IO bus, a DMC channel, or
a DMA channel:
SET MT IOBUS connect to IO bus
SET MT DMC=n connect to DMC channel n (1-16)
SET MT DMA=n connect to DMA channel n (1-4)
By default, the magtape controller is connected to the IO bus.
The magnetic tape controller implements these registers:
name size comments
BUF 16 data buffer
USEL 2 unit select
BUSY 1 controller busy flag
RDY 1 transfer ready flag
ERR 1 error flag
EOF 1 end of file flag
EOR 1 (DMA/DMC) end of range
DMA 1 transfer using DMA/DMC
MDIRQ 1 motion done interrupt request
INTREQ 1 device interrupt request
ENABLE 1 device interrupt enable
DBUF[0:65535] 8 transfer buffer
BPTR 17 transfer buffer pointer
BMAX 17 transfer size (reads)
CTIME 24 start/stop time
XTIME 24 delay between words
POS[0:3] 32 position, units 0-3
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error processed as
not attached tape not ready; if STOP_IOE, stop
end of file bad tape
OS I/O error parity error; if STOP_IOE, stop
2.6 4623/4651/4720 Disk Packs (DP)
The disk controller can be configured as a 4623, supporting 10 surface
disk packs; a 4651, supporting 2 surface disk packs; or a 4720, supporting
20 surface disk packs:
SET DP 4623 controller is 4623
SET DP 4651 controller is 4651
SET DP 4720 controller is 4720
The default is 4651. All disk packs on the controller must be of the
same type. Units can be set ONLINE or OFFLINE, and WRITEENABLED or
write LOCKED.
The disk pack controller can be connected to a DMC channel or a DMA
channel; it cannot be connected to the IO bus:
SET DP DMC=n connect to DMC channel n (1-16)
SET DP DMA=n connect to DMA channel n (1-4)
The disk pack controller supports variable track formatting. Each track
can contain between 1 and 103 records, with a minimum size of 1 word and
a maximum size of 1893 words. Record addresses are unconstrained. The
simulator provides a command to perform a simple, fixed record size format
of a new disk:
SET DPn FORMAT=k format unit n with k words per record
SET -R DPn FORMAT=k format unit n with k records per track
Record addresses can either be geometric (cylinder/track/sector) or simple
sequential starting from 0:
SET DPn FORMAT=k format with geometric record addresses
SET -S DPn FORMAT=k format with sequential record addresses
Geometric address have the cylinder number in bits<1:8>, the head number in
bits<9:13>, and the sector number in bits <14:16>.
A summary of the current format, and its validity, can be obtained with
the command:
SHOW DPn FORMAT display format of unit n
To accomodate the variable formatting, each track is allocated 2048 words
in the data file. A record consists of a three word header, the data, and
a five word trailer:
word 0 record length in words, not including header/trailer
word 1 record address
word 2 number of extension words used (0-4)
word 3 start of data record
word 3+n-1 end of data record
word 3+n..7+n record trailer: up to four extension words,
plus checksum
A record can "grow" by up to four words without disrupting the track formatting;
writing more than four extra words destroys the formatting of the rest of the
track and causes a simulator error.
The disk pack controller implements these registers:
name size comments
STA 16 status
BUF 16 data buffer
FNC 4 controller function
CW1 16 command word 1
CW2 16 command word 2
CSUM 16 record checksum
BUSY 1 controller busy
RDY 1 transfer ready
EOR 1 (DMA/DMC) end of range
DEFINT 1 seek deferred interrupt pending
INTREQ 1 interrupt request
ENABLE 1 interrupt enable
TBUF[0:2047] 16 track buffer
RPTR 11 pointer to start of record in track buffer
WPTR 11 pointer to current word in record
BCTR 15 bit counter for formatting
STIME 24 seek time, per cylinder
XTIME 24 transfer time, per word
BTIME 24 controller busy time
Error handling is as follows:
error processed as
not attached pack off line; if STOP_IOE, stop
end of file ignored
OS I/O error data error; if STOP_IOE, stop
2.7 Symbolic Display and Input
The H316/H516 simulator implements symbolic display and input. Display is
controlled by command line switches:

975
H316/h316_dp.c Normal file
View file

@ -0,0 +1,975 @@
/* h316_dp.c: Honeywell 4623, 4651, 4720 disk simulator
Copyright (c) 2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
dp 4623 disk subsystem
4651 disk subsystem
4720 disk subsystem
The Honeywell disks have the unique characteristic of supporting variable
formatting, on a per track basis. To accomodate this, each track is
simulated as 2048 words, divided into records. (2048 words accomodates
the largest record of 1891 + 8 overhead words.) A record is structured
as follows:
word 0 record length n (0 = end of track)
word 1 record address (16b, uninterpreted by the simulator)
word 2 record extension (0 to 4 words of permitted 'overwrite')
word 3 first data word
:
word 3+n-1 last data word
word 3+n checksum word
word 4+n first extension word
:
word 7+n fourth extension word
word 8+n start of next record
Formatting is done in two ways. The SET DPn FORMAT=k command formats
unit n with k records per track, each record having the maximum allowable
record size and a standard record address; or with k words per record.
Alternately, the simulator allows programmatic formating. When a track
is formated, the program supplies record parameters as follows:
word 0 record address
words 1-n data words
word n+1 gap size in bits
To make this work, the simulator tracks the consumption of bits in the
track, against the track capacity in bits. Bit consumption is:
16.5 * 16 for overhead (including address and checksum)
n * 16 for data
'gap' for gap, which must be at least 5% of the record length
*/
#include "h316_defs.h"
#include <math.h>
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define FNC u3 /* saved function */
#define CYL u4 /* actual cylinder */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
#define DP_TRKLEN 2048 /* track length, words */
#define DP_NUMDRV 8 /* max # drives */
#define DP_NUMTYP 3 /* # controller types */
/* Record format */
#define REC_LNT 0 /* length (unextended) */
#define REC_ADDR 1 /* address */
#define REC_EXT 2 /* extension (0-4) */
#define REC_DATA 3 /* start of data */
#define REC_OVHD 8 /* overhead words */
#define REC_MAXEXT 4 /* maximum extension */
#define REC_OVHD_WRDS 16.5 /* 16.5 words */
#define REC_OVHD_BITS ((16 * 16) + 8)
/* Status word, ^ = dynamic */
#define STA_BUSY 0100000 /* busy */
#define STA_RDY 0040000 /* ready */
#define STA_ADRER 0020000 /* address error */
#define STA_FMTER 0010000 /* format error */
#define STA_HNLER 0004000 /* heads not loaded (NI) */
#define STA_OFLER 0002000 /* offline */
#define STA_SEKER 0001000 /* seek error */
#define STA_MBZ 0000700
#define STA_WPRER 0000040 /* write prot error */
#define STA_UNSER 0000020 /* unsafe */
#define STA_CSMER 0000010 /* checksum error */
#define STA_DTRER 0000004 /* transfer rate error */
#define STA_ANYER 0000002 /* any error^ */
#define STA_EOR 0000001 /* end of record */
#define STA_ALLERR (STA_ADRER|STA_FMTER|STA_HNLER|STA_OFLER|STA_SEKER|\
STA_WPRER|STA_UNSER|STA_DTRER)
/* Functions */
#define FNC_SK0 0000 /* recalibrate */
#define FNC_SEEK 0001 /* seek */
#define FNC_RCA 0002 /* read current */
#define FNC_UNL 0004 /* unload */
#define FNC_FMT 0005 /* format */
#define FNC_RW 0006 /* read/write */
#define FNC_STOP 0010 /* stop format */
#define FNC_RDS 0011 /* read status */
#define FNC_DMA 0013 /* DMA/DMC */
#define FNC_AKI 0014 /* acknowledge intr */
#define FNC_IOBUS 0017 /* IO bus */
#define FNC_2ND 0020 /* second state */
#define FNC_3RD 0040 /* third state */
#define FNC_4TH 0060 /* fourth state */
#define FNC_5TH 0100 /* fifth state */
/* Command word 1 */
#define CW1_RW 0100000 /* read/write */
#define CW1_DIR 0000400 /* seek direction */
#define CW1_V_UNIT 11 /* unit select */
#define CW1_V_HEAD 6 /* head select */
#define CW1_V_OFFS 0 /* seek offset */
#define CW1_GETUNIT(x) (((x) >> CW1_V_UNIT) & dp_tab[dp_ctype].umsk)
#define CW1_GETHEAD(x) (((x) >> CW1_V_HEAD) & dp_tab[dp_ctype].hmsk)
#define CW1_GETOFFS(x) (((x) >> CW1_V_OFFS) & dp_tab[dp_ctype].cmsk)
/* OTA states */
#define OTA_NOP 0 /* normal */
#define OTA_CW1 1 /* expecting CW1 */
#define OTA_CW2 2 /* expecting CW2 */
/* Transfer state */
#define XIP_UMSK 007 /* unit mask */
#define XIP_SCHED 010 /* scheduled */
#define XIP_WRT 020 /* write */
#define XIP_FMT 040 /* format */
/* The H316/516 disk emulator supports three disk controllers:
controller units cylinders surfaces data words per track
4651 4 203 2 1908.25
4623 8 203 10 1816.5
4720 8 203 20 1908.25
Disk types may not be intermixed on the same controller.
*/
#define TYPE_4651 0
#define UNIT_4651 4
#define CYL_4651 203
#define SURF_4651 2
#define WRDS_4651 1908.25
#define UMSK_4651 0003
#define HMSK_4651 0001
#define CMSK_4651 0377
#define CAP_4651 (CYL_4651*SURF_4651*DP_TRKLEN)
#define TYPE_4623 1
#define UNIT_4623 8
#define CYL_4623 203
#define SURF_4623 10
#define WRDS_4623 1816.5
#define UMSK_4623 0007
#define HMSK_4623 0017
#define CMSK_4623 0377
#define CAP_4623 (CYL_4623*SURF_4623*DP_TRKLEN)
#define TYPE_4720 2
#define UNIT_4720 8
#define CYL_4720 203
#define SURF_4720 20
#define WRDS_4720 1908.25
#define UMSK_4720 0007
#define HMSK_4720 0037
#define CMSK_4720 0377
#define CAP_4720 (CYL_4720*SURF_4720*DP_TRKLEN)
struct drvtyp {
char *name;
uint32 numu;
uint32 cyl;
uint32 surf;
uint32 cap;
uint32 umsk;
uint32 hmsk;
uint32 cmsk;
float wrds; };
#define DP_DRV(d) \
#d, \
UNIT_##d, CYL_##d, SURF_##d, CAP_##d, \
UMSK_##d, HMSK_##d, CMSK_##d, WRDS_##d
static struct drvtyp dp_tab[] = {
{ DP_DRV (4651) },
{ DP_DRV (4623) },
{ DP_DRV (4720) } };
extern int32 dev_int, dev_enb, chan_req;
extern int32 stop_inst;
extern uint32 dma_ad[DMA_MAX];
extern int32 sim_switches;
uint32 dp_cw1 = 0; /* cmd word 1 */
uint32 dp_cw2 = 0; /* cmd word 2 */
uint32 dp_fnc = 0; /* saved function */
uint32 dp_buf = 0; /* buffer */
uint32 dp_otas = 0; /* state */
uint32 dp_sta = 0; /* status */
uint32 dp_defint = 0; /* deferred seek int */
uint32 dp_ctype = TYPE_4651; /* controller type */
uint32 dp_dma = 0; /* DMA/DMC */
uint32 dp_eor = 0; /* end of range */
uint32 dp_xip = 0; /* transfer in prog */
uint32 dp_csum = 0; /* parity checksum */
uint32 dp_rptr = 0; /* start of record */
uint32 dp_wptr = 0; /* word ptr in record */
uint32 dp_bctr = 0; /* format bit cntr */
uint32 dp_gap = 0; /* format gap size */
uint32 dp_stopioe = 1; /* stop on error */
int32 dp_stime = 1000; /* seek per cylinder */
int32 dp_xtime = 10; /* xfer per word */
int32 dp_btime = 30; /* busy time */
uint16 dpxb[DP_TRKLEN]; /* track buffer */
int32 dpio (int32 inst, int32 fnc, int32 dat, int32 dev);
t_stat dp_svc (UNIT *uptr);
t_stat dp_reset (DEVICE *dptr);
t_stat dp_attach (UNIT *uptr, char *cptr);
t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dp_go (uint32 dma);
t_stat dp_go1 (uint32 dat);
t_stat dp_go2 (uint32 dat);
t_stat dp_rdtrk (UNIT *uptr, uint16 *buf, uint32 cyl, uint32 hd);
t_stat dp_wrtrk (UNIT *uptr, uint16 *buf, uint32 cyl, uint32 hd);
t_bool dp_findrec (uint32 addr);
t_stat dp_wrwd (UNIT *uptr, uint32 dat);
t_stat dp_wrdone (UNIT *uptr, uint32 flg);
t_stat dp_done (uint32 req, uint32 f);
t_stat dp_setformat (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dp_showformat (FILE *st, UNIT *uptr, int32 val, void *desc);
/* 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 = { DP, DMC1, 1, &dpio };
UNIT dp_unit[] = {
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) },
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, CAP_4651) } };
REG dp_reg[] = {
{ ORDATA (STA, dp_sta, 16) },
{ ORDATA (BUF, dp_buf, 16) },
{ ORDATA (FNC, dp_fnc, 4) },
{ ORDATA (CW1, dp_cw1, 16) },
{ ORDATA (CW2, dp_cw2, 16) },
{ ORDATA (CSUM, dp_csum, 16) },
{ FLDATA (BUSY, dp_sta, 15) },
{ FLDATA (RDY, dp_sta, 14) },
{ FLDATA (EOR, dp_eor, 0) },
{ FLDATA (DEFINT, dp_defint, 0) },
{ FLDATA (INTREQ, dev_int, INT_V_DP) },
{ FLDATA (ENABLE, dev_enb, INT_V_DP) },
{ BRDATA (TBUF, dpxb, 8, 16, DP_TRKLEN) },
{ ORDATA (RPTR, dp_rptr, 11), REG_RO },
{ ORDATA (WPTR, dp_wptr, 11), REG_RO },
{ ORDATA (BCTR, dp_bctr, 15), REG_RO },
{ ORDATA (GAP, dp_gap, 16), REG_RO },
{ DRDATA (STIME, dp_stime, 24), REG_NZ + PV_LEFT },
{ DRDATA (XTIME, dp_xtime, 24), REG_NZ + PV_LEFT },
{ DRDATA (BTIME, dp_btime, 24), REG_NZ + PV_LEFT },
{ FLDATA (CTYPE, dp_ctype, 0), REG_HRO },
{ URDATA (UCYL, dp_unit[0].CYL, 10, 8, 0,
DP_NUMDRV, PV_LEFT | REG_HRO) },
{ URDATA (UFNC, dp_unit[0].FNC, 8, 7, 0,
DP_NUMDRV, REG_HRO) },
{ URDATA (CAPAC, dp_unit[0].capac, 10, T_ADDR_W, 0,
DP_NUMDRV, PV_LEFT | REG_HRO) },
{ ORDATA (OTAS, dp_otas, 2), REG_HRO },
{ ORDATA (XIP, dp_xip, 6), REG_HRO },
{ ORDATA (CHAN, dp_dib.chan, 5), REG_HRO },
{ FLDATA (STOP_IOE, dp_stopioe, 0) },
{ NULL } };
MTAB dp_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD | MTAB_VDV, TYPE_4623, NULL, "4623",
&dp_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, TYPE_4651, NULL, "4651",
&dp_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, TYPE_4720, NULL, "4720",
&dp_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
NULL, &dp_showtype, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMC",
&io_set_dmc, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMA",
&io_set_dma, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,
NULL, &io_show_chan, NULL },
{ MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "FORMAT", "FORMAT",
&dp_setformat, &dp_showformat, NULL },
{ 0 } };
DEVICE dp_dev = {
"DP", dp_unit, dp_reg, dp_mod,
DP_NUMDRV, 8, 24, 1, 8, 16,
NULL, NULL, &dp_reset,
NULL, &dp_attach, NULL,
&dp_dib, DEV_DISABLE };
/* IOT routines */
int32 dpio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */
int32 u;
UNIT *uptr;
switch (inst) { /* case on opcode */
case ioOCP: /* OCP */
switch (fnc) { /* case on function */
case FNC_SK0: case FNC_SEEK: case FNC_RCA: /* data transfer */
case FNC_UNL: case FNC_FMT: case FNC_RW:
dp_go (fnc); /* if !busy, start */
break;
case FNC_STOP: /* stop transfer */
if (dp_xip) { /* transfer in prog? */
uptr = dp_dev.units + (dp_xip & XIP_UMSK); /* get unit */
sim_cancel (uptr); /* stop operation */
if (dp_xip & (XIP_WRT|XIP_FMT)) /* write or format? */
dp_wrdone (uptr, /* write track */
((dp_xip & XIP_FMT) && /* check fmt state */
(uptr->FNC != (FNC_FMT|FNC_2ND)))?
STA_DTRER: 0);
else dp_done (1, dp_csum? STA_CSMER: 0);/* no, just clr busy */
dp_xip = 0; } /* clear flag */
dp_otas = OTA_NOP; /* clear state */
dp_sta = dp_sta & ~STA_BUSY; /* clear busy */
break;
case FNC_RDS: /* read status */
if (dp_sta & STA_BUSY) return dat; /* ignore if busy */
dp_sta = (dp_sta | STA_RDY) & ~(STA_MBZ | STA_ANYER);
if (dp_sta & STA_ALLERR) dp_sta = dp_sta | STA_ANYER;
dp_buf = dp_sta;
if (dp_dma && Q_DMA (ch)) SET_CH_REQ (ch); /* DMA? set chan req */
break;
case FNC_DMA: /* set DMA/DMC */
dp_dma = 1;
break;
case FNC_IOBUS: /* set IO bus */
dp_dma = 0;
break;
case FNC_AKI: /* ack intr */
CLR_INT (INT_DP);
break;
default: /* undefined */
return IOBADFNC (dat); }
break;
case ioINA: /* INA */
if (fnc) return IOBADFNC (dat); /* fnc 0 only */
if (dp_sta & STA_RDY) { /* ready? */
dp_sta = dp_sta & ~STA_RDY; /* clear ready */
return IOSKIP (dat | dp_buf); } /* ret buf, skip */
break;
case ioOTA: /* OTA */
if (fnc) return IOBADFNC (dat); /* fnc 0 only */
if (dp_sta & STA_RDY) { /* ready? */
dp_sta = dp_sta & ~STA_RDY; /* clear ready */
dp_buf = dat; /* store buf */
if (dp_otas == OTA_CW1) dp_go1 (dat); /* expecting CW1? */
else if (dp_otas == OTA_CW2) dp_go2 (dat); /* expecting CW2? */
return IOSKIP (dat); }
break;
case ioSKS: /* SKS */
u = 7; /* assume unit 7 */
switch (fnc) {
case 000: /* ready */
if (dp_sta & STA_RDY) return IOSKIP (dat);
break;
case 001: /* !interrupting */
if (!TST_INTREQ (INT_DP)) return IOSKIP (dat);
break;
case 002: /* operational */
if (!(dp_sta & (STA_BUSY | STA_ALLERR))) return IOSKIP (dat);
break;
case 003: /* !error */
if (!(dp_sta & STA_ALLERR)) return IOSKIP (dat);
break;
case 004: /* !busy */
if (!(dp_sta & STA_BUSY)) return IOSKIP (dat);
break;
case 011: case 012: case 013: /* !not seeking 0-6 */
case 014: case 015: case 016: case 017:
u = fnc - 011;
case 007: /* !not seeking 7 */
if (!sim_is_active (&dp_unit[u]) || /* quiescent? */
(dp_unit[u].FNC & 017) != FNC_SEEK) return IOSKIP (dat);
break; }
break;
case ioEND: /* end of range */
dp_eor = 1; /* transfer done */
break; }
return dat;
}
/* Start new operation - recal, seek, read address, format, read/write */
t_stat dp_go (uint32 fnc)
{
int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */
if (dp_sta & STA_BUSY) return SCPE_OK; /* ignore if busy */
dp_fnc = fnc; /* save function */
dp_xip = 0; /* transfer not started */
dp_eor = 0; /* not end of range */
dp_csum = 0; /* init checksum */
dp_otas = OTA_CW1; /* expect CW1 */
dp_sta = (dp_sta | STA_BUSY | STA_RDY) & ~(STA_ALLERR | STA_EOR);
if (dp_dma && Q_DMA (ch)) { /* DMA and DMA channel? */
SET_CH_REQ (ch); /* set channel request */
dma_ad[ch] = dma_ad[ch] & ~DMA_IN; } /* force output */
return SCPE_OK;
}
/* Process command word 1 - recal, seek, read address, format, read/write */
t_stat dp_go1 (uint32 dat)
{
int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */
uint32 u = CW1_GETUNIT (dat);
UNIT *uptr = dp_dev.units + u;
dp_cw1 = dat; /* store CW1 */
dp_otas = OTA_NOP; /* assume no CW2 */
uptr->FNC = dp_fnc;
if (sim_is_active (uptr)) /* still seeking? */
return dp_done (1, STA_UNSER); /* unsafe */
if (!(uptr->flags & UNIT_ATT)) /* not attached? */
return dp_done (1, STA_OFLER); /* offline */
switch (dp_fnc) { /* case on function */
case FNC_SEEK: /* seek */
case FNC_SK0: /* recalibrate */
case FNC_UNL: /* unload */
sim_activate (uptr, dp_btime); /* quick timeout */
break;
case FNC_FMT: /* format */
if (uptr->flags & UNIT_WPRT) /* write protect? */
return dp_done (1, STA_WPRER); /* stop now */
case FNC_RCA: /* read current addr */
dp_xip = u | XIP_SCHED; /* operation started */
sim_activate (uptr, dp_xtime * 10); /* rotation timeout */
break;
case FNC_RW: /* read/write */
dp_otas = OTA_CW2; /* expect CW2 */
dp_sta = dp_sta | STA_RDY; /* set ready */
if (dp_dma && Q_DMA (ch)) SET_CH_REQ (ch); /* DMA? set chan request */
break; }
return SCPE_OK;
}
/* Process command word 2 - read/write only */
t_stat dp_go2 (uint32 dat)
{
uint32 u = CW1_GETUNIT (dp_cw1);
UNIT *uptr = dp_dev.units + u;
dp_cw2 = dat; /* store CW2 */
dp_otas = OTA_NOP; /* normal state */
sim_activate (uptr, dp_xtime * 10); /* rotation timeout */
dp_xip = u | XIP_SCHED; /* operation started */
return SCPE_OK;
}
/* Unit service */
t_stat dp_svc (UNIT *uptr)
{
int32 dcyl = 0; /* assume recalibrate */
int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */
uint32 h = CW1_GETHEAD (dp_cw1); /* head */
int32 st;
uint32 i, offs, lnt, ming, tpos;
t_stat r;
if (!(uptr->flags & UNIT_ATT)) { /* not attached? */
dp_done (1, STA_OFLER); /* offline */
IORETURN (dp_stopioe, SCPE_UNATT); }
switch (uptr->FNC) { /* case on function */
case FNC_SEEK: /* seek, need cyl */
offs = CW1_GETOFFS (dp_cw1); /* get offset */
if (dp_cw1 & CW1_DIR) dcyl = uptr->CYL - offs; /* get desired cyl */
else dcyl = uptr->CYL + offs;
if ((offs == 0) || (dcyl < 0) ||
(dcyl >= (int32) dp_tab[dp_ctype].cyl))
return dp_done (1, STA_SEKER); /* bad seek? */
case FNC_SK0: /* recalibrate */
dp_sta = dp_sta & ~STA_BUSY; /* clear busy */
uptr->FNC = FNC_SEEK | FNC_2ND; /* next state */
st = (abs (dcyl - uptr->CYL)) * dp_stime; /* schedule seek */
if (st == 0) st = dp_stime;
uptr->CYL = dcyl; /* put on cylinder */
sim_activate (uptr, st);
return SCPE_OK;
case FNC_SEEK | FNC_2ND: /* seek, 2nd state */
if (dp_sta & STA_BUSY) dp_defint = 1; /* busy? queue intr */
else SET_INT (INT_DP); /* no, req intr */
return SCPE_OK;
case FNC_UNL: /* unload */
detach_unit (uptr); /* detach unit */
return dp_done (0, 0); /* clear busy, no intr */
case FNC_RCA: /* read current addr */
if (h >= dp_tab[dp_ctype].surf) /* invalid head? */
return dp_done (1, STA_ADRER); /* error */
if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */
return r;
dp_rptr = 0; /* init rec ptr */
if (dpxb[dp_rptr + REC_LNT] == 0) /* unformated? */
return dp_done (1, STA_ADRER); /* error */
tpos = (uint32) (fmod (sim_gtime () / (double) dp_xtime, DP_TRKLEN));
do { /* scan down track */
dp_buf = dpxb[dp_rptr + REC_ADDR]; /* get rec addr */
dp_rptr = dp_rptr + dpxb[dp_rptr + REC_LNT] + REC_OVHD; }
while ((dp_rptr < tpos) && (dpxb[dp_rptr + REC_LNT] != 0));
if (dp_dma) { /* DMA/DMC? */
if (Q_DMA (ch)) /* DMA? */
dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */
SET_CH_REQ (ch); } /* request chan */
return dp_done (1, STA_RDY); /* clr busy, set rdy */
/* Formating takes place in five states:
init - clear track buffer, start at first record
address - store address word
data - store data word(s) until end of range
pause - wait for gap word or stop command
gap - validate gap word, advance to next record
Note that formating is stopped externally by an OCP command; the
track buffer is flushed at that point. If the stop does not occur
in the proper state (gap word received), a format error occurs.
*/
case FNC_FMT: /* format */
for (i = 0; i < DP_TRKLEN; i++) dpxb[i] = 0; /* clear track */
dp_xip = dp_xip | XIP_FMT; /* format in progress */
dp_rptr = 0; /* init record ptr */
dp_gap = 0; /* no gap before first */
dp_bctr = (uint32) (16.0 * dp_tab[dp_ctype].wrds); /* init bit cntr */
uptr->FNC = uptr->FNC | FNC_2ND; /* address state */
break; /* set up next word */
case FNC_FMT | FNC_2ND: /* format, address word */
dp_wptr = 0; /* clear word ptr */
if (dp_bctr < (dp_gap + REC_OVHD_BITS + 16)) /* room for gap, record? */
return dp_wrdone (uptr, STA_FMTER); /* no, format error */
dp_bctr = dp_bctr - dp_gap - REC_OVHD_BITS; /* charge for gap, ovhd */
dpxb[dp_rptr + REC_ADDR] = dp_buf; /* store address */
uptr->FNC = FNC_FMT | FNC_3RD; /* data state */
if (dp_eor) { /* record done? */
dp_eor = 0; /* clear for restart */
if (dp_dma) SET_INT (INT_DP); } /* DMA/DMC? intr */
break; /* set up next word */
case FNC_FMT | FNC_3RD: /* format, data word */
if (dp_sta & STA_RDY) /* timing failure? */
return dp_wrdone (uptr, STA_DTRER); /* write trk, err */
else { /* no, have word */
if (dp_bctr < 16) /* room for it? */
return dp_wrdone (uptr, STA_FMTER); /* no, error */
dp_bctr = dp_bctr - 16; /* charge for word */
dp_csum = dp_csum ^ dp_buf; /* update checksum */
dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_buf;/* store word */
dpxb[dp_rptr + REC_LNT]++; /* incr rec lnt */
dp_wptr++; } /* incr word ptr */
if (dp_eor) { /* record done? */
dp_eor = 0; /* clear for restart */
if (dp_dma) SET_INT (INT_DP); /* DMA/DMC? intr */
dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; /* store checksum */
uptr->FNC = uptr->FNC | FNC_4TH; /* pause state */
sim_activate (uptr, 5 * dp_xtime); /* schedule pause */
return SCPE_OK; } /* don't request word */
break; /* set up next word */
case FNC_FMT | FNC_4TH: /* format, pause */
uptr->FNC = FNC_FMT | FNC_5TH; /* gap state */
break; /* request word */
case FNC_FMT | FNC_5TH: /* format, gap word */
ming = ((16 * dp_wptr) + REC_OVHD_BITS) / 20; /* min 5% gap */
if (dp_buf < ming) /* too small? */
return dp_wrdone (uptr, STA_FMTER); /* yes, format error */
dp_rptr = dp_rptr + dp_wptr + REC_OVHD; /* next record */
uptr->FNC = FNC_FMT | FNC_2ND; /* address state */
if (dp_eor) { /* record done? */
dp_eor = 0; /* clear for restart */
if (dp_dma) SET_INT (INT_DP); } /* DMA/DMC? intr */
dp_gap = dp_buf; /* save gap */
dp_csum = 0; /* clear checksum */
break; /* set up next word */
/* Read and write take place in two states:
init - read track into buffer, find record, validate parameters
data - (read) fetch data from buffer, stop on end of range
- (write) write data into buffer, flush on end of range
*/
case FNC_RW: /* read/write */
if (h >= dp_tab[dp_ctype].surf) /* invalid head? */
return dp_done (1, STA_ADRER); /* error */
if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */
return r;
if (!dp_findrec (dp_cw2)) /* find rec; error? */
return dp_done (1, STA_ADRER); /* address error */
if ((dpxb[dp_rptr + REC_LNT] >= (DP_TRKLEN - dp_rptr - REC_OVHD)) ||
(dpxb[dp_rptr + REC_EXT] >= REC_MAXEXT)) { /* bad lnt or ext? */
dp_done (1, STA_UNSER); /* stop simulation */
return STOP_DPFMT; } /* bad format */
uptr->FNC = uptr->FNC | FNC_2ND; /* next state */
if (dp_cw1 & CW1_RW) { /* write? */
if (uptr->flags & UNIT_WPRT) /* write protect? */
return dp_done (1, STA_WPRER); /* error */
dp_xip = dp_xip | XIP_WRT; /* write in progress */
dp_sta = dp_sta | STA_RDY; /* set ready */
if (dp_dma) SET_CH_REQ (ch); } /* if DMA/DMC, req chan */
else if (Q_DMA (ch)) /* read; DMA? */
dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */
sim_activate (uptr, dp_xtime); /* schedule word */
dp_wptr = 0; /* init word pointer */
return SCPE_OK;
case FNC_RW | FNC_2ND: /* read/write, word */
if (dp_cw1 & CW1_RW) { /* write? */
if (dp_sta & STA_RDY) /* timing failure? */
return dp_wrdone (uptr, STA_DTRER); /* yes, error */
if (r = dp_wrwd (uptr, dp_buf)) return r; /* wr word, error? */
if (dp_eor) { /* transfer done? */
dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum;
return dp_wrdone (uptr, 0); } } /* clear busy, intr req */
else { /* read? */
lnt = dpxb[dp_rptr + REC_LNT] + dpxb[dp_rptr + REC_EXT];
dp_buf = dpxb[dp_rptr + REC_DATA + dp_wptr];/* current word */
dp_csum = dp_csum ^ dp_buf; /* xor to csum */
if ((dp_wptr > lnt) || dp_eor) /* transfer done? */
return dp_done (1,
(dp_csum? STA_CSMER: 0) |
((dp_wptr >= lnt)? STA_EOR: 0));
if (dp_sta & STA_RDY) /* data buf full? */
return dp_done (1, STA_DTRER); /* no, underrun */
dp_wptr++; } /* next word */
break;
default:
return SCPE_IERR; } /* end case */
dp_sta = dp_sta | STA_RDY; /* set ready */
if (dp_dma) SET_CH_REQ (ch); /* if DMA/DMC, req chan */
sim_activate (uptr, dp_xtime); /* schedule word */
return SCPE_OK;
}
/* Read track */
t_stat dp_rdtrk (UNIT *uptr, uint16 *buf, uint32 c, uint32 h)
{
uint32 da = ((c * dp_tab[dp_ctype].surf) + h) * DP_TRKLEN;
int32 l;
fseek (uptr->fileref, da * sizeof (uint16), SEEK_SET);
l = fxread (buf, sizeof (uint16), DP_TRKLEN, uptr->fileref);
for ( ; l < DP_TRKLEN; l++) buf[l] = 0;
if (ferror (uptr->fileref)) {
perror ("DP I/O error");
clearerr (uptr->fileref);
dp_done (1, STA_UNSER);
return SCPE_IOERR; }
return SCPE_OK;
}
/* Write track */
t_stat dp_wrtrk (UNIT *uptr, uint16 *buf, uint32 c, uint32 h)
{
uint32 da = ((c * dp_tab[dp_ctype].surf) + h) * DP_TRKLEN;
fseek (uptr->fileref, da * sizeof (uint16), SEEK_SET);
fxwrite (buf, sizeof (uint16), DP_TRKLEN, uptr->fileref);
if (ferror (uptr->fileref)) {
perror ("DP I/O error");
clearerr (uptr->fileref);
dp_done (1, STA_UNSER);
return SCPE_IOERR; }
return SCPE_OK;
}
/* Find record; true if found, false if not found */
t_bool dp_findrec (uint32 addr)
{
dp_rptr = 0;
do { if (dpxb[dp_rptr + REC_LNT] == 0) return FALSE;
if (dpxb[dp_rptr + REC_LNT] >= DP_TRKLEN) return TRUE;
if (dpxb[dp_rptr + REC_ADDR] == addr) return TRUE;
dp_rptr = dp_rptr + dpxb[dp_rptr + REC_LNT] + REC_OVHD; }
while (dp_rptr < DP_TRKLEN);
return FALSE;
}
/* Write next word to track buffer; return TRUE if ok, FALSE if next record trashed */
t_stat dp_wrwd (UNIT *uptr, uint32 dat)
{
uint32 lnt = dpxb[dp_rptr + REC_LNT];
t_stat r;
dp_csum = dp_csum ^ dat;
if (dp_wptr < lnt) {
dpxb[dp_rptr + REC_DATA + dp_wptr++] = dat;
return SCPE_OK; }
if (dp_wptr < (lnt + REC_MAXEXT)) {
dpxb[dp_rptr + REC_EXT]++;
dpxb[dp_rptr + REC_DATA + dp_wptr++] = dat;
return SCPE_OK; }
dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; /* write csum */
dpxb[dp_rptr + lnt + REC_OVHD] = 0; /* zap rest of track */
if (r = dp_wrdone (uptr, STA_UNSER)) return r; /* dump track */
return STOP_DPOVR;
}
/* Write done, dump track, clear busy */
t_stat dp_wrdone (UNIT *uptr, uint32 flg)
{
dp_done (1, flg);
return dp_wrtrk (uptr, dpxb, uptr->CYL, CW1_GETHEAD (dp_cw1));
}
/* Clear busy, set errors, request interrupt if required */
t_stat dp_done (uint32 req, uint32 flg)
{
dp_xip = 0; /* clear xfr in prog */
dp_sta = (dp_sta | flg) & ~(STA_BUSY | STA_MBZ); /* clear busy */
if (req || dp_defint) SET_INT (INT_DP); /* if req, set intr */
dp_defint = 0; /* clr def intr */
return SCPE_OK;
}
/* Reset routine */
t_stat dp_reset (DEVICE *dptr)
{
int32 i;
dp_fnc = 0;
dp_cw1 = 0;
dp_cw2 = 0;
dp_sta = 0;
dp_buf = 0;
dp_xip = 0;
dp_eor = 0;
dp_dma = 0;
dp_csum = 0;
dp_rptr = 0;
dp_wptr = 0;
dp_bctr = 0;
dp_gap = 0;
dp_defint = 0;
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
sim_cancel (&dp_unit[i]); /* cancel activity */
dp_unit[i].FNC = 0; /* clear function */
dp_unit[i].CYL = 0; }
return SCPE_OK;
}
/* Attach routine, test formating */
t_stat dp_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
return dp_showformat (stdin, uptr, 0, NULL);
}
/* Set controller type */
t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i;
if ((val < 0) || (val >= DP_NUMTYP) || (cptr != NULL)) return SCPE_ARG;
for (i = 0; i < DP_NUMDRV; i++) {
if (dp_unit[i].flags & UNIT_ATT) return SCPE_ALATT; }
for (i = 0; i < DP_NUMDRV; i++)
dp_unit[i].capac = dp_tab[val].cap;
dp_ctype = val;
return SCPE_OK;
}
/* Show controller type */
t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
{
if (dp_ctype >= DP_NUMTYP) return SCPE_IERR;
fprintf (st, "%s", dp_tab[dp_ctype].name);
return SCPE_OK;
}
/* Set drive format
There is no standard format for record addresses. This routine
provides two schemes:
-S sequential addressing (starting from 0)
default geometric addressing (8b: cylinder, 5b: head, 3b: sector)
This routine also supports formatting by record count or word count:
-R argument is records per track
default argument is words per record
The relationship between words per record (W), bits per track (B),
and records per track (R), is as follows:
W = (B / (R + ((R - 1) / 20))) - 16.5
where (R - 1) / 20 is the "5% gap" and 16.5 is the overhead, in words,
per record.
*/
t_stat dp_setformat (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 h, c, cntr, rptr;
int32 i, nr, nw, inp;
uint16 tbuf[DP_TRKLEN];
float finp;
t_stat r;
if (uptr == NULL) return SCPE_IERR;
if (cptr == NULL) return SCPE_ARG;
if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT;
inp = (int32) get_uint (cptr, 10, 2048, &r);
if (r != SCPE_OK) return r;
if (inp == 0) return SCPE_ARG;
finp = (float) inp;
if (sim_switches & SWMASK ('R')) { /* format records? */
nr = inp;
nw = (int32) ((dp_tab[dp_ctype].wrds / (finp + ((finp - 1.0) / 20.0))) - REC_OVHD_WRDS);
if (nw <= 0) return SCPE_ARG; }
else { nw = inp; /* format words */
nr = (int32) ((((20.0 * dp_tab[dp_ctype].wrds) / (finp + REC_OVHD_WRDS)) + 1.0) / 21.0);
if (nr <= 0) return SCPE_ARG; }
printf ("Proposed format: records/track = %d, record size = %d\n", nr, nw);
if (!get_yn ("Formatting will destroy all data on this disk; proceed? [N]", FALSE))
return SCPE_OK;
for (c = cntr = 0; c < dp_tab[dp_ctype].cyl; c++) {
for (h = 0; h < dp_tab[dp_ctype].surf; h++) {
for (i = 0; i < DP_TRKLEN; i++) tbuf[i] = 0;
rptr = 0;
for (i = 0; i < nr; i++) {
tbuf[rptr + REC_LNT] = nw & DMASK;
if (sim_switches & SWMASK ('S'))
tbuf[rptr + REC_ADDR] = cntr++;
else tbuf[rptr + REC_ADDR] = (c << 8) + (h << 3) + i;
rptr = rptr + nw + REC_OVHD; }
if (r = dp_wrtrk (uptr, tbuf, c, h)) return r;
}
}
printf ("Formatting complete\n");
return SCPE_OK;
}
/* Show format */
t_stat dp_showformat (FILE *st, UNIT *uptr, int32 val, void *desc)
{
uint32 c, h, rptr, rlnt, sec;
uint32 minrec = DP_TRKLEN;
uint32 maxrec = 0;
uint32 minsec = DP_TRKLEN;
uint32 maxsec = 0;
uint16 tbuf[DP_TRKLEN];
t_stat r;
if (uptr == NULL) return SCPE_IERR;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
for (c = 0; c < dp_tab[dp_ctype].cyl; c++) {
for (h = 0; h < dp_tab[dp_ctype].surf; h++) {
if (r = dp_rdtrk (uptr, tbuf, c, h)) return r;
rptr = 0;
rlnt = tbuf[rptr + REC_LNT];
if (rlnt == 0) {
if (c || h) fprintf (st,
"Unformatted track, cyl = %d, head = %d\n", c, h);
else fprintf (st, "Disk is unformatted\n");
return SCPE_OK; }
for (sec = 0; rlnt != 0; sec++) {
if ((rptr + rlnt + REC_OVHD) >= DP_TRKLEN) {
fprintf (st, "Invalid record length %d, cyl = %d, head = %d, sect = %d\n",
rlnt, c, h, sec);
return SCPE_OK; }
if (tbuf[rptr + REC_EXT] >= REC_MAXEXT) {
fprintf (st, "Invalid record extension %d, cyl = %d, head = %d, sect = %d\n",
tbuf[rptr + REC_EXT], c, h, sec);
return SCPE_OK; }
if (rlnt > maxrec) maxrec = rlnt;
if (rlnt < minrec) minrec = rlnt;
rptr = rptr + rlnt + REC_OVHD;
rlnt = tbuf[rptr + REC_LNT];
}
if (sec > maxsec) maxsec = sec;
if (sec < minsec) minsec = sec;
}
}
if ((minrec == maxrec) && (minsec == maxsec)) fprintf (st,
"Valid fixed format, records/track = %d, record size = %d\n",
minsec, minrec);
else if (minrec == maxrec) fprintf (st,
"Valid variable format, records/track = %d-%d, record size = %d\n",
minsec, maxsec, minrec);
else if (minsec == maxsec) fprintf (st,
"Valid variable format, records/track = %d, record sizes = %d-%d\n",
minsec, minrec, maxrec);
else fprintf (st,
"Valid variable format, records/track = %d-%d, record sizes = %d-%d\n",
minsec, maxsec, minrec, maxrec);
return SCPE_OK;
}

423
H316/h316_fhd.c Normal file
View file

@ -0,0 +1,423 @@
/* h316_fhd.c: H316/516 fixed head simulator
Copyright (c) 2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
fhd 516-4400 fixed head disk
These head-per-track devices are buffered in memory, to minimize overhead.
*/
#include "h316_defs.h"
#include <math.h>
/* Constants */
#define FH_NUMWD 1536 /* words/track */
#define FH_NUMTK 64 /* tracks/surface */
#define FH_WDPSF (FH_NUMWD * FH_NUMTK) /* words/surface */
#define FH_NUMSF 16 /* surfaces/ctlr */
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
#define UNIT_V_SF (UNIT_V_UF + 1) /* #surfaces - 1 */
#define UNIT_M_SF 017
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_SF (UNIT_M_SF << UNIT_V_SF)
#define UNIT_GETSF(x) ((((x) >> UNIT_V_SF) & UNIT_M_SF) + 1)
/* Command word 1 */
#define CW1_RW 0100000 /* read vs write */
#define CW1_V_SF 10 /* surface */
#define CW1_M_SF 017
#define CW1_GETSF(x) (((x) >> CW1_V_SF) & CW1_M_SF)
#define CW1_V_TK 4 /* track */
#define CW1_M_TK 077
#define CW1_GETTK(x) (((x) >> CW1_V_TK) & CW1_M_TK)
/* Command word 2 */
#define CW2_V_CA 0 /* character addr */
#define CW2_M_CA 07777
#define CW2_GETCA(x) (((x) >> CW2_V_CA) & CW2_M_CA)
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) FH_NUMWD)))
/* OTA states */
#define OTA_NOP 0 /* normal */
#define OTA_CW1 1 /* expecting CW1 */
#define OTA_CW2 2 /* expecting CW2 */
extern int32 dev_int, dev_enb, chan_req;
extern int32 stop_inst;
extern uint32 dma_ad[DMA_MAX];
uint32 fhd_cw1 = 0; /* cmd word 1 */
uint32 fhd_cw2 = 0; /* cmd word 2 */
uint32 fhd_buf = 0; /* buffer */
uint32 fhd_otas = 0; /* state */
uint32 fhd_busy = 0; /* busy */
uint32 fhd_rdy = 0; /* word ready */
uint32 fhd_dte = 0; /* data err */
uint32 fhd_ace = 0; /* access error */
uint32 fhd_dma = 0; /* DMA/DMC */
uint32 fhd_eor = 0; /* end of range */
uint32 fhd_csum = 0; /* parity checksum */
uint32 fhd_stopioe = 1; /* stop on error */
int32 fhd_time = 10; /* time per word */
int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev);
t_stat fhd_svc (UNIT *uptr);
t_stat fhd_reset (DEVICE *dptr);
t_stat fhd_attach (UNIT *uptr, char *cptr);
t_stat fhd_boot (int32 unitno, DEVICE *dptr);
t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
void fhd_go (uint32 dma);
void fhd_go1 (uint32 dat);
void fhd_go2 (uint32 dat);
t_bool fhd_getc (UNIT *uptr, uint32 *ch);
t_bool fhd_putc (UNIT *uptr, uint32 ch);
t_bool fhd_bad_wa (uint32 wa);
uint32 fhd_csword (uint32 cs, uint32 ch);
/* FHD data structures
fhd_dev device descriptor
fhd_unit unit descriptor
fhd_mod unit modifiers
fhd_reg register list
*/
DIB fhd_dib = { FHD, IOBUS, 1, &fhdio };
UNIT fhd_unit =
{ UDATA (&fhd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF, FH_WDPSF) };
REG fhd_reg[] = {
{ ORDATA (CW1, fhd_cw1, 16) },
{ ORDATA (CW2, fhd_cw2, 16) },
{ ORDATA (BUF, fhd_buf, 16) },
{ FLDATA (BUSY, fhd_busy, 0) },
{ FLDATA (RDY, fhd_rdy, 0) },
{ FLDATA (DTE, fhd_dte, 0) },
{ FLDATA (ACE, fhd_ace, 0) },
{ FLDATA (EOR, fhd_eor, 0) },
{ FLDATA (DMA, fhd_dma, 0) },
{ FLDATA (CSUM, fhd_csum, 7) },
{ FLDATA (INTREQ, dev_int, INT_V_MT) },
{ FLDATA (ENABLE, dev_enb, INT_V_MT) },
{ DRDATA (TIME, fhd_time, 31), REG_NZ + PV_LEFT },
{ ORDATA (OTAS, fhd_otas, 2), REG_HRO },
{ ORDATA (CHAN, fhd_dib.chan, 5), REG_HRO },
{ FLDATA (STOP_IOE, fhd_stopioe, 0) },
{ NULL } };
MTAB fhd_mod[] = {
{ UNIT_SF, (0 << UNIT_V_SF), NULL, "1S", &fhd_set_size },
{ UNIT_SF, (1 << UNIT_V_SF), NULL, "2S", &fhd_set_size },
{ UNIT_SF, (2 << UNIT_V_SF), NULL, "3S", &fhd_set_size },
{ UNIT_SF, (3 << UNIT_V_SF), NULL, "4S", &fhd_set_size },
{ UNIT_SF, (4 << UNIT_V_SF), NULL, "5S", &fhd_set_size },
{ UNIT_SF, (5 << UNIT_V_SF), NULL, "6S", &fhd_set_size },
{ UNIT_SF, (6 << UNIT_V_SF), NULL, "7S", &fhd_set_size },
{ UNIT_SF, (7 << UNIT_V_SF), NULL, "8S", &fhd_set_size },
{ UNIT_SF, (8 << UNIT_V_SF), NULL, "9S", &fhd_set_size },
{ UNIT_SF, (9 << UNIT_V_SF), NULL, "10S", &fhd_set_size },
{ UNIT_SF, (10 << UNIT_V_SF), NULL, "11S", &fhd_set_size },
{ UNIT_SF, (11 << UNIT_V_SF), NULL, "12S", &fhd_set_size },
{ UNIT_SF, (12 << UNIT_V_SF), NULL, "13S", &fhd_set_size },
{ UNIT_SF, (13 << UNIT_V_SF), NULL, "14S", &fhd_set_size },
{ UNIT_SF, (14 << UNIT_V_SF), NULL, "15S", &fhd_set_size },
{ UNIT_SF, (15 << UNIT_V_SF), NULL, "16S", &fhd_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "IOBUS",
&io_set_iobus, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMC",
&io_set_dmc, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMA",
&io_set_dma, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,
NULL, &io_show_chan, NULL },
{ 0 } };
DEVICE fhd_dev = {
"FHD", &fhd_unit, fhd_reg, fhd_mod,
1, 8, 22, 1, 8, 16,
NULL, NULL, &fhd_reset,
NULL, &fhd_attach, NULL,
&fhd_dib, DEV_DISABLE };
/* IO routines */
int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
switch (inst) { /* case on opcode */
case ioOCP: /* control */
if (fnc == 04) { /* terminate output? */
fhd_eor = 1; /* stop */
CLR_INT (INT_FHD); } /* clear int req */
else if (fnc == 003) fhd_go (1); /* start, DMA */
else if (fnc == 007) fhd_go (0); /* start, IO bus */
else return IOBADFNC (dat);
break;
case ioOTA: /* output */
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
if (fhd_rdy) { /* ready? */
fhd_buf = dat; /* store data */
if (fhd_otas == OTA_CW1) fhd_go1 (dat); /* expecting CW1? */
else if (fhd_otas == OTA_CW2) fhd_go2 (dat);/* expecting CW2? */
else fhd_rdy = 0; /* normal, clr ready */
return IOSKIP (dat); }
break;
case ioINA: /* input */
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
if (fhd_rdy) { /* ready? */
fhd_rdy = 0; /* clear ready */
return IOSKIP (dat | fhd_buf); } /* return data */
break;
case ioSKS: /* sense */
if (((fnc == 000) && fhd_rdy) || /* 0 = skip if ready */
((fnc == 001) && !fhd_busy) || /* 1 = skip if !busy */
((fnc == 002) && !fhd_dte) || /* 2 = skip if !data err */
((fnc == 003) && !fhd_ace) || /* 3 = skip if !access err */
((fnc == 004) && !TST_INTREQ (INT_FHD))) /* 4 = skip if !interrupt */
return IOSKIP (dat);
break;
case ioEND:
fhd_eor = 1;
break; }
return dat;
}
/* Start new operation */
void fhd_go (uint32 dma)
{
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */
if (fhd_busy) return; /* ignore if busy */
fhd_busy = 1; /* ctlr is busy */
fhd_eor = 0; /* transfer not done */
fhd_csum = 0; /* init checksum */
fhd_dte = 0; /* clear errors */
fhd_ace = 0;
if (ch >= 0) fhd_dma = dma; /* DMA allowed? */
else fhd_dma = 0; /* no, force IO bus */
fhd_otas = OTA_CW1; /* expect CW1 */
fhd_rdy = 1; /* set ready */
if (fhd_dma && Q_DMA (ch)) { /* DMA and DMA channel? */
SET_CH_REQ (ch); /* set channel request */
dma_ad[ch] = dma_ad[ch] & ~DMA_IN; } /* force output */
return;
}
/* Process command word 1 */
void fhd_go1 (uint32 dat)
{
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */
fhd_cw1 = dat; /* store CW1 */
fhd_otas = OTA_CW2; /* expect CW2 */
fhd_rdy = 1; /* set ready */
if (fhd_dma && Q_DMA (ch)) SET_CH_REQ (ch); /* DMA? set chan request */
return;
}
/* Process command word 2 - initiate seek */
void fhd_go2 (uint32 dat)
{
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */
uint32 sf = CW1_GETSF (fhd_cw1); /* surface */
int32 t, wa;
fhd_cw2 = dat; /* store CW2 */
fhd_otas = OTA_NOP; /* next state */
wa = CW2_GETCA (fhd_cw2) >> 1; /* word addr */
if ((wa >= FH_NUMWD) || /* if bad char addr */
((fhd_unit.flags & UNIT_ATT) == 0) || /* or unattached */
(sf >= UNIT_GETSF (fhd_unit.flags))) { /* or bad surface */
fhd_ace = 1; /* access error */
fhd_busy = 0; /* abort operation */
SET_INT (INT_FHD);
return; }
if (fhd_cw1 & CW1_RW) { /* write? */
fhd_rdy = 1; /* set ready */
if (fhd_dma) SET_CH_REQ (ch); } /* if DMA/DMC, req chan */
else { fhd_rdy = 0; /* read, clear ready */
if (fhd_dma && (ch < DMC_V_DMC1)) /* read and DMA chan? */
dma_ad[ch] = dma_ad[ch] | DMA_IN; } /* force input */
t = wa - GET_POS (fhd_time); /* delta to new loc */
if (t < 0) t = t + FH_NUMWD; /* wrap around? */
sim_activate (&fhd_unit, t * fhd_time); /* schedule op */
return;
}
/* Unit service */
t_stat fhd_svc (UNIT *uptr)
{
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan (-1 if IO bus) */
uint32 c1, c2;
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
fhd_ace = 1; /* access error */
fhd_busy = 0; /* abort operation */
SET_INT (INT_FHD);
return IORETURN (fhd_stopioe, SCPE_UNATT); }
if (fhd_eor || fhd_rdy) { /* done or ready set? */
if (fhd_rdy) fhd_dte = 1; /* if ready set, data err */
if (fhd_cw1 & CW1_RW) { /* write? */
if (!fhd_rdy) { /* buffer full? */
fhd_putc (uptr, fhd_buf >> 8); /* store last word */
fhd_putc (uptr, fhd_buf); }
fhd_putc (uptr, fhd_csum); } /* store csum */
else { /* read */
fhd_getc (uptr, &c1); /* get csum */
if (fhd_csum) fhd_dte = 1; } /* if csum != 0, err */
fhd_busy = 0; /* operation complete */
SET_INT (INT_FHD);
return SCPE_OK; }
if (fhd_cw1 & CW1_RW) { /* write? */
if (fhd_putc (uptr, fhd_buf >> 8)) return SCPE_OK;
if (fhd_putc (uptr, fhd_buf)) return SCPE_OK; }
else { if (fhd_getc (uptr, &c1)) return SCPE_OK; /* read */
if (fhd_getc (uptr, &c2)) return SCPE_OK;
fhd_buf = (c1 << 8) | c2; }
sim_activate (uptr, fhd_time); /* next word */
fhd_rdy = 1; /* set ready */
if (fhd_dma) SET_CH_REQ (ch); /* if DMA/DMC, req chan */
return SCPE_OK;
}
/* Read character from disk */
t_bool fhd_getc (UNIT *uptr, uint32 *ch)
{
uint32 sf = CW1_GETSF (fhd_cw1); /* surface */
uint32 tk = CW1_GETTK (fhd_cw1); /* track */
uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */
uint32 wa = ca >> 1; /* word addr */
uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */
uint16 *fbuf = uptr->filebuf; /* buffer base */
uint32 wd;
if (fhd_bad_wa (wa)) return TRUE; /* addr bad? */
fhd_cw2 = fhd_cw2 + 1; /* incr char addr */
if (ca & 1) wd = fbuf[ba] & 0377; /* select char */
else wd = (fbuf[ba] >> 8) & 0377;
fhd_csum = fhd_csword (fhd_csum, wd); /* put in csum */
*ch = wd; /* return */
return FALSE;
}
/* Write character to disk */
t_bool fhd_putc (UNIT *uptr, uint32 ch)
{
uint32 sf = CW1_GETSF (fhd_cw1); /* surface */
uint32 tk = CW1_GETTK (fhd_cw1); /* track */
uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */
uint32 wa = ca >> 1; /* word addr */
uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */
uint16 *fbuf = uptr->filebuf; /* buffer base */
ch = ch & 0377; /* mask char */
if (fhd_bad_wa (wa)) return TRUE; /* addr bad? */
fhd_cw2 = fhd_cw2 + 1; /* incr char addr */
if (ca & 1) fbuf[ba] = (fbuf[ba] & ~0377) | ch; /* odd? low char */
else fbuf[ba] = (fbuf[ba] & 0377) | (ch << 8); /* even, hi char */
fhd_csum = fhd_csword (fhd_csum, ch); /* put in csum */
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; /* update hwmark */
return FALSE;
}
/* Check word address */
t_bool fhd_bad_wa (uint32 wa)
{
if (wa >= FH_NUMWD) { /* bad address? */
fhd_ace = 1; /* access error */
fhd_busy = 0; /* abort operation */
SET_INT (INT_FHD);
return TRUE; }
return FALSE;
}
/* Add character to checksum (parity) */
uint32 fhd_csword (uint32 cs, uint32 ch)
{
while (ch) { /* count bits */
ch = ch & ~(ch & (-(int32) ch));
cs = cs ^ 0200; } /* invert cs for each 1 */
return cs;
}
/* Reset routine */
t_stat fhd_reset (DEVICE *dptr)
{
fhd_busy = 0; /* reset state */
fhd_rdy = 0;
fhd_ace = 0;
fhd_dte = 0;
fhd_eor = 0;
fhd_otas = OTA_NOP;
fhd_cw1 = fhd_cw2 = fhd_buf = 0;
CLR_INT (INT_FHD); /* clear int, enb */
CLR_ENB (INT_FHD);
sim_cancel (&fhd_unit); /* cancel operation */
return SCPE_OK;
}
/* Attach routine */
t_stat fhd_attach (UNIT *uptr, char *cptr)
{
uint32 sz, sf;
uint32 ds_bytes = FH_WDPSF * sizeof (int16);
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) {
sf = (sz + ds_bytes - 1) / ds_bytes;
if (sf >= FH_NUMSF) sf = FH_NUMSF - 1;
uptr->flags = (uptr->flags & ~UNIT_SF) |
(sf << UNIT_V_SF); }
uptr->capac = UNIT_GETSF (uptr->flags) * FH_WDPSF;
return attach_unit (uptr, cptr);
}
/* Set size routine */
t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (val < 0) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = UNIT_GETSF (val) * FH_WDPSF;
return SCPE_OK;
}

View file

@ -25,6 +25,7 @@
lpt line printer
24-Oct-03 RMS Added DMA/DMC support
25-Apr-03 RMS Revised for extended file support
30-May-02 RMS Widened POS to 32b
@ -55,8 +56,10 @@
lpt_crpos carriage position (0-1)
lpt_svcst service state (shuttle, paper advance)
lpt_svcch channel for paper advance (0 = no adv)
lpt_xfer transfer ready flag
lpt_rdy transfer ready flag
lpt_prdn printing done flag
lpt_dma use DMA/DMC
lpt_eor DMA/DMC end of range
*/
#include "h316_defs.h"
@ -67,22 +70,26 @@
#define LPT_SVCSH 01 /* shuttle */
#define LPT_SVCPA 02 /* paper advance */
extern int32 dev_ready, dev_enable;
extern int32 dev_int, dev_enb;
extern int32 stop_inst;
extern uint32 chan_req;
int32 lpt_wdpos = 0; /* word position */
int32 lpt_drpos = 0; /* drum position */
int32 lpt_crpos = 0; /* carriage position */
int32 lpt_svcst = 0; /* service state */
int32 lpt_svcch = 0; /* service channel */
int32 lpt_xfer = 0; /* transfer flag */
int32 lpt_rdy = 0; /* transfer flag */
int32 lpt_prdn = 1; /* printing done */
int32 lpt_dma = 0; /* use DMA/DMC */
int32 lpt_eor = 0; /* DMA/DMC end range */
char lpt_buf[LPT_WIDTH + 1] = { 0 }; /* line buffer */
int32 lpt_xtime = 5; /* transfer time */
int32 lpt_etime = 50; /* end of scan time */
int32 lpt_ptime = 5000; /* paper adv time */
int32 lpt_stopioe = 0; /* stop on error */
int32 lptio (int32 inst, int32 fnc, int32 dat, int32 dev);
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
@ -94,16 +101,20 @@ t_stat lpt_reset (DEVICE *dptr);
lpt_reg LPT register list
*/
DIB lpt_dib = { LPT, IOBUS, 1, &lptio };
UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0) };
REG lpt_reg[] = {
{ DRDATA (WDPOS, lpt_wdpos, 6) },
{ DRDATA (DRPOS, lpt_drpos, 6) },
{ FLDATA (CRPOS, lpt_crpos, 0) },
{ FLDATA (XFER, lpt_xfer, 0) },
{ FLDATA (RDY, lpt_rdy, 0) },
{ FLDATA (EOR, lpt_eor, 0) },
{ FLDATA (DMA, lpt_dma, 0) },
{ FLDATA (PRDN, lpt_prdn, 0) },
{ FLDATA (INTREQ, dev_ready, INT_V_LPT) },
{ FLDATA (ENABLE, dev_enable, INT_V_LPT) },
{ FLDATA (INTREQ, dev_int, INT_V_LPT) },
{ FLDATA (ENABLE, dev_enb, INT_V_LPT) },
{ ORDATA (SVCST, lpt_svcst, 2) },
{ ORDATA (SVCCH, lpt_svcch, 2) },
{ BRDATA (BUF, lpt_buf, 8, 8, 120) },
@ -118,12 +129,14 @@ DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&lpt_dib, DEV_DISABLE };
/* IO routine */
int32 lptio (int32 inst, int32 fnc, int32 dat)
int32 lptio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
int32 ch = lpt_dib.chan - 1; /* DMA/DMC chan */
int32 chr;
switch (inst) { /* case on opcode */
@ -133,13 +146,26 @@ case ioOCP: /* OCP */
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 */
CLR_INT (INT_LPT); /* clear int */
break;
case 007: /* init scan */
case 003: /* init scan DMA/DMC */
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 */
lpt_eor = 0;
if (ch >= 0) lpt_dma = 1; /* try for DMA/DMC */
lpt_dma = 0;
if (!sim_is_active (&lpt_unit)) {
lpt_rdy = 1;
if (lpt_dma) SET_CH_REQ (ch); }
CLR_INT (INT_LPT); /* clear int */
break;
case 007: /* init scan IO bus*/
lpt_prdn = 0; /* clear pr done */
lpt_wdpos = 0; /* init scan pos */
lpt_eor = 0;
lpt_dma = 0; /* IO bus */
if (!sim_is_active (&lpt_unit)) lpt_rdy = 1;
CLR_INT (INT_LPT); /* clear int */
break;
default:
return IOBADFNC (dat); }
@ -148,7 +174,7 @@ case ioOCP: /* OCP */
case ioSKS: /* SKS */
switch (fnc) { /* case on fnc */
case 000: /* if xfer rdy */
if (lpt_xfer) return IOSKIP (dat);
if (lpt_rdy) return IOSKIP (dat);
break;
case 002: /* if !alarm */
if (lpt_unit.flags & UNIT_ATT) return IOSKIP (dat);
@ -187,8 +213,8 @@ case ioSKS: /* SKS */
case ioOTA: /* OTA */
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
if (lpt_xfer) { /* xfer ready? */
lpt_xfer = 0; /* clear xfer */
if (lpt_rdy) { /* xfer ready? */
lpt_rdy = 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;
@ -207,6 +233,10 @@ case ioOTA: /* OTA */
} /* end if endscan */
else sim_activate (&lpt_unit, lpt_xtime);
return IOSKIP (dat); } /* skip return */
break;
case ioEND: /* end DMA/DMC */
lpt_eor = 1; /* set end range */
break; } /* end case op */
return dat;
}
@ -216,6 +246,7 @@ return dat;
t_stat lpt_svc (UNIT *uptr)
{
int32 i;
int32 ch = lpt_dib.chan - 1; /* DMA/DMC chan */
static const char *lpt_cc[] = {
"\r",
"\n",
@ -224,12 +255,18 @@ static const char *lpt_cc[] = {
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
lpt_xfer = 1;
if (lpt_dma) { /* DMA/DMC? */
if (lpt_eor) SET_INT (INT_LPT); /* end range? intr */
else {
lpt_rdy = 1; /* set ready */
SET_CH_REQ (ch); } } /* get more data */
else lpt_rdy = 1; /* IO, continue scan */
if (lpt_dma && lpt_eor) SET_INT (INT_LPT); /* end of range? */
if (lpt_svcst & LPT_SVCSH) { /* shuttling */
SET_READY (INT_LPT); /* interrupt */
SET_INT (INT_LPT); /* interrupt */
if (lpt_crpos == 0) lpt_prdn = 1; }
if (lpt_svcst & LPT_SVCPA) { /* paper advance */
SET_READY (INT_LPT); /* interrupt */
SET_INT (INT_LPT); /* interrupt */
for (i = LPT_WIDTH - 1; i >= 0; i++) {
if (lpt_buf[i] != ' ') break; }
lpt_buf[i + 1] = 0;
@ -250,12 +287,14 @@ int32 i;
lpt_wdpos = lpt_drpos = lpt_crpos = 0; /* clear positions */
lpt_svcst = lpt_svcch = 0; /* idle state */
lpt_xfer = 0; /* not rdy to xfer */
lpt_rdy = 0; /* not rdy to xfer */
lpt_prdn = 1; /* printing done */
lpt_eor = 0;
lpt_dma = 0;
for (i = 0; i < LPT_WIDTH; i++) lpt_buf[i] = ' '; /* clear buffer */
lpt_buf[LPT_WIDTH] = 0;
CLR_READY (INT_LPT); /* clear int, enb */
CLR_ENABLE (INT_LPT);
CLR_INT (INT_LPT); /* clear int, enb */
CLR_ENB (INT_LPT);
sim_cancel (&lpt_unit); /* deactivate unit */
return SCPE_OK;
}

520
H316/h316_mt.c Normal file
View file

@ -0,0 +1,520 @@
/* h316_mt.c: H316/516 magnetic tape simulator
Copyright (c) 2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
mt 516-4100 seven track magnetic tape
Magnetic tapes are represented as a series of variable records
of the form:
32b byte count
byte 0
byte 1
:
byte n-2
byte n-1
32b byte count
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
*/
#include "h316_defs.h"
#include "sim_tape.h"
#define MT_NUMDR 4 /* number of drives */
#define DB_N_SIZE 16 /* max data buf */
#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */
#define FNC u3 /* function */
#define UST u4 /* unit status */
#define UNIT_WPRT (MTUF_WLK | UNIT_RO) /* write prot */
/* Function codes */
#define FNC_RBCD2 000
#define FNC_RBIN2 001
#define FNC_RBIN3 002
#define FNC_DMANM 003
#define FNC_WBCD2 004
#define FNC_WBIN2 005
#define FNC_WEOF 006
#define FNC_IOBUS 007
#define FNC_WBIN3 010
#define FNC_FSR 011
#define FNC_FSF 012
#define FNC_DMAAU 013
#define FNC_REW 014
#define FNC_BSR 015
#define FNC_BSF 016
#define FNC_STOPW 017
#define FNC_2ND 020 /* second state */
#define FNC_NOP (FNC_STOPW|FNC_2ND)
#define FNC_EOM 040 /* end of motion */
/* Status - unit.UST */
#define STA_BOT 0000002 /* beg of tape */
#define STA_EOT 0000001 /* end of tape */
extern int32 dev_int, dev_enb, chan_req;
extern int32 stop_inst;
uint32 mt_buf = 0; /* data buffer */
uint32 mt_usel = 0; /* unit select */
uint32 mt_busy = 0; /* ctlr busy */
uint32 mt_mdirq = 0; /* motion done int req */
uint32 mt_rdy = 0; /* transfer ready (int) */
uint32 mt_err = 0; /* error */
uint32 mt_eof = 0; /* end of file */
uint32 mt_eor = 0; /* transfer done */
uint32 mt_dma = 0; /* DMA/DMC */
uint32 mt_xtime = 16; /* transfer time */
uint32 mt_ctime = 3000; /* start/stop time */
uint32 mt_stopioe = 1; /* stop on I/O error */
uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */
t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev);
void mt_updint (uint32 rdy, uint32 mdone);
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_map_err (UNIT *uptr, t_stat st);
void mt_wrwd (UNIT *uptr, uint32 dat);
/* 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 = { MT, IOBUS, MT_NUMDR, &mtio };
UNIT mt_unit[] = {
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) } };
REG mt_reg[] = {
{ ORDATA (BUF, mt_buf, 16) },
{ ORDATA (USEL, mt_usel, 2) },
{ FLDATA (BUSY, mt_busy, 0) },
{ FLDATA (RDY, mt_rdy, 0) },
{ FLDATA (ERR, mt_err, 0) },
{ FLDATA (EOF, mt_eof, 0) },
{ FLDATA (EOR, mt_eor, 0) },
{ FLDATA (MDIRQ, mt_mdirq, 0) },
{ FLDATA (DMA, mt_dma, 0) },
{ FLDATA (INTREQ, dev_int, INT_V_MT) },
{ FLDATA (ENABLE, dev_enb, INT_V_MT) },
{ BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },
{ DRDATA (BPTR, mt_ptr, DB_N_SIZE + 1) },
{ DRDATA (BMAX, mt_max, DB_N_SIZE + 1) },
{ DRDATA (CTIME, mt_ctime, 24), REG_NZ + PV_LEFT },
{ DRDATA (XTIME, mt_xtime, 24), REG_NZ + PV_LEFT },
{ URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, MT_NUMDR, PV_LEFT) },
{ URDATA (FNC, mt_unit[0].FNC, 8, 8, 0, MT_NUMDR, REG_HRO) },
{ URDATA (UST, mt_unit[0].UST, 8, 2, 0, MT_NUMDR, REG_HRO) },
{ ORDATA (CHAN, mt_dib.chan, 5), REG_HRO },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ NULL } };
MTAB mt_mod[] = {
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "IOBUS",
&io_set_iobus, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMC",
&io_set_dmc, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMA",
&io_set_dma, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,
NULL, &io_show_chan, NULL },
{ 0 } };
DEVICE mt_dev = {
"MT", mt_unit, mt_reg, mt_mod,
MT_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &mt_detach,
&mt_dib, DEV_DISABLE };
/* IO routine */
int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
uint32 u = dev & 03;
UNIT *uptr = mt_dev.units + u;
static uint8 wrt_fnc[16] = { /* >0 = wr, 1 = chan op */
0, 0, 0, 0, 1, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
switch (inst) { /* case on opcode */
case ioOCP:
mt_updint (mt_rdy, 0); /* clear motion intr */
mt_eof = 0; /* clear eof */
switch (fnc) { /* case on function */
case FNC_DMANM: /* set DMA/DMC */
case FNC_DMAAU:
mt_usel = u; /* save unit select */
if (mt_dib.chan) mt_dma = 1; /* if configured */
break;
case FNC_IOBUS: /* set IOBUS */
mt_usel = u; /* save unit select */
mt_dma = 0;
break;
case FNC_STOPW: /* stop write */
mt_usel = u; /* save unit select */
mt_updint (0, mt_mdirq); /* clear ready */
if (wrt_fnc[uptr->FNC & 017] == 1) /* writing? */
mt_eor = 1; /* set transfer done */
break;
default: /* motion command */
if (mt_busy) return dat; /* nop if ctlr busy */
mt_eor = 0; /* clr transfer done */
mt_err = 0; /* clr error */
mt_usel = u; /* save unit select */
if (((uptr->flags & UNIT_ATT) == 0) || /* nop if not att */
sim_is_active (uptr)) /* or busy */
(IORETURN (mt_stopioe, SCPE_UNATT) | dat);
if (wrt_fnc[fnc] && (uptr->flags & UNIT_WPRT))
return (STOP_MTWRP << IOT_V_REASON);
uptr->FNC = fnc;
uptr->UST = 0;
mt_busy = 1;
sim_activate (uptr, mt_ctime); /* schedule */
break; }
break;
case ioINA: /* INA */
if (fnc) return IOBADFNC (dat); /* fnc 0 only */
if (mt_rdy) { /* ready? */
mt_rdy = 0; /* clear ready */
return IOSKIP (dat | mt_buf); } /* ret buf, skip */
break;
case ioOTA: /* OTA */
if (fnc) return IOBADFNC (dat); /* fnc 0 only */
if (mt_rdy) { /* ready? */
mt_rdy = 0; /* clear ready */
mt_buf = dat; /* store buf */
return IOSKIP (dat); } /* skip */
break;
case ioSKS:
uptr = mt_dev.units + mt_usel; /* use saved unit sel */
switch (fnc) {
case 000: /* ready */
if (mt_rdy) return IOSKIP (dat);
break;
case 001: /* !busy */
if (!mt_busy) return IOSKIP (dat);
break;
case 002: /* !error */
if (!mt_err) return IOSKIP (dat);
break;
case 003: /* !BOT */
if (!(uptr->UST & STA_BOT)) return IOSKIP (dat);
break;
case 004: /* !interrupting */
if (!TST_INTREQ (INT_MT)) return IOSKIP (dat);
break;
case 005: /* !EOT */
if (!(uptr->UST & STA_EOT)) return IOSKIP (dat);
break;
case 006: /* !EOF */
if (!mt_eof) return IOSKIP (dat);
break;
case 007: /* !write prot */
if (!(uptr->flags & UNIT_WPRT)) return IOSKIP (dat);
break;
case 011: /* operational */
if ((uptr->flags & UNIT_ATT) &&
((uptr->FNC & 017) != FNC_REW)) return IOSKIP (dat);
break;
case 012: /* skip if !chan 2 */
return IOSKIP (dat);
case 013: /* skip if !auto */
return IOSKIP (dat);
case 014: /* !rewinding */
uptr = mt_dev.units + (dev & 03); /* use specified unit */
if ((uptr->FNC & 017) != FNC_REW) return IOSKIP (dat);
break; }
break;
case ioEND: /* end of range */
mt_eor = 1; /* transfer done */
break; }
return dat;
}
/* Unit service
If rewind done, reposition to start of tape, set status
else, do operation, set done, interrupt
Can't be write locked, can only write lock detached unit
*/
t_stat mt_svc (UNIT *uptr)
{
int32 ch = mt_dib.chan - 1; /* DMA/DMC ch */
uint32 i, c1, c2, c3;
t_mtrlnt tbc;
t_stat st, r = SCPE_OK;
if ((uptr->flags & UNIT_ATT) == 0) { /* offline? */
mt_err = 1;
mt_busy = 0;
mt_updint (0, 1); /* cmd done */
return IORETURN (mt_stopioe, SCPE_UNATT); }
switch (uptr->FNC) { /* case on function */
case FNC_REW: /* rewind (initial) */
mt_busy = 0; /* ctlr not busy */
uptr->FNC = uptr->FNC | FNC_2ND;
sim_activate (uptr, mt_ctime);
return SCPE_OK; /* continue */
case FNC_REW | FNC_2ND: /* rewind done */
uptr->pos = 0; /* reposition file */
uptr->UST = STA_BOT; /* set BOT */
uptr->FNC = FNC_NOP; /* nop function */
for (i = 0; i < MT_NUMDR; i++) { /* last rewind? */
if ((mt_unit[i].FNC & 017) == FNC_REW) return SCPE_OK; }
mt_updint (mt_rdy, 1); /* yes, motion done */
return SCPE_OK;
case FNC_WEOF: /* write file mark */
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
r = mt_map_err (uptr, st); /* map error */
break; /* sched end motion */
case FNC_FSR: /* space fwd rec */
if (st = sim_tape_sprecf (uptr, &tbc)) /* space fwd, err? */
r = mt_map_err (uptr, st); /* map error */
break; /* sched end motion */
case FNC_BSR: /* space rev rec */
if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */
r = mt_map_err (uptr, st); /* map error */
break; /* sched end motion */
case FNC_FSF: /* space fwd file */
while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
r = mt_map_err (uptr, st); /* map error */
break; /* sched end motion */
case FNC_BSF: /* space rev file */
while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
r = mt_map_err (uptr, st); /* map error */
break; /* sched end motion */
case FNC_EOM: /* end of motion */
uptr->FNC = FNC_NOP; /* nop function */
mt_busy = 0; /* not busy */
mt_updint (mt_rdy, 1); /* end of motion */
return SCPE_OK; /* done! */
/* Unit service, continued */
case FNC_RBCD2: case FNC_RBIN2: case FNC_RBIN3: /* read first */
mt_ptr = 0; /* clr buf ptr */
st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */
if (st != MTSE_OK) { /* error? */
r = mt_map_err (uptr, st); /* map error */
break; } /* sched end motion */
uptr->FNC = uptr->FNC | FNC_2ND; /* next state */
sim_activate (uptr, mt_xtime); /* sched xfer */
return SCPE_OK;
case FNC_RBCD2 | FNC_2ND: /* read, word */
case FNC_RBIN2 | FNC_2ND:
case FNC_RBIN3 | FNC_2ND:
if (mt_ptr >= mt_max) break; /* record done? */
c1 = mtxb[mt_ptr++] & 077; /* get 2 chars */
c2 = mtxb[mt_ptr++] & 077;
if (uptr->FNC == (FNC_RBCD2 | FNC_2ND)) { /* BCD? */
if (c1 == 012) c1 = 0; /* change 12 to 0 */
if (c2 == 012) c2 = 0; }
if (uptr->FNC == (FNC_RBIN3 | FNC_2ND)) { /* read 3? */
if (mt_ptr >= mt_max) break; /* lose wd if not enuf */
c3 = mtxb[mt_ptr++] & 017; } /* get 3rd char */
else c3 = 0;
sim_activate (uptr, mt_xtime); /* no, sched word */
if (mt_eor) return SCPE_OK; /* xfer done? */
mt_buf = (c1 << 10) | (c2 << 4) | c3; /* pack chars */
if (mt_rdy) mt_err = 1; /* buf full? err */
mt_updint (1, mt_mdirq); /* set ready */
if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */
return SCPE_OK; /* continue */
case FNC_WBCD2: case FNC_WBIN2: case FNC_WBIN3: /* write first */
mt_ptr = 0; /* clear buf ptr */
mt_updint (1, mt_mdirq); /* set ready */
if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */
uptr->FNC = uptr->FNC | FNC_2ND; /* next state */
sim_activate (uptr, mt_xtime); /* sched xfer */
return SCPE_OK; /* continue */
case FNC_WBCD2 | FNC_2ND: /* write, word */
case FNC_WBIN2 | FNC_2ND:
case FNC_WBIN3 | FNC_2ND:
if (mt_eor || mt_rdy) { /* done or no data? */
if (!mt_rdy) mt_wrwd (uptr, mt_buf); /* write last word */
if (mt_ptr) { /* any data? */
if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) /* write, err? */
r = mt_map_err (uptr, st); } /* map error */
break; } /* sched end motion */
mt_wrwd (uptr, mt_buf); /* write word */
sim_activate (uptr, mt_xtime); /* no, sched word */
mt_updint (1, mt_mdirq); /* set ready */
if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */
return SCPE_OK; /* continue */
default: /* unknown */
break; }
/* End of command, process error or schedule end of motion */
if (r != SCPE_OK) {
uptr->FNC = FNC_NOP; /* nop function */
mt_busy = 0; /* not busy */
mt_updint (mt_rdy, 1); /* end of motion */
return r; }
uptr->FNC = FNC_EOM; /* sched end motion */
sim_activate (uptr, mt_ctime);
return SCPE_OK;
}
/* Write word to buffer */
void mt_wrwd (UNIT *uptr, uint32 dat)
{
uint32 c1, c2;
c1 = (dat >> 10) & 077; /* get 2 chars */
c2 = (dat >> 4) & 077;
if (uptr->FNC == (FNC_WBCD2 | FNC_2ND)) { /* BCD? */
if (c1 == 0) c1 = 012; /* change 0 to 12 */
if (c2 == 0) c2 = 012; }
if (mt_ptr < DBSIZE) mtxb[mt_ptr++] = c1; /* store 2 char */
if (mt_ptr < DBSIZE) mtxb[mt_ptr++] = c2;
if ((uptr->FNC == (FNC_WBIN3 | FNC_2ND)) && /* write 3? */
(mt_ptr < DBSIZE)) mtxb[mt_ptr++] = mt_buf & 017;
return;
}
/* Map tape error status */
t_stat mt_map_err (UNIT *uptr, t_stat st)
{
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* unattached */
mt_err = 1; /* reject */
case MTSE_OK: /* no error */
return SCPE_IERR; /* never get here! */
case MTSE_TMK: /* end of file */
mt_eof = 1; /* eof */
break;
case MTSE_INVRL: /* invalid rec lnt */
mt_err = 1;
return SCPE_MTRLNT;
case MTSE_IOERR: /* IO error */
mt_err = 1; /* error */
if (mt_stopioe) return SCPE_IOERR;
break;
case MTSE_RECE: /* record in error */
case MTSE_EOM: /* end of medium */
mt_err = 1; /* error */
break;
case MTSE_BOT: /* reverse into BOT */
uptr->UST = STA_BOT; /* set status */
break;
case MTSE_WRP: /* write protect */
mt_err = 1; /* error */
return STOP_MTWRP; }
return SCPE_OK;
}
/* Update interrupts */
void mt_updint (uint32 rdy, uint32 mdirq)
{
mt_rdy = rdy; /* store new ready */
mt_mdirq = mdirq; /* store new motion irq */
if ((mt_rdy && !mt_dma) || mt_mdirq) SET_INT (INT_MT); /* update int request */
else CLR_INT (INT_MT);
return;
}
/* Reset routine */
t_stat mt_reset (DEVICE *dptr)
{
int32 i;
UNIT *uptr;
mt_buf = 0; /* clear state */
mt_usel = 0;
mt_mdirq = 0;
mt_eor = 0;
mt_busy = 0;
mt_rdy = 0;
mt_eof = 0;
mt_err = 0;
mt_dma = 0;
CLR_INT (INT_MT); /* clear int, enb */
CLR_ENB (INT_MT);
for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */
uptr = mt_dev.units + i;
sim_tape_reset (uptr); /* reset tape */
sim_cancel (uptr); /* cancel op */
uptr->UST = uptr->pos? 0: STA_BOT; /* update status */
uptr->FNC = FNC_NOP; }
return SCPE_OK;
}
/* Attach routine */
t_stat mt_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = sim_tape_attach (uptr, cptr); /* attach unit */
if (r != SCPE_OK) return r; /* update status */
uptr->UST = STA_BOT;
return r;
}
/* Detach routine */
t_stat mt_detach (UNIT* uptr)
{
uptr->UST = 0; /* update status */
uptr->FNC = FNC_NOP; /* nop function */
return sim_tape_detach (uptr); /* detach unit */
}

View file

@ -28,6 +28,7 @@
tty 316/516-33 teleprinter
clk/options 316/516-12 real time clocks/internal options
24-Oct-03 RMS Added DMA/DMC support
25-Apr-03 RMS Revised for extended file support
01-Mar-03 RMS Added SET/SHOW CLK FREQ support
22-Dec-02 RMS Added break support
@ -50,7 +51,7 @@ extern uint16 M[];
extern int32 PC;
extern int32 stop_inst;
extern int32 C, dp, ext, extoff_pending, sc;
extern int32 dev_ready, dev_enable;
extern int32 dev_int, dev_enb;
extern UNIT cpu_unit;
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
@ -58,15 +59,19 @@ int32 ptp_power = 0, ptp_ptime; /* punch power, time */
int32 tty_mode = 0, tty_buf = 0; /* tty mode, buf */
int32 clk_tps = 60; /* ticks per second */
int32 ptrio (int32 inst, int32 fnc, int32 dat, int32 dev);
t_stat ptr_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
int32 ptpio (int32 inst, int32 fnc, int32 dat, int32 dev);
t_stat ptp_svc (UNIT *uptr);
t_stat ptp_reset (DEVICE *dptr);
int32 ttyio (int32 inst, int32 fnc, int32 dat, int32 dev);
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tty_reset (DEVICE *dptr);
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
int32 clkio (int32 inst, int32 fnc, int32 dat, int32 dev);
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);
@ -80,14 +85,16 @@ t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
ptr_reg PTR register list
*/
DIB ptr_dib = { PTR, IOBUS, 1, &ptrio };
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (READY, dev_ready, INT_V_PTR) },
{ FLDATA (ENABLE, dev_enable, INT_V_PTR) },
{ FLDATA (READY, dev_int, INT_V_PTR) },
{ FLDATA (ENABLE, dev_enb, INT_V_PTR) },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
@ -97,7 +104,8 @@ DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
&ptr_boot, NULL, NULL };
&ptr_boot, NULL, NULL,
&ptr_dib, 0 };
/* PTP data structures
@ -107,13 +115,15 @@ DEVICE ptr_dev = {
ptp_reg PTP register list
*/
DIB ptp_dib = { PTP, IOBUS, 1, &ptpio };
UNIT ptp_unit = {
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (READY, dev_ready, INT_V_PTP) },
{ FLDATA (ENABLE, dev_enable, INT_V_PTP) },
{ FLDATA (READY, dev_int, INT_V_PTP) },
{ FLDATA (ENABLE, dev_enb, INT_V_PTP) },
{ FLDATA (POWER, ptp_power, 0) },
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
@ -121,12 +131,12 @@ REG ptp_reg[] = {
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ NULL } };
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&ptp_dib, 0 };
/* TTY data structures
@ -139,6 +149,8 @@ DEVICE ptp_dev = {
#define TTI 0
#define TTO 1
DIB tty_dib = { TTY, IOBUS, 1, &ttyio };
UNIT tty_unit[] = {
{ UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT },
{ UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT } };
@ -146,8 +158,8 @@ UNIT tty_unit[] = {
REG tty_reg[] = {
{ ORDATA (BUF, tty_buf, 8) },
{ FLDATA (MODE, tty_mode, 0) },
{ FLDATA (READY, dev_ready, INT_V_TTY) },
{ FLDATA (ENABLE, dev_enable, INT_V_TTY) },
{ FLDATA (READY, dev_int, INT_V_TTY) },
{ FLDATA (ENABLE, dev_enb, INT_V_TTY) },
{ DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT },
@ -164,7 +176,8 @@ DEVICE tty_dev = {
"TTY", tty_unit, tty_reg, tty_mod,
2, 10, 31, 1, 8, 8,
NULL, NULL, &tty_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&tty_dib, 0 };
/* CLK data structures
@ -174,12 +187,14 @@ DEVICE tty_dev = {
clk_reg CLK register list
*/
DIB clk_dib = { CLK_KEYS, IOBUS, 1, &clkio };
UNIT clk_unit = {
UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
{ FLDATA (READY, dev_ready, INT_V_CLK) },
{ FLDATA (ENABLE, dev_enable, INT_V_CLK) },
{ FLDATA (READY, dev_int, INT_V_CLK) },
{ FLDATA (ENABLE, dev_enb, INT_V_CLK) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
{ NULL } };
@ -197,11 +212,12 @@ DEVICE clk_dev = {
"CLK", &clk_unit, clk_reg, clk_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &clk_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&clk_dib, 0 };
/* Paper tape reader: IO routine */
int32 ptrio (int32 inst, int32 fnc, int32 dat)
int32 ptrio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
switch (inst) { /* case on opcode */
case ioOCP: /* OCP */
@ -211,14 +227,14 @@ case ioOCP: /* OCP */
break;
case ioSKS: /* SKS */
if (fnc & 013) return IOBADFNC (dat); /* only fnc 0,4 */
if (((fnc == 0) && TST_READY (INT_PTR)) || /* fnc 0? skip rdy */
if (((fnc == 0) && TST_INT (INT_PTR)) || /* fnc 0? skip rdy */
((fnc == 4) && !TST_INTREQ (INT_PTR))) /* fnc 4? skip !int */
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 */
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
if (TST_INT (INT_PTR)) { /* ready? */
CLR_INT (INT_PTR); /* clear ready */
return IOSKIP (ptr_unit.buf | dat); } /* ret buf, skip */
break; } /* end case op */
return dat;
@ -239,7 +255,7 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte */
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
SET_READY (INT_PTR); /* set ready flag */
SET_INT (INT_PTR); /* set ready flag */
ptr_unit.buf = temp & 0377; /* get byte */
ptr_unit.pos = ftell (ptr_unit.fileref); /* update pos */
sim_activate (&ptr_unit, ptr_unit.wait); /* reactivate */
@ -250,8 +266,8 @@ return SCPE_OK;
t_stat ptr_reset (DEVICE *dptr)
{
CLR_READY (INT_PTR); /* clear ready, enb */
CLR_ENABLE (INT_PTR);
CLR_INT (INT_PTR); /* clear ready, enb */
CLR_ENB (INT_PTR);
ptr_unit.buf = 0; /* clear buffer */
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
@ -292,13 +308,13 @@ return SCPE_OK;
/* Paper tape punch: IO routine */
int32 ptpio (int32 inst, int32 fnc, int32 dat)
int32 ptpio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
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 */
CLR_INT (INT_PTP); /* not ready */
ptp_power = 0; /* turn off power */
sim_cancel (&ptp_unit); } /* stop punch */
else if (ptp_power == 0) /* fnc 0? start */
@ -307,7 +323,7 @@ case ioOCP: /* OCP */
case ioSKS: /* SKS */
if ((fnc & 012) || (fnc == 005)) /* only 0, 1, 4 */
return IOBADFNC (dat);
if (((fnc == 00) && TST_READY (INT_PTP)) || /* fnc 0? skip rdy */
if (((fnc == 00) && TST_INT (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 */
@ -315,8 +331,8 @@ case ioSKS: /* SKS */
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 */
if (TST_INT (INT_PTP)) { /* if ptp ready */
CLR_INT (INT_PTP); /* clear ready */
ptp_unit.buf = dat & 0377; /* store byte */
sim_activate (&ptp_unit, ptp_unit.wait);
return IOSKIP (dat); } /* skip return */
@ -329,7 +345,7 @@ return dat;
t_stat ptp_svc (UNIT *uptr)
{
SET_READY (INT_PTP); /* set flag */
SET_INT (INT_PTP); /* set flag */
if (ptp_power == 0) { /* power on? */
ptp_power = 1; /* ptp is ready */
return SCPE_OK; }
@ -347,8 +363,8 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr)
{
CLR_READY (INT_PTP); /* clear ready, enb */
CLR_ENABLE (INT_PTP);
CLR_INT (INT_PTP); /* clear ready, enb */
CLR_ENB (INT_PTP);
ptp_power = 0; /* power off */
ptp_unit.buf = 0; /* clear buffer */
sim_cancel (&ptp_unit); /* deactivate unit */
@ -357,22 +373,22 @@ return SCPE_OK;
/* Terminal: IO routine */
int32 ttyio (int32 inst, int32 fnc, int32 dat)
int32 ttyio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
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 */
SET_READY (INT_TTY);
SET_INT (INT_TTY);
tty_mode = 1; } /* mode is output */
else if ((fnc == 0) && tty_mode) { /* output to input? */
CLR_READY (INT_TTY); /* clear ready */
CLR_INT (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 */
if (((fnc == 0) && TST_READY (INT_TTY)) || /* fnc 0? skip rdy */
if (((fnc == 0) && TST_INT (INT_TTY)) || /* fnc 0? skip rdy */
((fnc == 1) && /* fnc 1? skip !busy */
tty_mode && !sim_is_active (&tty_unit[TTO])) ||
((fnc == 4) && !TST_INTREQ (INT_TTY)) || /* fnc 4? skip !int */
@ -381,22 +397,22 @@ case ioSKS: /* SKS */
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 */
if (fnc & 005) return IOBADFNC (dat); /* only 0,2 */
if (TST_INT (INT_TTY)) { /* ready? */
if (tty_mode == 0) CLR_INT (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? */
if (TST_INT (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); }
CLR_INT (INT_TTY); }
return IOSKIP (dat); }
break; } /* end case op */
return dat;
@ -419,7 +435,7 @@ else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177);
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 */
SET_INT (INT_TTY); /* set flag */
if (out) sim_putchar (out); } /* echo */
return SCPE_OK;
}
@ -429,12 +445,14 @@ t_stat tto_svc (UNIT *uptr)
int32 c;
t_stat r;
SET_READY (INT_TTY); /* set done flag */
if (tty_unit[TTO].flags & UNIT_KSR) { /* UC only? */
c = tty_buf & 0177; /* mask to 7b */
if (islower (c)) c = toupper (c); } /* cvt to UC */
else c = tty_buf & ((tty_unit[TTO].flags & UNIT_8B)? 0377: 0177);
if ((r = sim_putchar (c)) != SCPE_OK) return r; /* output char */
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */
SET_INT (INT_TTY); /* set done flag */
tty_unit[TTO].pos = tty_unit[TTO].pos + 1;
return SCPE_OK;
}
@ -443,8 +461,8 @@ return SCPE_OK;
t_stat tty_reset (DEVICE *dptr)
{
CLR_READY (INT_TTY); /* clear ready, enb */
CLR_ENABLE (INT_TTY);
CLR_INT (INT_TTY); /* clear ready, enb */
CLR_ENB (INT_TTY);
tty_mode = 0; /* mode = input */
tty_buf = 0;
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */
@ -461,12 +479,12 @@ return SCPE_OK;
/* Clock/options: IO routine */
int32 clkio (int32 inst, int32 fnc, int32 dat)
int32 clkio (int32 inst, int32 fnc, int32 dat, int32 dev)
{
switch (inst) { /* case on opcode */
case ioOCP: /* OCP */
if (fnc & 015) return IOBADFNC (dat); /* only fnc 0,2 */
CLR_READY (INT_CLK); /* reset ready */
CLR_INT (INT_CLK); /* reset ready */
if (fnc) sim_cancel (&clk_unit); /* fnc = 2? stop */
else { /* fnc = 0? */
if (!sim_is_active (&clk_unit))
@ -477,13 +495,13 @@ case ioSKS: /* SKS */
if (fnc == 0) { /* clock skip !int */
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)))
if (((fnc == 002) && !TST_INT (INT_MPE)) ||
((fnc == 012) && TST_INT (INT_MPE)))
return IOSKIP (dat); }
else return IOBADFNC (dat); /* invalid fnc */
break;
case ioOTA: /* OTA */
if (fnc == 000) dev_enable = dat; /* SMK */
if (fnc == 000) dev_enb = dat; /* SMK */
else if (fnc == 010) { /* OTK */
C = (dat >> 15) & 1; /* set C */
if (cpu_unit.flags & UNIT_HSA) /* HSA included? */
@ -505,7 +523,7 @@ t_stat clk_svc (UNIT *uptr)
{
M[M_CLK] = M[M_CLK + 1] & DMASK; /* increment mem ctr */
if (M[M_CLK] == 0) SET_READY (INT_CLK); /* = 0? set flag */
if (M[M_CLK] == 0) SET_INT (INT_CLK); /* = 0? set flag */
sim_activate (&clk_unit, sim_rtc_calb (clk_tps)); /* reactivate */
return SCPE_OK;
}
@ -514,8 +532,8 @@ return SCPE_OK;
t_stat clk_reset (DEVICE *dptr)
{
CLR_READY (INT_CLK); /* clear ready, enb */
CLR_ENABLE (INT_CLK);
CLR_INT (INT_CLK); /* clear ready, enb */
CLR_ENB (INT_CLK);
sim_cancel (&clk_unit); /* deactivate unit */
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.
24-Oct-03 RMS Added DMA/DMC support
17-Sep-01 RMS Removed multiconsole support
*/
@ -31,9 +32,14 @@
extern DEVICE cpu_dev;
extern UNIT cpu_unit;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tty_dev, lpt_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE tty_dev;
extern DEVICE lpt_dev;
extern DEVICE clk_dev;
extern DEVICE dp_dev;
extern DEVICE fhd_dev;
extern DEVICE mt_dev;
extern REG cpu_reg[];
extern uint16 M[];
extern int32 sim_switches;
@ -54,10 +60,16 @@ REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = { &cpu_dev,
&ptr_dev, &ptp_dev,
&tty_dev, &lpt_dev,
DEVICE *sim_devices[] = {
&cpu_dev,
&ptr_dev,
&ptp_dev,
&tty_dev,
&lpt_dev,
&clk_dev,
&dp_dev,
&fhd_dev,
&mt_dev,
NULL };
const char *sim_stop_messages[] = {
@ -66,7 +78,11 @@ const char *sim_stop_messages[] = {
"Unimplemented I/O device",
"HALT instruction",
"Breakpoint",
"Indirect address loop" };
"Indirect address loop",
"DMA error",
"MT write protected",
"DP write overrun, track destroyed",
"DP track format invalid" };
/* Binary loader

View file

@ -291,6 +291,7 @@ t_stat drc_svc (UNIT *uptr)
{
int32 devd, trk, sec;
uint32 da;
uint16 *bptr = uptr->filebuf;
if ((uptr->flags & UNIT_ATT) == 0) {
drc_sta = DRS_ABO;
@ -304,7 +305,7 @@ da = ((trk * DR_NUMSC) + sec) * DR_NUMWD;
if (drc_cw & CW_WR) { /* write? */
if ((da < uptr->capac) && (sec < DR_NUMSC)) {
*(((uint16 *) uptr->filebuf) + da + drd_ptr) = drd_obuf;
bptr[da + drd_ptr] = drd_obuf;
if (((uint32) (da + drd_ptr)) >= uptr->hwmark)
uptr->hwmark = da + drd_ptr + 1; }
drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */
@ -313,12 +314,12 @@ if (drc_cw & CW_WR) { /* write? */
sim_activate (uptr, dr_time); } /* sched next word */
else if (drd_ptr) { /* done, need to fill? */
for ( ; drd_ptr < DR_NUMWD; drd_ptr++)
*(((uint16 *) uptr->filebuf) + da + drd_ptr) = 0; }
bptr[da + drd_ptr] = 0; }
} /* end write */
else { /* read */
if (CMD (devd)) { /* dch active? */
if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0;
else drd_ibuf = *(((uint16 *) uptr->filebuf) + da + drd_ptr);
else drd_ibuf = bptr[da + drd_ptr];
drd_ptr = dr_incda (trk, sec, drd_ptr);
setFLG (devd); /* set dch flg */
sim_activate (uptr, dr_time); } /* sched next word */
@ -367,6 +368,7 @@ if (sz == 0) return SCPE_IERR;
uptr->capac = sz;
return attach_unit (uptr, cptr);
}
/* Set size routine */
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)

View file

@ -25,6 +25,7 @@
ipli, iplo 12556B interprocessor link pair
21-Dec-03 RMS Adjusted ipl_ptime for TSB (from Mike Gemeny)
09-May-03 RMS Added network device flag
31-Jan-03 RMS Links are full duplex (found by Mike Gemeny)
*/
@ -49,7 +50,7 @@
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_ptime = 31; /* polling interval */
int32 ipl_stopioe = 0; /* stop on error */
int32 ipl_hold[2] = { 0 }; /* holding character */
@ -339,7 +340,7 @@ return SCPE_OK;
t_stat ipl_detach (UNIT *uptr)
{
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
if (!(uptr->flags & UNIT_ATT)) 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 */

View file

@ -25,6 +25,7 @@
mt 12559A 3030 nine track magnetic tape
21-Dec-03 RMS Adjusted msc_ctime for TSB (from Mike Gemeny)
25-Apr-03 RMS Revised for extended file support
28-Mar-03 RMS Added multiformat support
28-Feb-03 RMS Revised for magtape library
@ -92,7 +93,7 @@ int32 mtc_fnc = 0; /* function */
int32 mtc_sta = 0; /* status register */
int32 mtc_dtf = 0; /* data xfer flop */
int32 mtc_1st = 0; /* first svc flop */
int32 mtc_ctime = 1000; /* command wait */
int32 mtc_ctime = 40; /* command wait */
int32 mtc_gtime = 1000; /* gap stop time */
int32 mtc_xtime = 15; /* data xfer time */
int32 mtc_stopioe = 1; /* stop on error */

View file

@ -25,6 +25,7 @@
mux,muxl,muxc 12920A terminal multiplexor
21-Dec-03 RMS Added invalid character screening for TSB (from Mike Gemeny)
09-May-03 RMS Added network device flag
01-Nov-02 RMS Added 7B/8B support
22-Aug-02 RMS Updated for changes to sim_tmxr
@ -526,7 +527,10 @@ if (mux_ldsc[ln].conn) { /* connected? */
if (mux_xpar[ln] & OTL_DIAG) /* xmt diag? */
mux_diag (mux_xbuf[ln]); /* before munge */
mux_xdon[ln] = 1; /* set done */
tmxr_putc_ln (lp, c); /* output char */
if (!(muxl_unit[ln].flags & UNIT_8B) && /* not transparent? */
(c != 0x7f) && (c != 0x13) && /* not del, ^S? */
(c != 0x11) && (c != 0x5)) /* not ^Q, ^E? */
tmxr_putc_ln (lp, c); /* output char */
tmxr_poll_tx (&mux_desc); } } /* poll xmt */
else { /* buf full */
tmxr_poll_tx (&mux_desc); /* poll xmt */

View file

@ -1,6 +1,6 @@
/* hp2100_stddev.c: HP2100 standard devices simulator
Copyright (c) 1993-2003, Robert M. Supnik
Copyright (c) 1993-2004, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -28,6 +28,7 @@
tty 12531C buffered teleprinter interface
clk 12539C time base generator
29-Mar-03 RMS Added support for console backpressure
25-Apr-03 RMS Added extended file support
22-Dec-02 RMS Added break support
01-Nov-02 RMS Revised BOOT command for IBL ROMs
@ -538,15 +539,20 @@ return dat;
t_stat tto_out (int32 c)
{
t_stat ret = SCPE_OK;
t_stat r;
if (tty_mode & TM_PRI) { /* printing? */
if (tty_unit[TTO].flags & UNIT_UC) { /* UC only? */
c = c & 0177;
if (islower (c)) c = toupper (c); }
else c = c & ((tty_unit[TTO].flags & UNIT_8B)? 0377: 0177);
ret = sim_putchar (c); /* output char */
if (r = sim_putchar_s (c)) return r; /* output char */
tty_unit[TTO].pos = tty_unit[TTO].pos + 1; }
return SCPE_OK;
}
t_stat ttp_out (int32 c)
{
if (tty_mode & TM_PUN) { /* punching? */
if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ttp_stopioe, SCPE_UNATT);
@ -555,7 +561,7 @@ if (tty_mode & TM_PUN) { /* punching? */
clearerr (tty_unit[TTP].fileref);
return SCPE_IOERR; }
tty_unit[TTP].pos = ftell (tty_unit[TTP].fileref); }
return ret;
return SCPE_OK;
}
t_stat tti_svc (UNIT *uptr)
@ -574,19 +580,25 @@ 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 */
if (c) return tto_out (c); } /* echo or punch? */
if (c) {
tto_out (c); /* echo? */
return ttp_out (c); } } /* punch? */
return SCPE_OK;
}
t_stat tto_svc (UNIT *uptr)
{
int32 c, dev;
t_stat r;
c = tty_buf; /* get char */
tty_buf = 0377; /* defang buf */
if ((r = tto_out (c)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* retry */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */
dev = tty_dib.devno; /* get device no */
setFLG (dev); /* set done flag */
c = tty_buf;
tty_buf = 0377; /* defang buf */
return tto_out (c); /* print and/or punch */
return ttp_out (c); /* punch if enabled */
}
/* Reset routine */

View file

@ -26,6 +26,7 @@
This CPU module incorporates code and comments from the 1620 simulator by
Geoff Kuenning, with his permission.
02-Nov-03 RMS Fixed bug in branch digit (found by Dave Babcock)
21-Aug-03 RMS Fixed bug in immediate index add (found by Michael Short)
25-Apr-03 RMS Changed t_addr to uint32 throughout
18-Oct-02 RMS Fixed bugs in invalid result testing (found by Hans Pufal)
@ -567,10 +568,10 @@ case OP_BB:
else reason = STOP_INVRTN; /* MAR check */
break;
/* Branch on digit (zero) - P,Q are valid */
/* Branch on digit (not zero) - P,Q are valid */
case OP_BD:
if ((M[QAR] & DIGIT) == 0) { /* digit == 0? */
if ((M[QAR] & DIGIT) != 0) { /* digit != 0? */
BRANCH (PAR); } /* branch */
break;

View file

@ -25,6 +25,7 @@
lpt 1443 line printer
29-Dec-03 RMS Fixed bug in scheduling
25-Apr-03 RMS Revised for extended file support
*/
@ -217,7 +218,7 @@ if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */
return SCPE_UNATT; }
ind[IN_PRBSY] = 1; /* print busy */
sim_activate (&lpt_unit, lpt_unit.time); /* start timer */
sim_activate (&lpt_unit, lpt_unit.wait); /* start timer */
for (i = LPT_WIDTH; i <= LPT_BSIZE; i++) /* clear unprintable */
lpt_buf[i] = ' ';

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 KiB

After

Width:  |  Height:  |  Size: 372 KiB

BIN
Ibm1130/1132empty.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
Ibm1130/1132full.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
Ibm1130/1442empty.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
Ibm1130/1442eof.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
Ibm1130/1442full.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
Ibm1130/1442middle.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -82,9 +82,9 @@ $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib shell32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\
wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\
wsock32.lib shell32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\
/PDB:$(OUTDIR)/"ibm1130.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe"
DEF_FILE=
LINK32_OBJS= \
@ -161,9 +161,10 @@ $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib shell32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# SUBTRACT LINK32 /MAP
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\
wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\
wsock32.lib shell32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\
/PDB:$(OUTDIR)/"ibm1130.pdb" /DEBUG /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe"
DEF_FILE=
LINK32_OBJS= \

View file

@ -19,7 +19,7 @@
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
1 TEXTINCLUDE DISCARDABLE
BEGIN
"ibm1130res.h\0"
END
@ -45,9 +45,21 @@ END
// Bitmap
//
IDB_CONSOLE BITMAP DISCARDABLE "1130consoleblank.bmp"
IDB_CONSOLE BITMAP "1130consoleblank.bmp"
FULL_1442 BITMAP "1442full.bmp"
EOF_1442 BITMAP "1442eof.bmp"
EMPTY_1442 BITMAP "1442empty.bmp"
MIDDLE_1442 BITMAP "1442middle.bmp"
FULL_1132 BITMAP "1132full.bmp"
EMPTY_1132 BITMAP "1132empty.bmp"
IDC_HAND CURSOR DISCARDABLE "HAND.CUR"
/////////////////////////////////////////////////////////////////////////////
//
// Cursor
//
IDC_HAND CURSOR "HAND.CUR"
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////

View file

@ -17,6 +17,7 @@
16-Aug-02 BLK Fixed bug in multiply instruction; didn't work with negative values
18-Mar-03 BLK Fixed bug in divide instruction; didn't work with negative values
23-Jul-03 BLK Prevented tti polling in CGI mode
24-Nov-03 BLK Fixed carry bit error in subtract and subtract double, found by Bob Flanders
The register state for the IBM 1130 CPU is:
@ -556,6 +557,8 @@ t_stat sim_instr (void)
if (cpu_unit.flags & UNIT_ATT)
trace_io("* XIO %s %s mod %02x addr %04x", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr);
// fprintf(stderr, "* XIO %s %s mod %02x addr %04x\n", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr);
ACC = 0; /* ACC is destroyed, and default XIO_SENSE_DEV result is 0 */
switch (iocc_func) {
@ -895,7 +898,7 @@ t_stat sim_instr (void)
src2 = ReadW(eaddr);
ACC = (ACC-src2) & 0xFFFF;
C = src2 < src;
C = src < src2;
if (! V)
V = SIGN_BIT((src ^ src2) & (src ^ ACC));
break;
@ -907,7 +910,7 @@ t_stat sim_instr (void)
ACC = (dst >> 16) & 0xFFFF;
EXT = dst & 0xFFFF;
C = (unsigned int32) src2 < (unsigned int32) src;
C = (unsigned int32) src < (unsigned int32) src2;
if (! V)
V = DWSIGN_BIT((src ^ src2) & (src ^ dst));
break;
@ -1527,7 +1530,7 @@ static t_stat cpu_attach (UNIT *uptr, char *cptr)
fclose(fd);
}
return attach_unit(uptr, cptr);
return attach_unit(uptr, quotefix(cptr)); /* fix quotes in filenames & attach */
}
static void trace_instruction (void)
@ -1795,6 +1798,7 @@ static void cgi_stop(t_stat reason)
ORIGIN orig;
char *msg;
} pretstop[] = {
0x8000, O_FORTRAN, "I/O attempted on invalid unit # or uninstalled device (just a guess)",
0xF000, O_FORTRAN, "No *IOCS was specified but I/O was attempted",
0xF001, O_FORTRAN, "Local unit defined incorrectly, or no *IOCS for specified device",
0xF002, O_FORTRAN, "Requested record exceeds buffer size",

File diff suppressed because it is too large Load diff

View file

@ -260,6 +260,8 @@ void xio_error (char *msg);
void bail (char *msg);
t_stat load_cr_boot (int drv, int switches);
t_stat cr_boot (int unitno, DEVICE *dptr);
t_stat cr_rewind (void);
t_stat cr_detach (UNIT *uptr);
void calc_ints (void); /* recalculate interrupt bitmask */
void trace_io (char *fmt, ...); /* debugging printout */
void scp_panic (char *msg); /* bail out of simulator */
@ -269,9 +271,12 @@ char hollerith_to_ascii (uint16 hol); /* for debugging use only */
t_bool gdu_active (void);
void remark_cmd (char *remark);
void stuff_cmd (char *cmd);
t_bool stuff_and_wait (char *cmd, int timeout, int delay);
void update_gui (t_bool force);
void sim_init (void);
t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help);
t_stat basic_attach (UNIT *uptr, char *cptr);
char * quotefix (char * cptr);
/* GUI interface routines */
t_bool keyboard_is_busy (void);

View file

@ -513,7 +513,7 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr)
SETBIT(uptr->flags, UNIT_ROABLE|UNIT_MUSTBUF); // but don't set the UNIT_RONLY flag so DMS can write to the buffered image
}
if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) { // mount new disk
if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK) { // mount new disk
SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY);
return rval;
}

View file

@ -57,10 +57,10 @@
// -------------------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <ctype.h>
#include <string.h>
#include "ibm1130_fmt.h"
#define MAXLINE 81 // maximum output line size

View file

@ -662,7 +662,7 @@ static HBITMAP hBmp = NULL;
static int curwid = 0;
static int curht = 0;
static BOOL wcInited = FALSE;
static int GDUPumpID = 0;
static DWORD GDUPumpID = 0;
static HANDLE hGDUPump = INVALID_HANDLE_VALUE;
static HPEN hGreenPen = NULL;
static HBRUSH hRedBrush = NULL;

View file

@ -11,6 +11,10 @@
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org
*
* 02-Dec-02 BLK Changed display, added printer and card reader icons
* Added drag and drop support for scripts and card decks
* Added support for physical card reader and printer (hides icons)
*
* 17-May-02 BLK Pulled out of ibm1130_cpu.c
*/
@ -32,6 +36,14 @@
# define UPDATE_INTERVAL 5000 // GUI: set to 100000/f where f = desired updates/second of 1130 time
#endif
#define UNIT_V_CR_EMPTY (UNIT_V_UF + 5) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_cr.c */
#define UNIT_CR_EMPTY (1u << UNIT_V_CR_EMPTY)
#define UNIT_V_PHYSICAL (UNIT_V_UF + 9)
#define UNIT_PHYSICAL (1u << UNIT_V_PHYSICAL)
#define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */
#define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
/* ------------------------------------------------------------------------
* Function declarations
* ------------------------------------------------------------------------ */
@ -71,6 +83,10 @@ DEVICE console_dev = {
extern char *read_line (char *cptr, int size, FILE *stream);
extern FILE *sim_log;
extern DEVICE *find_unit (char *cptr, UNIT **uptr);
extern UNIT cr_unit; /* pointers to 1442 and 1132 (1403) printers */
extern UNIT prt_unit;
#ifndef GUI_SUPPORT
void update_gui (int force) {} /* stubs for non-GUI builds */
@ -84,10 +100,11 @@ extern FILE *sim_log;
static void init_console_window (void) {}
static void destroy_console_window (void) {}
t_stat console_reset (DEVICE *dptr) {return SCPE_OK;}
void stuff_cmd (char *cmd) {}
char *read_cmdline (char *ptr, int size, FILE *stream) {return read_line(ptr, size, stream);}
void remark_cmd (char *remark) {printf("%s\n", remark); if (sim_log) fprintf(sim_log, "%s\n", remark);}
t_stat console_reset (DEVICE *dptr) {return SCPE_OK;}
void stuff_cmd (char *cmd) {}
t_bool stuff_and_wait (char *cmd, int timeout, int delay) {return FALSE;}
char *read_cmdline (char *ptr, int size, FILE *stream) {return read_line(ptr, size, stream);}
void remark_cmd (char *remark) {printf("%s\n", remark); if (sim_log) fprintf(sim_log, "%s\n", remark);}
#else
t_stat console_reset (DEVICE *dptr)
@ -134,15 +151,29 @@ void scp_panic (char *msg)
#define IDC_RESET 14
#define IDC_PROGRAM_LOAD 15
#define IDC_TEAR 16 // standard button
#define IDC_1442 17 // device images
#define IDC_1132 18
#define LAMPTIME 500 // 500 msec delay on updating
#define FLASH_TIMER_ID 1
#define UPDATE_TIMER_ID 2
#define RUNSWITCH_X 689 // center of the run mode switch dial
#define RUNSWITCH_Y 107
#define TOGGLES_X 122 // left edge of series of toggle switches
#define TXTBOX_X 200 // text labels showing attached devices
#define TXTBOX_Y 300
#define TXTBOX_WIDTH 195
#define TXTBOX_HEIGHT 12
static BOOL class_defined = FALSE;
static HWND hConsoleWnd = NULL;
static HBITMAP hBitmap = NULL;
static HFONT hFont = NULL;
static HFONT hBtnFont = NULL;
static HFONT hTinyFont = NULL;
static HBRUSH hbLampOut = NULL;
static HBRUSH hbWhite = NULL;
static HBRUSH hbBlack = NULL;
@ -164,41 +195,80 @@ static char szConsoleClassName[] = "1130CONSOLE";
static DWORD PumpID = 0;
static HANDLE hPump = INVALID_HANDLE_VALUE;
static int bmwid, bmht;
static HANDLE hbm1442_full, hbm1442_empty, hbm1442_eof, hbm1442_middle;
static HANDLE hbm1132_full, hbm1132_empty;
static struct tag_btn {
int x, y;
int x, y, wx, wy;
char *txt;
BOOL pushable, state;
COLORREF clr;
HBRUSH hbrLit, hbrDark;
HWND hBtn;
BOOL subclassed;
} btn[] = {
0, 0, "KEYBOARD\nSELECT", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
0, 1, "DISK\nUNLOCK", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL,
0, 2, "RUN", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL,
0, 3, "PARITY\nCHECK", FALSE, FALSE, RGB(255,0,0), NULL, NULL, NULL,
0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "KEYBOARD\nSELECT", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
0, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "DISK\nUNLOCK", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
0, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "RUN", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,
0, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "PARITY\nCHECK", FALSE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,
1, 0, "", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
1, 1, "FILE\nREADY", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL,
1, 2, "FORMS\nCHECK", FALSE, FALSE, RGB(255,255,0), NULL, NULL, NULL,
1, 3, "POWER\nON", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL,
1, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
1, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "FILE\nREADY", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,
1, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "FORMS\nCHECK", FALSE, FALSE, RGB(255,255,0), NULL, NULL, NULL, TRUE,
1, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "POWER\nON", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
2, 0, "POWER", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
2, 1, "PROGRAM\nSTART", TRUE, FALSE, RGB(0,255,0), NULL, NULL, NULL,
2, 2, "PROGRAM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL,
2, 3, "LOAD\nIAR", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL,
2, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "POWER", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
2, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nSTART", TRUE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,
2, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,
2, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "LOAD\nIAR", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,
3, 0, "KEYBOARD", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL,
3, 1, "IMM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL,
3, 2, "CHECK\nRESET", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL,
3, 3, "PROGRAM\nLOAD", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL,
3, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "KEYBOARD", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
3, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "IMM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,
3, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "CHECK\nRESET", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,
3, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nLOAD", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,
TXTBOX_X+40, TXTBOX_Y+25, 35, 12, "Tear", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
635, 238, 110, 110, "EMPTY_1442", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
// 635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
};
#define NBUTTONS (sizeof(btn) / sizeof(btn[0]))
#define STATE_1442_EMPTY 0 // no cards (no file attached)
#define STATE_1442_FULL 1 // cards in hopper (file attached at BOF)
#define STATE_1442_MIDDLE 2 // cards in hopper and stacker (file attached, neither EOF nor BOF)
#define STATE_1442_EOF 3 // cards in stacker (file attached, at EOF)
#define STATE_1442_HIDDEN 4 // simulator is attached to physical card reader
#define STATE_1132_EMPTY 0 // no paper hanging out of printer
#define STATE_1132_FULL 1 // paper hanging out of printer
#define STATE_1132_HIDDEN 2 // printer is attached to physical printer
static struct tag_txtbox {
int x, y;
char *txt;
char *unitname;
int idctrl;
} txtbox[] = {
TXTBOX_X, TXTBOX_Y, "Card Reader", "CR", -1,
TXTBOX_X, TXTBOX_Y+ 25, "Printer", "PRT", IDC_1132,
TXTBOX_X, TXTBOX_Y+ 50, "Disk 1", "DSK0", -1,
TXTBOX_X, TXTBOX_Y+ 75, "Disk 2", "DSK1", -1,
TXTBOX_X, TXTBOX_Y+100, "Disk 3", "DSK2", -1,
TXTBOX_X, TXTBOX_Y+125, "Disk 4", "DSK3", -1,
TXTBOX_X, TXTBOX_Y+150, "Disk 5", "DSK4", -1,
};
#define NTXTBOXES (sizeof(txtbox) / sizeof(txtbox[0]))
#define TXTBOX_BOTTOM (TXTBOX_Y+150)
static void init_console_window (void);
static void destroy_console_window (void);
LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static DWORD WINAPI Pump (LPVOID arg);
static void accept_dropped_file (HANDLE hDrop);
static void tear_printer (void);
#define NIXOBJECT(hObj) if (hObj != NULL) {DeleteObject(hObj); hObj = NULL;}
@ -249,6 +319,7 @@ static void destroy_console_window (void)
NIXOBJECT(hbLampOut)
NIXOBJECT(hFont)
NIXOBJECT(hBtnFont);
NIXOBJECT(hTinyFont);
NIXOBJECT(hcHand)
NIXOBJECT(hSwitchPen)
NIXOBJECT(hLtGreyPen)
@ -322,6 +393,7 @@ void update_gui (BOOL force)
BOOL state;
static int in_here = FALSE;
static int32 displayed = 0;
RECT xin;
if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { // setting has changed
displayed = console_unit.flags & UNIT_DISPLAY;
@ -380,9 +452,9 @@ void update_gui (BOOL force)
if ((wait_state|wait_lamp) != shown_wait)
{shown_wait= (wait_state|wait_lamp); RedrawRegion(hConsoleWnd, 380, 77, 414, 97);}
if (CES != shown_ces)
{shown_ces = CES; RepaintRegion(hConsoleWnd, 115, 230, 478, 275);} /* console entry sw: do erase bkgnd */
{shown_ces = CES; RepaintRegion(hConsoleWnd, TOGGLES_X-7, 230, TOGGLES_X+360, 275);} /* console entry sw: do erase bkgnd */
if (RUNMODE != shown_runmode)
{shown_runmode = RUNMODE;RepaintRegion(hConsoleWnd, 270, 359, 330, 418);}
{shown_runmode = RUNMODE;RepaintRegion(hConsoleWnd, RUNSWITCH_X-50, RUNSWITCH_Y-50, RUNSWITCH_X+50, RUNSWITCH_Y+50);}
int_lamps = 0;
@ -415,6 +487,55 @@ void update_gui (BOOL force)
}
}
if (force) { // if force flag is set, update text region
SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+2*TXTBOX_HEIGHT);
InvalidateRect(hConsoleWnd, &xin, TRUE);
}
state = ((cr_unit.flags & UNIT_ATT) == 0) ? STATE_1442_EMPTY :
(cr_unit.flags & UNIT_PHYSICAL) ? STATE_1442_HIDDEN :
(cr_unit.flags & UNIT_CR_EMPTY) ? STATE_1442_EOF :
cr_unit.pos ? STATE_1442_MIDDLE :
STATE_1442_FULL;
if (state != btn[IDC_1442].state) {
if (state == STATE_1442_HIDDEN)
ShowWindow(btn[IDC_1442].hBtn, SW_HIDE);
else {
if (btn[IDC_1442].state == STATE_1442_HIDDEN)
ShowWindow(btn[IDC_1442].hBtn, SW_SHOWNA);
SendMessage(btn[IDC_1442].hBtn, STM_SETIMAGE, IMAGE_BITMAP,
(LPARAM) (
(state == STATE_1442_FULL) ? hbm1442_full :
(state == STATE_1442_MIDDLE) ? hbm1442_middle :
(state == STATE_1442_EOF) ? hbm1442_eof :
hbm1442_empty));
}
btn[IDC_1442].state = state;
}
state = ((prt_unit.flags & UNIT_ATT) == 0) ? STATE_1132_EMPTY :
(prt_unit.flags & UNIT_PHYSICAL_PTR) ? STATE_1132_HIDDEN :
prt_unit.pos ? STATE_1132_FULL :
STATE_1132_EMPTY;
if (state != btn[IDC_1132].state) {
if (state == STATE_1132_HIDDEN)
ShowWindow(btn[IDC_1132].hBtn, SW_HIDE);
else {
if (btn[IDC_1132].state == STATE_1132_HIDDEN)
ShowWindow(btn[IDC_1132].hBtn, SW_SHOWNA);
SendMessage(btn[IDC_1132].hBtn, STM_SETIMAGE, IMAGE_BITMAP,
(LPARAM) (
(state == STATE_1132_FULL) ? hbm1132_full : hbm1132_empty));
}
btn[IDC_1132].state = state;
}
in_here = FALSE;
}
@ -474,6 +595,9 @@ void PaintButton (LPDRAWITEMSTRUCT dis)
if (! BETWEEN(i, 0, NBUTTONS-1))
return;
if (! btn[i].subclassed)
return;
FillRect(dis->hDC, &dis->rcItem, ((btn[i].pushable || power) && IsWindowEnabled(btn[i].hBtn)) ? btn[i].hbrLit : btn[i].hbrDark);
if (! btn[i].pushable) {
@ -565,7 +689,7 @@ HWND CreateSubclassedButton (HWND hwParent, int i)
int r, g, b;
y = bmht - (4*BUTTON_HEIGHT) + BUTTON_HEIGHT * btn[i].y;
x = (btn[i].x < 2) ? (btn[i].x*BUTTON_WIDTH) : (bmwid - (4-btn[i].x)*BUTTON_WIDTH);
x = (btn[i].x < 2) ? (btn[i].x*BUTTON_WIDTH) : (598 - (4-btn[i].x)*BUTTON_WIDTH);
if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW,
x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL)
@ -654,12 +778,16 @@ static DWORD WINAPI Pump (LPVOID arg)
hFont = CreateFont(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial");
if (hBtnFont == NULL)
hBtnFont = CreateFont(-12, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial");
if (hTinyFont == NULL)
hTinyFont = CreateFont(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial");
if (hConsoleWnd == NULL) { /* create window */
if ((hConsoleWnd = CreateWindow(szConsoleClassName, "IBM 1130", WS_OVERLAPPED, 0, 0, 200, 200, NULL, NULL, hInstance, NULL)) == NULL) {
if ((hConsoleWnd = CreateWindow(szConsoleClassName, "IBM 1130", WS_OVERLAPPED|WS_CLIPCHILDREN, 0, 0, 200, 200, NULL, NULL, hInstance, NULL)) == NULL) {
PumpID = 0;
return 0;
}
DragAcceptFiles(hConsoleWnd, TRUE); /* let it accept dragged files (scripts) */
}
GetObject(hBitmap, sizeof(bm), &bm); /* get bitmap size */
@ -667,12 +795,52 @@ static DWORD WINAPI Pump (LPVOID arg)
bmht = bm.bmHeight;
for (i = 0; i < NBUTTONS; i++) {
CreateSubclassedButton(hConsoleWnd, i);
if (! btn[i].subclassed)
continue;
CreateSubclassedButton(hConsoleWnd, i);
if (! btn[i].pushable)
EnableWindow(btn[i].hBtn, btn[i].state);
}
// This isn't needed anymore, now that we have the big printer icon -- it acts like a button now
// i = IDC_TEAR;
// btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,
// btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
//
// SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
hbm1442_full = LoadBitmap(hInstance, "FULL_1442");
hbm1442_empty = LoadBitmap(hInstance, "EMPTY_1442");
hbm1442_eof = LoadBitmap(hInstance, "EOF_1442");
hbm1442_middle = LoadBitmap(hInstance, "MIDDLE_1442");
hbm1132_full = LoadBitmap(hInstance, "FULL_1132");
hbm1132_empty = LoadBitmap(hInstance, "EMPTY_1132");
i = IDC_1442;
btn[i].hBtn = CreateWindow("STATIC", btn[i].txt, WS_CHILD|WS_VISIBLE|SS_BITMAP|SS_SUNKEN|WS_BORDER|SS_REALSIZEIMAGE|SS_NOTIFY,
btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
btn[i].state = STATE_1442_EMPTY;
// wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_full);
wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_empty);
i = IDC_1132;
btn[i].hBtn = CreateWindow("STATIC", btn[i].txt, WS_CHILD|WS_VISIBLE|SS_BITMAP|SS_SUNKEN|WS_BORDER|SS_REALSIZEIMAGE|SS_NOTIFY,
btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
btn[i].state = FALSE;
wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1132_empty);
// for (i = 0; i < NTXTBOXES; i++) {
// txtbox[i].hBox = CreateWindow("EDIT", txtbox[i].txt,
// WS_CHILD|WS_VISIBLE|ES_LEFT|ES_READONLY,
// txtbox[i].x, txtbox[i].y, TXTBOX_WIDTH, TXTBOX_HEIGHT, hConsoleWnd, (HMENU) (i+100), hInstance, NULL);
// SendMessage(txtbox[i].hBox, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
// }
GetWindowRect(hConsoleWnd, &r); /* get window size as created */
wx = r.right - r.left + 1;
wy = r.bottom - r.top + 1;
@ -711,8 +879,9 @@ static DWORD WINAPI Pump (LPVOID arg)
DispatchMessage(&msg);
}
if (hConsoleWnd != NULL) {
DestroyWindow(hConsoleWnd); /* but if a quit message got posted, clean up */
if (hConsoleWnd != NULL) {
DragAcceptFiles(hConsoleWnd, FALSE); /* unregister as drag/drop target */
DestroyWindow(hConsoleWnd); /* but if a quit message got posted, clean up */
hConsoleWnd = NULL;
}
@ -753,11 +922,12 @@ static void DrawBits (HDC hDC, int x, int y, int bits, int nbits, int mask, char
* DrawToggles - display the console sense switches
* ------------------------------------------------------------------------ */
static void DrawToggles (HDC hDC, int bits)
{
int b, x;
for (b = 0x8000, x = 122; b != 0; b >>= 1) {
for (b = 0x8000, x = TOGGLES_X; b != 0; b >>= 1) {
if (shown_ces & b) { /* up */
SelectObject(hDC, hbWhite);
Rectangle(hDC, x, 232, x+9, 240);
@ -789,10 +959,10 @@ void DrawRunmode (HDC hDC, int mode)
ca = cos(angle);
sa = sin(angle);
x0 = 301 + (int) (20.*ca + 0.5); /* inner radius */
y0 = 389 - (int) (20.*sa + 0.5);
x1 = 301 + (int) (25.*ca + 0.5); /* outer radius */
y1 = 389 - (int) (25.*sa + 0.5);
x0 = RUNSWITCH_X + (int) (20.*ca + 0.5); /* inner radius */
y0 = RUNSWITCH_Y - (int) (20.*sa + 0.5);
x1 = RUNSWITCH_X + (int) (25.*ca + 0.5); /* outer radius */
y1 = RUNSWITCH_Y - (int) (25.*sa + 0.5);
hOldPen = SelectObject(hDC, hSwitchPen);
@ -812,7 +982,7 @@ static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual)
{
int b, x, r, ang, i;
for (b = 0x8000, x = 122; b != 0; b >>= 1) {
for (b = 0x8000, x = TOGGLES_X; b != 0; b >>= 1) {
if (BETWEEN(xh, x-3, x+8+3) && BETWEEN(yh, 230, 275)) {
if (actual) {
CES ^= b; /* a hit. Invert the bit and redisplay */
@ -823,9 +993,9 @@ static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual)
x += (b & 0x1111) ? 31 : 21;
}
if (BETWEEN(xh, 245, 355) && BETWEEN(yh, 345, 425)) { /* hit near rotary switch */
ang = (int) (atan2(301.-xh, 389.-yh)*180./3.1415926); /* this does implicit 90 deg rotation by the way */
r = (int) sqrt((xh-301)*(xh-301)+(yh-389)*(yh-389));
if (BETWEEN(xh, RUNSWITCH_X-50, RUNSWITCH_X+50) && BETWEEN(yh, RUNSWITCH_Y-50, RUNSWITCH_Y+50)) { /* hit near rotary switch */
ang = (int) (atan2(RUNSWITCH_X-xh, RUNSWITCH_Y-yh)*180./3.1415926); /* this does implicit 90 deg rotation by the way */
r = (int) sqrt((xh-RUNSWITCH_X)*(xh-RUNSWITCH_X)+(yh-RUNSWITCH_Y)*(yh-RUNSWITCH_Y));
if (r > 12) {
for (i = MODE_LOAD; i <= MODE_INT_RUN; i++) {
if (BETWEEN(ang, i*45-12, i*45+12)) {
@ -852,13 +1022,19 @@ static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual)
* RepaintRegion-> repaint with background redraw. Used for toggles which change position.
* ------------------------------------------------------------------------ */
static void DrawConsole (HDC hDC)
static void DrawConsole (HDC hDC, PAINTSTRUCT *ps)
{
static char digits[] = " 0 1 2 3 4 5 6 7 8 9101112131415";
static char cccs[] = "3216 8 4 2 1";
static char cnds[] = " C V";
static char waits[] = " W";
HFONT hOldFont, hOldBrush;
RECT xout, xin;
int i, n;
DEVICE *dptr;
UNIT *uptr;
t_bool enab;
char nametemp[50], *dispname;
hOldFont = SelectObject(hDC, hFont); /* use that tiny font */
hOldBrush = SelectObject(hDC, hbWhite);
@ -885,6 +1061,47 @@ static void DrawConsole (HDC hDC)
SelectObject(hDC, hOldFont);
SelectObject(hDC, hOldBrush);
SetBkColor(hDC, RGB(0,0,0));
SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+TXTBOX_HEIGHT);
if (IntersectRect(&xout, &xin, &ps->rcPaint)) {
hOldFont = SelectObject(hDC, hTinyFont);
for (i = 0; i < NTXTBOXES; i++) {
enab = FALSE;
dptr = find_unit(txtbox[i].unitname, &uptr);
if (dptr != NULL && uptr != NULL) {
if (uptr->flags & UNIT_DIS) {
SetTextColor(hDC, RGB(128,0,0));
}
else if (uptr->flags & UNIT_ATT) {
SetTextColor(hDC, RGB(0,0,255));
if ((n = strlen(uptr->filename)) > 30) {
strcpy(nametemp, "...");
strcpy(nametemp+3, uptr->filename+n-30);
dispname = nametemp;
}
else
dispname = uptr->filename;
TextOut(hDC, txtbox[i].x+25, txtbox[i].y+TXTBOX_HEIGHT, dispname, strlen(dispname));
SetTextColor(hDC, RGB(255,255,255));
enab = TRUE;
}
else {
SetTextColor(hDC, RGB(128,128,128));
}
TextOut(hDC, txtbox[i].x, txtbox[i].y, txtbox[i].txt, strlen(txtbox[i].txt));
}
if (txtbox[i].idctrl >= 0)
EnableWindow(btn[txtbox[i].idctrl].hBtn, enab);
}
SelectObject(hDC, hOldFont);
}
}
/* ------------------------------------------------------------------------
@ -914,11 +1131,11 @@ void gui_run (int running)
flash_run(); /* keep run lamp active for a while after we stop running */
}
void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam)
void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
{
int i;
switch (wParam) {
switch (idCtl) {
case IDC_POWER: /* toggle system power */
power = ! power;
reset_all(0);
@ -1009,6 +1226,21 @@ void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam)
remark_cmd("IPL failed");
}
break;
case IDC_TEAR: /* "tear off printer output" */
case IDC_1132: /* do same if they click on the printer icon */
if (btn[IDC_1132].state && (wNotify == STN_CLICKED || wNotify == STN_DBLCLK))
tear_printer();
break;
case IDC_1442:
if (btn[IDC_1442].state == STATE_1442_FULL || wNotify == STN_DBLCLK)
stuff_cmd("detach cr");
else if (btn[IDC_1442].state != STATE_1442_EMPTY && wNotify == STN_CLICKED) {
cr_rewind();
update_gui(TRUE);
}
break;
}
update_gui(FALSE);
@ -1050,12 +1282,17 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
DrawConsole(hDC);
DrawConsole(hDC, &ps);
EndPaint(hWnd, &ps);
break;
case WM_COMMAND: /* button click */
HandleCommand(hWnd, wParam, lParam);
case WM_COMMAND: /* button click */
HandleCommand(hWnd, HIWORD(wParam), LOWORD(wParam), (HWND) lParam);
break;
case WM_CTLCOLOREDIT: /* text color for edit controls */
SetBkColor((HDC) wParam, RGB(0,0,0));
SetTextColor((HDC) wParam, RGB(255,255,255));
break;
case WM_DRAWITEM:
@ -1085,6 +1322,10 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
update_gui(FALSE);
break;
case WM_DROPFILES:
accept_dropped_file((HANDLE) wParam); // console window - dragged file is a script or card deck
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
@ -1160,6 +1401,81 @@ void disk_unlocked (int unlocked)
EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked);
}
static void accept_dropped_file (HANDLE hDrop)
{
int nfiles;
char fname[MAX_PATH], cmd[MAX_PATH+50], *deckfile;
BOOL cardreader;
POINT pt;
HWND hWndDrop;
nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // get file count,
DragQueryFile(hDrop, 0, fname, sizeof(fname)); // get first filename
DragQueryPoint(hDrop, &pt); // get location of drop
DragFinish(hDrop);
if (nfiles <= 0) // hmm, this seems unlikely to occur, but better check
return;
if (running) { // can only accept a drop while processor is stopped
MessageBeep(0);
return;
}
if ((hWndDrop = ChildWindowFromPoint(hConsoleWnd, pt)) == btn[IDC_1442].hBtn)
cardreader = TRUE; // file was dropped onto 1442 card reader
else if (hWndDrop == NULL || hWndDrop == hConsoleWnd)
cardreader = FALSE; // file was dropped onto console window, not a button
else {
MessageBeep(0); // file was dropped onto another button
return;
}
if (nfiles > 1) { // oops, we wouldn't know what order to read them in
MessageBox(hConsoleWnd, "You may only drop one file at a time", "", MB_OK);
return;
}
// if shift key is down, prepend @ to name (make it a deck file)
deckfile = ((GetKeyState(VK_SHIFT) & 0x8000) && cardreader) ? "@" : "";
sprintf(cmd, "%s \"%s%s\"", cardreader ? "attach cr" : "do", deckfile, fname);
stuff_cmd(cmd);
}
static void tear_printer (void)
{
char cmd[MAX_PATH+100], filename[MAX_PATH];
if ((prt_unit.flags & UNIT_ATT) == 0)
return;
strcpy(filename, prt_unit.filename); // save current attached filename
if (! stuff_and_wait("detach prt", 1000, 0)) // detach it
return;
sprintf(cmd, "view \"%s\"", filename); // spawn notepad to view it
if (! stuff_and_wait(cmd, 3000, 500))
return;
// no, now we have them click the card reader icon twice to unload the deck. more flexible that way
// if (! stuff_and_wait("detach cr", 1000, 0)) // detach the card reader so they can edit the deck file
// return;
unlink(filename); // delete the file
sprintf(cmd, "attach prt \"%s\"", filename); // reattach
stuff_cmd(cmd);
}
#ifdef XXX
if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW,
x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL)
return NULL;
#endif
CRITICAL_SECTION critsect;
void begin_critical_section (void)
@ -1201,6 +1517,7 @@ static DWORD WINAPI CmdThread (LPVOID arg)
WaitForSingleObject(hCmdReadEvent, INFINITE); /* wait for request */
read_line(cmdbuffer, sizeof(cmdbuffer), stdin); /* read one line */
scp_stuffed = FALSE; /* say how we got it */
scp_reading = FALSE;
SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */
}
return 0;
@ -1225,11 +1542,8 @@ char *read_cmdline (char *ptr, int size, FILE *stream)
SetEvent(hCmdReadEvent); /* let read thread get one line */
WaitForSingleObject(hCmdReadyEvent, INFINITE); /* wait for read thread or GUI to respond */
scp_reading = FALSE;
strncpy(ptr, cmdbuffer, MIN(size, sizeof(cmdbuffer))); /* copy line to caller's buffer */
for (cptr = ptr; isspace(*cptr); cptr++) /* absorb spaces */
;
@ -1247,9 +1561,58 @@ void stuff_cmd (char *cmd)
{
strcpy(cmdbuffer, cmd); /* save the string */
scp_stuffed = TRUE; /* note where it came from */
scp_reading = FALSE;
ResetEvent(hCmdReadEvent); /* clear read request event */
SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */
}
// my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,
// since it sleeps in the GUI thread while scp runs in the main thread. However,
// at the end of every command scp calls update_gui, which can result in messages
// being sent to the GUI thread. So, the GUI thread has to process messages while
// stuff_and_wait is waiting.
static void my_yield (void)
{
MSG msg;
// multitask
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// stuff_and_wait -- stuff a command and wait for the emulator to process the command
// and come back to prompt for another
t_bool stuff_and_wait (char *cmd, int timeout, int delay)
{
scp_reading = FALSE;
stuff_cmd(cmd);
while (! scp_reading) {
if (timeout < 0)
return FALSE;
my_yield();
if (scp_reading)
break;
Sleep(50);
if (timeout)
if ((timeout -= 50) <= 0)
timeout = -1;
my_yield();
}
if (delay)
Sleep(delay);
return TRUE;
}
/* remark_cmd - print a remark from inside a command processor. This routine takes
* into account the possiblity that the command might have been stuffed, in which
* case the sim> prompt needs to be reprinted.
@ -1257,8 +1620,14 @@ void stuff_cmd (char *cmd)
void remark_cmd (char *remark)
{
if (scp_reading) {
putchar('\n');
if (sim_log) putc('\n', sim_log);
}
printf("%s\n", remark);
if (sim_log) fprintf(sim_log, "%s\n", remark);
if (scp_reading) {
printf("sim> ");
if (sim_log) fprintf(sim_log, "sim> ");

View file

@ -4,6 +4,15 @@
Brian Knittel
Revision History
2003.12.02 - Added -p option for physical line printer output (flushes
output buffer after each line). When using a physical printer on
Windows, be sure to set printer to "send output directly to printer"
to disable spooling, otherwise nothing appears until printer is
detatched.
2003.11.25 - Changed magic filename for standard output to "(stdout)".
2002.09.13 - Added 1403 support. New file, taken from part of ibm1130_stddev.c
Note: The 1403 is much faster, even in emulation, because it takes much
@ -88,6 +97,7 @@ static int32 prt_twait = 50; /* transfer wait, for 1403 operations */
#define UNIT_V_PARITYCHECK (UNIT_V_UF + 7) /* error flags for 1403 */
#define UNIT_V_RINGCHECK (UNIT_V_UF + 8)
#define UNIT_V_SYNCCHECK (UNIT_V_UF + 9)
#define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* this appears in ibm1130_gui as well */
#define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK)
#define UNIT_DATACHECK (1u << UNIT_V_DATACHECK)
@ -99,13 +109,15 @@ static int32 prt_twait = 50; /* transfer wait, for 1403 operations */
#define UNIT_PARITYCHECK (1u << UNIT_V_PARITYCHECK)
#define UNIT_RINGCHECK (1u << UNIT_V_RINGCHECK)
#define UNIT_SYNCCHECK (1u << UNIT_V_SYNCCHECK)
#define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
UNIT prt_unit[] = {
{ UDATA (&prt_svc, UNIT_ATTABLE, 0) },
};
#define IS_1403(uptr) (uptr->flags & UNIT_1403) /* model test */
#define IS_1132(uptr) ((uptr->flags & UNIT_1403) == 0) /* model test */
#define IS_1403(uptr) (uptr->flags & UNIT_1403) /* model test */
#define IS_1132(uptr) ((uptr->flags & UNIT_1403) == 0) /* model test */
#define IS_PHYSICAL(uptr) (uptr->flags & UNIT_PHYSICAL_PTR)
/* Parameter in the unit descriptor (1132 printer) */
@ -118,8 +130,8 @@ REG prt_reg[] = {
{ HRDATA (PRTDSW, PRT_DSW, 16) }, /* device status word */
{ DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */
{ DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */
{ DRDATA (CTIME, prt_fwait, 24), PV_LEFT }, /* 1403 fast wait */
{ DRDATA (CTIME, prt_twait, 24), PV_LEFT }, /* 1403 transfer wait */
{ DRDATA (FTIME, prt_fwait, 24), PV_LEFT }, /* 1403 fast wait */
{ DRDATA (TTIME, prt_twait, 24), PV_LEFT }, /* 1403 transfer wait */
{ NULL } };
MTAB prt_mod[] = {
@ -175,6 +187,8 @@ cccgi[] = {
#include "ibm1130_prtwheel.h"
extern int32 sim_switches;
// cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read
static int cc_format_1132 (int bits)
@ -239,7 +253,7 @@ static void newpage (FILE *fd)
putc('\f', fd); // formfeed
}
static void flush_prt_line (FILE *fd, int spacemode)
static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush)
{
int r;
@ -262,6 +276,7 @@ static void flush_prt_line (FILE *fd, int spacemode)
else
prt_nnl++;
prt_unit->pos++; // note something written
return;
}
@ -296,7 +311,11 @@ static void flush_prt_line (FILE *fd, int spacemode)
reset_prt_line();
prt_unit->pos++; // note something written
prt_nnl++; // queue a newline
if (phys_flush) // if physical printer, send buffered output to device
fflush(fd);
}
// 1132 printer commands
@ -412,7 +431,7 @@ static t_stat prt1132_svc (UNIT *uptr)
}
if (uptr->flags & UNIT_SPACING) {
flush_prt_line(uptr->fileref, UNIT_SPACING);
flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY);
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE);
@ -423,7 +442,7 @@ static t_stat prt1132_svc (UNIT *uptr)
if (uptr->flags & UNIT_SKIPPING) {
do {
flush_prt_line(uptr->fileref, UNIT_SKIPPING);
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK);
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]));
} while ((cctape[prt_row] & CC_1132_BITS) == 0); // slew directly to a cc tape punch
@ -569,7 +588,7 @@ static t_stat prt1403_svc(UNIT *uptr)
}
else if (uptr->flags & UNIT_SKIPPING) {
do { // find line with exact match of tape punches
flush_prt_line(uptr->fileref, UNIT_SKIPPING);
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
} while (cctape[prt_row] != SKIPTARGET); // slew directly to requested cc tape punch
CLRBIT(uptr->flags, UNIT_SKIPPING); // done with this
@ -579,7 +598,7 @@ static t_stat prt1403_svc(UNIT *uptr)
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
}
else if (uptr->flags & UNIT_SPACING) {
flush_prt_line(uptr->fileref, UNIT_SPACING);
flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
@ -685,9 +704,14 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
}
}
if (sim_switches & SWMASK('P')) /* set physical (unbuffered) printer flag */
SETBIT(uptr->flags, UNIT_PHYSICAL_PTR);
else
CLRBIT(uptr->flags, UNIT_PHYSICAL_PTR);
sim_cancel(uptr);
if (strcmp(cptr, "-") == 0) { /* connect printer to stdout */
if (strcmp(cptr, "(stdout)") == 0) { /* connect printer to stdout */
if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */
uptr->filename = calloc(CBUFSIZE, sizeof(char));
strcpy(uptr->filename, "(stdout)");
@ -695,11 +719,13 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
SETBIT(uptr->flags, UNIT_ATT);
uptr->pos = 0;
}
else if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) {
return rval;
else {
if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK)
return rval;
}
fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */
fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */
uptr->pos = ftell(uptr->fileref);
if (IS_1132(uptr)) {
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
@ -743,7 +769,7 @@ static t_stat prt_detach (UNIT *uptr)
{
t_stat rval;
flush_prt_line(uptr->fileref, TRUE);
flush_prt_line(uptr->fileref, TRUE, TRUE);
if (uptr->fileref == stdout) {
CLRBIT(uptr->flags, UNIT_ATT);

View file

@ -5,6 +5,10 @@
Brian Knittel
Revision History:
2003.11.23 - Fixed bug in new routine "quotefix" that made sim crash
for all non-Windows builds :(
2003.06.15 - added output translation code to accomodate APL font
added input translation feature to assist emulation of 1130 console keyboard for APL
changes to console input and output IO emulation, fixed bugs exposed by APL interpreter
@ -197,7 +201,7 @@ DEVICE tti_dev = {
"KEYBOARD", &tti_unit, tti_reg, tti_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tti_reset,
NULL, NULL, NULL };
NULL, basic_attach, NULL };
/* TTO data structures
@ -206,7 +210,11 @@ DEVICE tti_dev = {
tto_reg TTO register list
*/
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
// 14-Nov-03 -- the wait time was SERIAL_OUT_WAIT, but recent versions of SIMH reduced
// this to 100, and wouldn't you know it, APL\1130 has about 120 instructions between the XIO WRITE
// to the console and the associated WAIT.
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), 200 };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, 16) },
@ -227,7 +235,7 @@ DEVICE tto_dev = {
"TTO", &tto_unit, tto_reg, tto_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto_reset,
NULL, NULL, NULL };
NULL, basic_attach, NULL };
/* Terminal input routines
@ -270,6 +278,8 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify)
ch = (ReadW(iocc_addr) >> 8) & 0xFF; /* get character to write */
tto_unit.buf = emit_conout_character(ch); /* output character and save write status */
// fprintf(stderr, "[CONOUT] %02x\n", ch);
SETBIT(tto_dsw, TT_DSW_PRINTER_BUSY);
sim_activate(&tto_unit, tto_unit.wait); /* schedule interrupt */
break;
@ -288,6 +298,8 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify)
sprintf(msg, "Invalid console XIO function %x", func);
xio_error(msg);
}
// fprintf(stderr, "After XIO %04x %04x\n", tti_dsw, tto_dsw);
}
// emit_conout_character - write character with 1130 console code 'ch'
@ -345,6 +357,8 @@ static t_stat tti_svc (UNIT *uptr)
/* otherwise, so ^E can interrupt the simulator, */
sim_activate(&tti_unit, tti_unit.wait); /* always continue polling keyboard */
assert(sim_clock_queue != NULL);
temp = sim_poll_kbd();
if (temp < SCPE_KFLAG)
@ -411,6 +425,8 @@ static t_stat tti_svc (UNIT *uptr)
SETBIT(ILSW[4], ILSW_4_CONSOLE);
calc_ints();
// fprintf(stderr, "TTI interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw);
return SCPE_OK;
}
@ -433,6 +449,35 @@ static t_stat tti_reset (DEVICE *dptr)
return SCPE_OK;
}
// basic_attach - fix quotes in filename, then call standard unit attach routine
t_stat basic_attach (UNIT *uptr, char *cptr)
{
return attach_unit(uptr, quotefix(cptr)); /* fix quotes in filenames & attach */
}
// quotefix - strip off quotes around filename, if present
char * quotefix (char * cptr)
{
#ifdef WIN32 /* do this only for Windows builds, for the time being */
char *c;
int quote;
if (*cptr == '"' || *cptr == '\'') {
quote = *cptr++; /* remember quote and skip over it */
for (c = cptr; *c && *c != quote; c++)
; /* find closing quote, or end of string */
if (*c) /* terminate string at closing quote */
*c = '\0';
}
#endif
return cptr; /* return pointer to cleaned-up name */
}
t_bool keyboard_is_busy (void) /* return TRUE if keyboard is not expecting a character */
{
return (tti_dsw & TT_DSW_KEYBOARD_BUSY);
@ -446,6 +491,8 @@ static t_stat tto_svc (UNIT *uptr)
SETBIT(ILSW[4], ILSW_4_CONSOLE);
calc_ints();
// fprintf(stderr, "TTO interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw);
return (t_stat) tto_unit.buf; /* return status saved during output conversion */
}
@ -824,7 +871,10 @@ static t_stat map_conout_character (int ch)
curcol--;
}
else if (n_os_mappings && ch != (unsigned char) IGNR_) {
if (curcol > maxcol) { // first time in this column, no overstrike possible yet
if (curcol >= MAX_OUTPUT_COLUMNS)
map_conout_character('\x81'); // precede with automatic carriage return/line feed, I guess
if (curcol > maxcol) { // first time in this column, no overstrike possible yet
os_buf[curcol].nin = 0;
maxcol = curcol;
}
@ -853,7 +903,7 @@ static t_stat map_conout_character (int ch)
}
}
if (curcol < MAX_OUTPUT_COLUMNS)
if (curcol < MAX_OUTPUT_COLUMNS) // this should now never happen, as we automatically return
curcol++;
}
@ -897,18 +947,15 @@ static t_stat font_cmd (int32 flag, char *cptr)
if (! *cptr) return SCPE_2FARG; /* argument missing */
fname = cptr; /* save start */
while (*cptr && (*cptr > ' ')) {
if (*cptr == '\'' || *cptr == '"') { /* quoted string */
quote = *cptr; /* remember quote character */
strcpy(cptr, cptr+1); /* slide string down over the quote */
if (*cptr == '\'' || *cptr == '"') { /* quoted string */
quote = *cptr++; /* remember quote character */
fname++; /* skip the quote */
while (*cptr && *cptr != quote) /* find closing quote */
cptr++;
if (*cptr == quote) /* if closer was found, slide down over it */
strcpy(cptr, cptr+1);
}
else /* skip over regular character */
while (*cptr && (*cptr != quote)) /* find closing quote */
cptr++;
}
else {
while (*cptr && (*cptr > ' ')) /* find terminating blank */
cptr++;
}
*cptr = '\0'; /* terminate name */

View file

@ -46,7 +46,6 @@ extern int32 saved_PC;
*/
char sim_name[] = "IBM 1130";
char sim_version[] = "V0.30";
REG *sim_PC = &cpu_reg[0];

View file

@ -2,9 +2,8 @@
// Microsoft Visual C++ generated include file.
// Used by ibm1130.rc
//
#define IDB_CONSOLE 101
#define IDC_HAND 102
#define IDC_HAND 102
// Next default values for new objects
//

View file

@ -1,74 +0,0 @@
# (This makefile is for operating systems other than Windows,
# or compilers other than Microsoft's. For MS builds, use the
# .mak files found in this directory and the utils directory).
#
# If you are building the emulator and utilities as part of
# the SIMH package, please:
#
# Be sure that you there are NO copies of scp.c, scp_tty.c,
# sim_sock.c, sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and
# sim_tmxr.h in the ibm1130 subdirectory. Delete them if there
# are.
#
# Do not use this makefile with "make all" or "make ibm1130".
# Use the SIMH build files instead.
#
# If and when you download updates for this simulator from
# www.ibm1130.org, get ibm1130code.zip and ibm1130software.zip
# separately.
#
# If you have downloaded the emulator independently of SIMH (e.g, from
# www.ibm1130.org), please:
#
# Be sure that you DO have copies of scp.c, scp_tty.c, sim_sock.c,
# sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and sim_tmxr.h
# in this folder.
#
# Use this file to make the emulator.
#
# If and when you download updates for this simulator from
# www.ibm1130.org, get ibm1130.zip. When you expand it,
# also expand ibm1130sofware.zip, which is inside.
#
# In either case, if you want to build DMS or work with assembly
# language programs outside of DMS, you'll want to make the utilities
# by cd'ing to the utils directory and running make there.
# CC Command
#
# Note: -O2 is sometimes broken in GCC when setjump/longjump is being
# used. Try -O2 only with released simulators.
#
CC = gcc -O0 -lm -I .
#CC = gcc -O2 -g -lm -I .
#
# Common Libraries
#
BIN =
SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c
SIM_INC = sim_defs.h sim_rev.h sim_sock.h sim_tmxr.h
#
# Emulator source files and compile time options
#
ibm1130D = ./
ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \
${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \
${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.c \
${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c \
${ibm1130D}ibm1130_fmt.c
ibm1130_INC = ibm1130res.h ibm1130_conin.h ibm1130_conout.h \
ibm1130_defs.h ibm1130_prtwheel.h ibm1130_fmt.h \
dmsr2v12phases.h dmsr2v12slet.h
#
# Build the emulator
#
${BIN}ibm1130 : ${ibm1130} ${SIM} ${ibm1130_INC} ${SIM_INC}
${CC} ${ibm1130} ${SIM} -o $@

View file

@ -2,6 +2,18 @@ Version: 10 July 2003
History (partial):
2003-11-15 Changed default value of TTO STIME to 200. It was
defined using a constant from sim_defs.h which was
changed from 10 to 100 at some point. APL\1130 has a
sychronization bug & hangs if the console output complete
interrupt occurs between the XIO SENSE and WAIT instructions.
This bug is hit frequently if the delay time is set to
100 instructions. 10 worked reliably, but is really not realistic,
and 200 may not be adequate in all cases, but we'll try 200 for now.
2003-11-00 Updated GUI to allow drag and drop to simulated card
reader, tear-off from simulated printer
2003-07-10 Fixed disk and console terminal bugs uncovered by
APL\1130. Added APL keyboard and output font support
to enable use of APL\1130. APL will be released soon.

File diff suppressed because it is too large Load diff

View file

@ -1,161 +0,0 @@
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=Win32 Debug
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
!ENDIF
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "asm1130.mak" CFG="Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "Win32 Debug"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "WinRel"
# PROP BASE Intermediate_Dir "WinRel"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "WinRel"
# PROP Intermediate_Dir "WinRel"
OUTDIR=.\WinRel
INTDIR=.\WinRel
ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/ /c
CPP_OBJS=.\WinRel/
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc"
BSC32_SBRS= \
$(INTDIR)/asm1130.sbr
$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
/INCREMENTAL:no /PDB:$(OUTDIR)/"asm1130.pdb" /MACHINE:I386\
/OUT:$(OUTDIR)/"asm1130.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/asm1130.obj
$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "WinDebug"
# PROP BASE Intermediate_Dir "WinDebug"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "WinDebug"
# PROP Intermediate_Dir "WinDebug"
OUTDIR=.\WinDebug
INTDIR=.\WinDebug
ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/\
/Fd$(OUTDIR)/"asm1130.pdb" /c
CPP_OBJS=.\WinDebug/
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc"
BSC32_SBRS= \
$(INTDIR)/asm1130.sbr
$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
/INCREMENTAL:yes /PDB:$(OUTDIR)/"asm1130.pdb" /DEBUG /MACHINE:I386\
/OUT:$(OUTDIR)/"asm1130.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/asm1130.obj
$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Group "Source Files"
################################################################################
# Begin Source File
SOURCE=.\asm1130.c
$(INTDIR)/asm1130.obj : $(SOURCE) $(INTDIR)
# End Source File
# End Group
# End Project
################################################################################

View file

@ -1,752 +0,0 @@
/*
* (C) Copyright 2002, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
*/
// ---------------------------------------------------------------------------------
// BINDUMP - dumps card deck files in assembler object format
//
// Usage:
/// bindump deckfile lists object header info & sector break cards
// bindump -v deckfile lists object data records as well
// bindump -p deckfile for system program, lists phase IDs in the deck
// bindump -s deckfile >outfile for system program, sorts the phases & writes to stdout
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
# include <windows.h>
# include <io.h>
# include <fcntl.h>
#endif
#ifndef TRUE
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif
typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC;
BOOL verbose = FALSE;
BOOL phid = FALSE;
BOOL sort = FALSE;
unsigned short card[80], buf[54], cardtype;
// bindump - dump a binary (card format) deck to verify sbrks, etc
void bail (char *msg);
void dump (char *fname);
void dump_data (char *fname);
void dump_phids (char *fname);
char *getname (unsigned short *ptr);
char *getseq (void);
int hollerith_to_ascii (unsigned short h);
void process (char *fname);
void show_raw (char *name);
void show_data (void);
void show_core (void);
void show_endc (void);
void show_81 (void);
void show_main (void);
void show_sub (void);
void show_ils (void);
void show_iss (void);
void show_end (void);
void sort_phases (char *fname);
void trim (char *s);
void unpack (unsigned short *card, unsigned short *buf);
void verify_checksum(unsigned short *buf);
int main (int argc, char **argv)
{
char *arg;
static char usestr[] = "Usage: bindump [-psv] filename...";
int i;
for (i = 1; i < argc; i++) {
arg = argv[i];
if (*arg == '-') {
arg++;
while (*arg) {
switch (*arg++) {
case 'v':
verbose = TRUE;
break;
case 'p':
phid = TRUE; // print only phase ID's
break;
case 's':
sort = TRUE; // sort deck by phases, writing to stdout
break;
default:
bail(usestr);
}
}
}
}
for (i = 1; i < argc; i++) {
arg = argv[i];
if (*arg != '-')
process(arg);
}
return 0;
}
void process (char *nm)
{
#ifdef WIN32
WIN32_FIND_DATA fd;
HANDLE hFind;
char *c, buf[256];
if (strchr(nm, '*') == NULL && strchr(nm, '?') == NULL)
dump(nm);
else if ((hFind = FindFirstFile(nm, &fd)) == INVALID_HANDLE_VALUE)
fprintf(stderr, "No files matching '%s'\n", nm);
else {
if ((c = strrchr(nm, '\\')) == NULL)
c = strrchr(nm, ':');
do {
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
if (c == NULL)
dump(fd.cFileName);
else {
strcpy(buf, nm);
strcpy(buf + (c-nm+1), fd.cFileName);
dump(buf);
}
} while (FindNextFile(hFind, &fd));
FindClose(hFind);
}
#else
dump(nm); // on unices, sh globs for us
#endif
}
void dump (char *fname)
{
if (sort)
sort_phases(fname);
else if (phid)
dump_phids(fname);
else
dump_data(fname);
}
struct tag_card {
int phid, seq;
unsigned short card[80];
};
int cardcomp (const void *a, const void *b)
{
short diff;
diff = ((struct tag_card *) a)->phid - ((struct tag_card *) b)->phid;
return diff ? diff : (((struct tag_card *) a)->seq - ((struct tag_card *) b)->seq);
}
void sort_phases (char *fname)
{
int i, ncards, cardtype, len, seq = 0, phid;
struct tag_card *deck;
FILE *fd;
BOOL saw_sbrk = TRUE;
if ((fd = fopen(fname, "rb")) == NULL) {
perror(fname);
return;
}
fseek(fd, 0, SEEK_END);
len = ftell(fd); // get length of file
fseek(fd, 0, SEEK_SET);
if (len <= 0 || (len % 160) != 0) {
fprintf(stderr, "%s is not a binard deck image\n");
fclose(fd);
return;
}
ncards = len / 160;
if ((deck = (struct tag_card *) malloc(ncards*sizeof(struct tag_card))) == NULL) {
fprintf(stderr, "%s: can't sort, insufficient memory\n");
fclose(fd);
return;
}
phid = 0;
for (i = 0; i < ncards; i++) {
if (fread(deck[i].card, sizeof(card[0]), 80, fd) != 80) {
free(deck);
fprintf(stderr, "%s: error reading deck\n");
fclose(fd);
return;
}
unpack(deck[i].card, buf);
deck[i].seq = seq++;
deck[i].phid = phid;
verify_checksum(buf);
cardtype = (buf[2] >> 8) & 0xFF;
if (cardtype == 1 || cardtype == 2) { // start of deck is same as sector break
saw_sbrk = TRUE;
}
else if (cardtype == 0) {
fprintf(stderr, "%s is a core image deck\n");
free(deck);
fclose(fd);
return;
}
else if (cardtype == 0x0A && saw_sbrk) {
phid = (int) (signed short) buf[10];
if (phid < 0)
phid = -phid;
deck[i].phid = phid; // this belongs to the new phase
deck[i-1].phid = phid; // as does previous card
saw_sbrk = FALSE;
}
}
fclose(fd);
qsort(deck, ncards, sizeof(struct tag_card), cardcomp); // sort the deck
#ifdef WIN32
_setmode(_fileno(stdout), _O_BINARY); // set standard output to binary mode
#endif
for (i = 0; i < ncards; i++) // write to stdout
fwrite(deck[i].card, sizeof(card[0]), 80, stdout);
free(deck);
}
void dump_phids (char *fname)
{
FILE *fp;
BOOL first = TRUE;
BOOL saw_sbrk = TRUE, neg;
short id;
if ((fp = fopen(fname, "rb")) == NULL) {
perror(fname);
return;
}
printf("\n%s:\n", fname);
while (fread(card, sizeof(card[0]), 80, fp) > 0) {
unpack(card, buf);
verify_checksum(buf);
cardtype = (buf[2] >> 8) & 0xFF;
if (cardtype == 1 && ! first) { // sector break
saw_sbrk = TRUE;
continue;
}
else {
switch (cardtype) {
case 0x00:
printf(" This is a core image deck\n");
goto done;
break;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x0F:
break;
case 0x0A:
if (saw_sbrk) {
id = buf[10];
if (id < 0)
id = -id, neg = TRUE;
else
neg = FALSE;
printf(" : %3d / %02x%s\n", id, id, neg ? " (neg)" : "");
saw_sbrk = FALSE;
}
break;
default:
show_raw("??? ");
}
}
done:
first = FALSE;
}
fclose(fp);
}
void dump_data (char *fname)
{
FILE *fp;
BOOL first = TRUE;
char str[80];
int i;
if ((fp = fopen(fname, "rb")) == NULL) {
perror(fname);
return;
}
printf("\n%s:\n", fname);
while (fread(card, sizeof(card[0]), 80, fp) > 0) {
unpack(card, buf);
verify_checksum(buf);
cardtype = (buf[2] >> 8) & 0xFF;
if (cardtype == 1 && ! first) { // sector break
for (i = 4; i < 72; i++)
str[i] = hollerith_to_ascii(card[i]);
str[i] = '\0';
trim(str+4);
printf("*SBRK %s\n", str+4);
continue;
}
else {
switch (cardtype) {
case 0x00:
if (first)
show_raw("CORE");
if (verbose)
show_core();
break;
case 0x01:
show_raw("ABS ");
show_main();
break;
case 0x02:
show_raw("REL ");
show_main();
break;
case 0x03:
show_raw("LIB ");
show_sub();
break;
case 0x04:
show_raw("SUB ");
show_sub();
break;
case 0x05:
show_raw("ISSL");
show_iss();
break;
case 0x06:
show_raw("ISSC");
show_iss();
break;
case 0x07:
show_raw("ILS ");
show_ils();
break;
case 0x0F:
show_raw("END ");
show_end();
break;
case 0x80:
show_raw("ENDC");
show_endc();
break;
case 0x81:
show_raw("81 ");
show_81();
break;
case 0x0A:
if (verbose)
show_data();
break;
default:
show_raw("??? ");
}
}
first = FALSE;
}
fclose(fp);
}
void show_data (void)
{
int i, n, jrel, rflag, nout, ch, reloc;
BOOL first = TRUE;
n = buf[2] & 0x00FF;
printf("%04x: ", buf[0]);
jrel = 3;
nout = 0;
rflag = buf[jrel++];
for (i = 0; i < n; i++) {
if (nout >= 8) {
rflag = buf[jrel++];
if (first) {
printf(" %s", getseq());
first = FALSE;
}
printf("\n ");
nout = 0;
}
reloc = (rflag >> 14) & 0x03;
ch = (reloc == R_ABSOLUTE) ? ' ' :
(reloc == R_RELATIVE) ? 'R' :
(reloc == R_LIBF) ? 'L' : '@';
printf("%04x%c ", buf[9+i], ch);
rflag <<= 2;
nout++;
}
putchar('\n');
}
void show_core (void)
{
int i, n, nout;
BOOL first = TRUE;
n = buf[2] & 0x00FF;
printf("%04x: ", buf[0]);
nout = 0;
for (i = 0; i < n; i++) {
if (nout >= 8) {
if (first) {
printf(" %s", getseq());
first = FALSE;
}
printf("\n ");
nout = 0;
}
printf("%04x ", buf[9+i]);
nout++;
}
putchar('\n');
}
void info (int i, char *nm, char type)
{
if (nm)
printf("%s ", nm);
switch (type) {
case 'd':
printf("%d ", buf[i]);
break;
case 'x':
printf("%04x ", buf[i]);
break;
case 'b':
printf("%02x ", buf[i] & 0xFF);
break;
case 'n':
printf("%s ", getname(buf+i));
break;
default:
bail("BAD TYPE");
}
}
void show_main (void)
{
printf(" ");
info(2, "prec", 'b');
info(4, "common", 'd');
info(6, "work", 'd');
info(8, "files", 'd');
info(9, "name", 'n');
info(11, "pta", 'x');
putchar('\n');
}
void show_sub (void)
{
int i, n;
printf(" ");
info( 2, "prec", 'b');
n = buf[5] / 3;
for (i = 0; i < n; i++) {
info( 9+3*i, "ent", 'n');
info(11+3*i, NULL, 'x');
}
putchar('\n');
}
void show_iss (void)
{
printf(" ");
info(12, "level", 'd');
putchar('\n');
}
void show_ils (void)
{
printf(" ");
info( 2, "prec", 'b');
info( 5, "nint6", 'd');
info( 9, "ent", 'n');
info(11, NULL, 'x');
info(14, "nint", 'd');
info(15, "il1", 'd');
info(16, "il2", 'd');
putchar('\n');
}
void show_end (void)
{
printf(" ");
info(0, "size", 'd');
info(3, "pta", 'x');
putchar('\n');
}
void show_endc(void)
{
printf(" ");
info(52, "IX3", 'x');
info(53, "pta", 'x');
putchar('\n');
}
void show_81(void)
{
}
void show_raw (char *name)
{
int i;
printf("*%s", name);
for (i = 0; i < 12; i++)
printf(" %04x", buf[i]);
printf(" %s\n", getseq());
}
char * getseq (void)
{
static char seq[10];
int i;
for (i = 0; i < 8; i++)
seq[i] = hollerith_to_ascii(card[72+i]);
seq[i] = '\0';
return seq;
}
void bail (char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
void unpack (unsigned short *icard, unsigned short *obuf)
{
int i, j;
unsigned short wd1, wd2, wd3, wd4;
for (i = j = 0; i < 54; i += 3, j += 4) {
wd1 = icard[j];
wd2 = icard[j+1];
wd3 = icard[j+2];
wd4 = icard[j+3];
obuf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F);
obuf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF);
obuf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF);
}
}
void verify_checksum (unsigned short *obuf)
{
// unsigned short sum;
if (obuf[1] == 0) // no checksum
return;
// if (sum != card[1])
// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]);
}
typedef struct {
unsigned short hollerith;
char ascii;
} CPCODE;
static CPCODE cardcode_029[] =
{
0x0000, ' ',
0x8000, '&', // + in 026 Fortran
0x4000, '-',
0x2000, '0',
0x1000, '1',
0x0800, '2',
0x0400, '3',
0x0200, '4',
0x0100, '5',
0x0080, '6',
0x0040, '7',
0x0020, '8',
0x0010, '9',
0x9000, 'A',
0x8800, 'B',
0x8400, 'C',
0x8200, 'D',
0x8100, 'E',
0x8080, 'F',
0x8040, 'G',
0x8020, 'H',
0x8010, 'I',
0x5000, 'J',
0x4800, 'K',
0x4400, 'L',
0x4200, 'M',
0x4100, 'N',
0x4080, 'O',
0x4040, 'P',
0x4020, 'Q',
0x4010, 'R',
0x3000, '/',
0x2800, 'S',
0x2400, 'T',
0x2200, 'U',
0x2100, 'V',
0x2080, 'W',
0x2040, 'X',
0x2020, 'Y',
0x2010, 'Z',
0x0820, ':',
0x0420, '#', // = in 026 Fortran
0x0220, '@', // ' in 026 Fortran
0x0120, '\'',
0x00A0, '=',
0x0060, '"',
0x8820, 'c', // cent
0x8420, '.',
0x8220, '<', // ) in 026 Fortran
0x8120, '(',
0x80A0, '+',
0x8060, '|',
0x4820, '!',
0x4420, '$',
0x4220, '*',
0x4120, ')',
0x40A0, ';',
0x4060, 'n', // not
0x2820, 'x', // what?
0x2420, ',',
0x2220, '%', // ( in 026 Fortran
0x2120, '_',
0x20A0, '>',
0x2060, '>',
};
int hollerith_to_ascii (unsigned short h)
{
int i;
h &= 0xFFF0;
for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++)
if (cardcode_029[i].hollerith == h)
return cardcode_029[i].ascii;
return '?';
}
// ---------------------------------------------------------------------------------
// trim - remove trailing whitespace from string s
// ---------------------------------------------------------------------------------
void trim (char *s)
{
char *nb;
for (nb = s-1; *s; s++)
if (*s > ' ')
nb = s;
nb[1] = '\0';
}
int ascii_to_ebcdic_table[128] =
{
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d,
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
};
char *getname (unsigned short *ptr)
{
static char str[6];
int i, j, ch;
long v;
v = (ptr[0] << 16L) | ptr[1];
for (i = 0; i < 5; i++) {
ch = ((v >> 24) & 0x3F) | 0xC0; // recover those lost two bits
v <<= 6;
str[i] = ' ';
for (j = 0; j < (sizeof(ascii_to_ebcdic_table)/sizeof(ascii_to_ebcdic_table[0])); j++) {
if (ascii_to_ebcdic_table[j] == ch) {
str[i] = j;
break;
}
}
}
str[5] = '\0';
return str;
}

View file

@ -1,161 +0,0 @@
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=Win32 Debug
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
!ENDIF
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "bindump.mak" CFG="Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "Win32 Debug"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "WinRel"
# PROP BASE Intermediate_Dir "WinRel"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "WinRel"
# PROP Intermediate_Dir "WinRel"
OUTDIR=.\WinRel
INTDIR=.\WinRel
ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/ /c
CPP_OBJS=.\WinRel/
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc"
BSC32_SBRS= \
$(INTDIR)/bindump.sbr
$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
/NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"bindump.pdb"\
/MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/bindump.obj
$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "WinDebug"
# PROP BASE Intermediate_Dir "WinDebug"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "WinDebug"
# PROP Intermediate_Dir "WinDebug"
OUTDIR=.\WinDebug
INTDIR=.\WinDebug
ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/\
/Fd$(OUTDIR)/"bindump.pdb" /c
CPP_OBJS=.\WinDebug/
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc"
BSC32_SBRS= \
$(INTDIR)/bindump.sbr
$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
/NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"bindump.pdb" /DEBUG\
/MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/bindump.obj
$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Group "Source Files"
################################################################################
# Begin Source File
SOURCE=.\bindump.c
$(INTDIR)/bindump.obj : $(SOURCE) $(INTDIR)
# End Source File
# End Group
# End Project
################################################################################

View file

@ -1,264 +0,0 @@
/*
* (C) Copyright 2002, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
*/
// checkdisk - validates and optionally dumps an IBM1130 DMS2 disk image file
//
// Usage:
// checkdisk [-f] [-d cyl.sec|abssec] [-n count] filename
//
// Examples:
// checkdisk file.dsk
// report any misnumbered sectors in file.dsk
//
// checkdisk -f file.dsk
// report and fix any misnumbered sectors
//
// checkdisk -d 198.0 file.dsk
// dump cylinder 198 sector 0
//
// checkdisk -d 0 file.dsk
// dump absolute sector 0
//
// checkdisk -d 198.0 -n 4 file.dsk
// dump 4 sectors starting at m.n
// -----------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util_io.h"
#ifdef WIN32
# include <io.h>
#else
long filelength (int fno);
# include <sys/types.h>
# include <sys/stat.h>
#endif
#ifndef TRUE
# define BOOL int
# define TRUE 1
# define FALSE 0
#endif
#define DSK_NUMWD 321 /* words/sector */
#define DSK_NUMSC 4 /* sectors/surface */
#define DSK_NUMSF 2 /* surfaces/cylinder */
#define DSK_NUMCY 203 /* cylinders/drive */
#define DSK_NUMDR 5 /* drives/controller */
#define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */
char *usestr = "Usage: checkdisk [-f] [-d cyl.sec|abssec] [-n count] diskfile";
char *baddisk = "Cannot fix this";
void bail (char *msg);
char *lowcase (char *str);
int main (int argc, char **argv)
{
FILE *fp;
char *fname = NULL, *arg, *argval;
int i, j, cyl, sec, pos, asec, retry, nbad = 0, nfixed = 0, nline;
BOOL fixit = FALSE, dump = FALSE;
int dsec, nsec = 1;
unsigned short wd, buf[DSK_NUMWD];
util_io_init();
for (i = 1; i < argc;) {
arg = argv[i++];
if (*arg == '-') {
arg++;
lowcase(arg);
while (*arg) {
switch (*arg++) {
case 'f':
fixit = TRUE;
break;
case 'd':
dump = TRUE;
if (i >= argc)
bail(usestr);
argval = argv[i++];
if (strchr(argval, '.') != NULL) {
if (sscanf(argval, "%d.%d", &cyl, &sec) != 2)
bail(usestr);
dsec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec;
}
else if (sscanf(argval, "%d", &dsec) != 1)
bail(usestr);
if (dsec < 0 || dsec >= (DSK_NUMCY*DSK_NUMSF*DSK_NUMSC))
bail("No such sector");
break;
case 'n':
if (i >= argc)
bail(usestr);
argval = argv[i++];
if (sscanf(argval, "%d", &nsec) != 1)
bail(usestr);
if (nsec <= 0)
bail(usestr);
break;
default:
bail(usestr);
}
}
}
else if (fname == NULL)
fname = arg;
else
bail(usestr);
}
if (fname == NULL)
bail(usestr);
if ((fp = fopen(fname, "rb+")) == NULL) {
perror(fname);
return 1;
}
if (filelength(fileno(fp)) != 2*DSK_SIZE) {
fprintf(stderr, "File is wrong length, expected %d\n", DSK_SIZE);
bail(baddisk);
}
for (cyl = 0; cyl < DSK_NUMCY; cyl++) {
for (sec = 0; sec < (DSK_NUMSF*DSK_NUMSC); sec++) {
retry = 1;
again:
asec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec;
pos = asec*2*DSK_NUMWD;
if (fseek(fp, pos, SEEK_SET) != 0) {
fprintf(stderr, "Error seeking to pos %x\n", pos);
bail(baddisk);
}
if (fxread(&wd, sizeof(wd), 1, fp) != 1) {
fprintf(stderr, "Error reading word at abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos);
bail(baddisk);
}
if (wd != asec) {
fprintf(stderr, "Bad sector #%x at abs sec %x, cyl %x, sec %x at offset %x\n", wd, asec, cyl, sec, pos);
nbad++;
if (fixit) {
if (fseek(fp, pos, SEEK_SET) != 0) {
fprintf(stderr, "Error seeking to pos %x\n", pos);
bail(baddisk);
}
if (fxwrite(&asec, sizeof(wd), 1, fp) != 1) {
fprintf(stderr, "Error writing sector # to abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos);
bail(baddisk);
}
if (retry) {
retry = 0;
nfixed++;
goto again;
}
fprintf(stderr, "Failed after retry\n");
bail(baddisk);
}
}
}
}
if (nbad)
printf("%d bad sector mark%s %s\n", nbad, (nbad == 1) ? "" : "s", fixit ? "fixed" : "found");
else if (! dump)
printf("All sector marks OK\n");
if (! dump)
return 0;
pos = dsec*2*DSK_NUMWD;
if (fseek(fp, pos, SEEK_SET) != 0) {
fprintf(stderr, "Error seeking to pos %x\n", pos);
bail(baddisk);
}
for (i = 0; i < nsec; i++) {
cyl = dsec / (DSK_NUMSF*DSK_NUMSC);
sec = dsec - cyl*(DSK_NUMSF*DSK_NUMSC);
if (fxread(&buf, sizeof(buf[0]), DSK_NUMWD, fp) != DSK_NUMWD) {
fprintf(stderr, "Error reading abs sec %x, cyl %x, sec %x at offset %x\n", dsec, cyl, sec, pos);
bail(baddisk);
}
printf("\nSector %d.%d - %d - /%04x label %04x\n", cyl, sec, dsec, dsec, buf[0]);
for (nline = 0, j = 1; j < DSK_NUMWD; j++) {
printf("%04x", buf[j]);
if (++nline == 16) {
putchar('\n');
nline = 0;
}
else
putchar(' ');
}
dsec++;
}
return 0;
}
void bail (char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
/* ------------------------------------------------------------------------
* lowcase - force a string to lower case (ASCII)
* ------------------------------------------------------------------------ */
char *lowcase (char *str)
{
char *s;
for (s = str; *s; s++) {
if (*s >= 'A' && *s <= 'Z')
*s += 32;
}
return str;
}
#ifndef WIN32
long filelength (int fno)
{
struct stat sb;
if (fstat(fno, &sb) != 0)
return 0;
return (long) sb.st_size;
}
#endif

View file

@ -1,177 +0,0 @@
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=Win32 Debug
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
!ENDIF
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "checkdisk.mak" CFG="Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "Win32 Release"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "WinRel"
# PROP BASE Intermediate_Dir "WinRel"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "WinRel"
# PROP Intermediate_Dir "WinRel"
OUTDIR=.\WinRel
INTDIR=.\WinRel
ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/ /c
CPP_OBJS=.\WinRel/
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc"
BSC32_SBRS= \
$(INTDIR)/checkdisk.sbr \
$(INTDIR)/util_io.sbr
$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\
/SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"checkdisk.pdb" /MACHINE:I386\
/OUT:$(OUTDIR)/"checkdisk.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/checkdisk.obj \
$(INTDIR)/util_io.obj
$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "WinDebug"
# PROP BASE Intermediate_Dir "WinDebug"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "WinDebug"
# PROP Intermediate_Dir "WinDebug"
OUTDIR=.\WinDebug
INTDIR=.\WinDebug
ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/\
/Fd$(OUTDIR)/"checkdisk.pdb" /c
CPP_OBJS=.\WinDebug/
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc"
BSC32_SBRS= \
$(INTDIR)/checkdisk.sbr \
$(INTDIR)/util_io.sbr
$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\
/SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"checkdisk.pdb" /DEBUG\
/MACHINE:I386 /OUT:$(OUTDIR)/"checkdisk.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/checkdisk.obj \
$(INTDIR)/util_io.obj
$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Group "Source Files"
################################################################################
# Begin Source File
SOURCE=.\checkdisk.c
DEP_CHECK=\
.\util_io.h\
\MSVC20\INCLUDE\sys\types.h\
\MSVC20\INCLUDE\sys\stat.h
$(INTDIR)/checkdisk.obj : $(SOURCE) $(DEP_CHECK) $(INTDIR)
# End Source File
################################################################################
# Begin Source File
SOURCE=.\util_io.c
$(INTDIR)/util_io.obj : $(SOURCE) $(INTDIR)
# End Source File
# End Group
# End Project
################################################################################

View file

@ -1,614 +0,0 @@
/*
* (C) Copyright 2002, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
*/
// DISKVIEW - lists contents of an 1130 system disk image file. Not finished yet.
// needs LET/SLET listing routine.
//
// usage:
// diskview -v diskfile
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "util_io.h"
#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b)))
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
#ifndef TRUE
# define TRUE 1
# define FALSE 0
# define BOOL int
#endif
#define NOT_DEF 0x0658 // defective cylinder table entry means no defect
#define DSK_NUMWD 321 /* words/sector */
#define DSK_NUMCY 203 /* cylinders/drive */
#define DSK_SECCYL 8 /* sectors per cylinder */
#define SECLEN 320 /* data words per sector */
#define SLETLEN ((3*SECLEN)/4) /* length of slet in records */
typedef unsigned short WORD;
FILE *fp;
WORD buf[DSK_NUMWD];
WORD dcom[DSK_NUMWD];
#pragma pack(2)
struct tag_slet {
WORD phid;
WORD addr;
WORD nwords;
WORD sector;
} slet[SLETLEN];
#pragma pack()
WORD dcyl[3];
BOOL verbose = FALSE;
void checksectors (void);
void dump_id (void);
void dump_dcom (void);
void dump_resmon (void);
void dump_slet (void);
void dump_hdng (void);
void dump_scra (void);
void dump_let (void);
void dump_flet (void);
void dump_cib (void);
void getsector (int sec, WORD *sbuf);
void getdcyl (void);
char *lowcase (char *str);
void bail(char *fmt, ...);
char *trim (char *s);
int main (int argc, char **argv)
{
char *fname = NULL, *arg;
static char usestr[] = "Usage: diskview [-v] filename";
int i;
util_io_init();
for (i = 1; i < argc;) {
arg = argv[i++];
if (*arg == '-') {
arg++;
lowcase(arg);
while (*arg) {
switch (*arg++) {
case 'v':
verbose = TRUE;
break;
default:
bail(usestr);
}
}
}
else if (fname == NULL)
fname = arg;
else
bail(usestr);
}
if (fname == NULL)
bail(usestr);
if ((fp = fopen(fname, "rb")) == NULL) {
perror(fname);
return 2;
}
printf("%s:\n", fname);
checksectors();
getdcyl();
dump_id(); // ID & coldstart
dump_dcom(); // DCOM
dump_resmon(); // resident image
dump_slet(); // SLET
dump_hdng(); // heading sector
dump_scra();
dump_flet();
dump_cib();
dump_let();
fclose(fp);
return 0;
}
// checksectors - verify that all sectors are properly numbered
void checksectors ()
{
WORD sec = 0;
fseek(fp, 0, SEEK_SET);
for (sec = 0; sec < DSK_NUMCY*DSK_SECCYL; sec++) {
if (fxread(buf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD)
bail("File read error or not a disk image file");
if (buf[0] != sec)
bail("Sector /%x is misnumbered, run checkdisk [-f]", sec);
}
}
// get defective cylinder list
void getdcyl (void)
{
fseek(fp, sizeof(WORD), SEEK_SET); // skip sector count
if (fxread(dcyl, sizeof(WORD), 3, fp) != 3)
bail("Unable to read defective cylinder table");
}
// getsector - read specified absolute sector
void getsector (int sec, WORD *sbuf)
{
int i, cyl, ssec;
sec &= 0x7FF; // mask of drive bits, if any
cyl = sec / DSK_SECCYL; // get cylinder
ssec = sec & ~(DSK_SECCYL-1); // mask to get starting sector of cylinder
for (i = 0; i < 3; i++) { // map through defective cylinder table
if (dcyl[i] == ssec) {
sec &= (DSK_SECCYL-1); // mask to get base sector
cyl = DSK_NUMCY-3+i; // replacements are last three on disk
sec += cyl*DSK_SECCYL; // add new cylinder offset
break;
}
}
// read the sector
if (fseek(fp, (sec*DSK_NUMWD+1)*sizeof(WORD), SEEK_SET) != 0)
bail("File seek failed");
if (fxread(sbuf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD)
bail("File read error or not a disk image file");
}
void dump (int nwords)
{
int i, nline = 0;
for (i = 0; i < nwords; i++) {
if (nline == 16) {
putchar('\n');
nline = 0;
}
printf("%04x", buf[i]);
nline++;
}
putchar('\n');
}
void showmajor (char *label)
{
int i;
printf("\n--- %s ", label);
for (i = strlen(label); i < 40; i++)
putchar('-');
putchar('\n');
putchar('\n');
}
void name (char *label)
{
printf("%-32.32s ", label);
}
void pbf (char *label, WORD *buf, int nwords)
{
int i, nout;
name(label);
for (i = nout = 0; i < nwords; i++, nout++) {
if (nout == 8) {
putchar('\n');
name("");
nout = 0;
}
printf(" %04x", buf[i]);
}
putchar('\n');
}
void prt (char *label, char *fmt, ...)
{
va_list args;
name(label);
putchar(' ');
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
putchar('\n');
}
void dump_id (void)
{
showmajor("Sector 0 - ID & coldstart");
getsector(0, buf);
pbf("DCYL def cyl table", buf+ 0, 3);
pbf("CIDN cart id", buf+ 3, 1);
pbf(" copy code", buf+ 4, 1);
pbf("DTYP disk type", buf+ 7, 1);
pbf(" diskz copy", buf+ 30, 8);
pbf(" cold start pgm",buf+270, 8);
}
// EQUIVALENCES FOR DCOM PARAMETERS
#define NAME 4 // NAME OF PROGRAM/CORE LOAD
#define DBCT 6 // BLOCK CT OF PROGRAM/CORE LOAD
#define FCNT 7 // FILES SWITCH
#define SYSC 8 // SYSTEM/NON-SYSTEM CARTRIDGE INDR
#define JBSW 9 // JOBT SWITCH
#define CBSW 10 // CLB-RETURN SWITCH
#define LCNT 11 // NO. OF LOCALS
#define MPSW 12 // CORE MAP SWITCH
#define MDF1 13 // NO. DUP CTRL RECORDS (MODIF)
#define MDF2 14 // ADDR OF MODIF BUFFER
#define NCNT 15 // NO. OF NOCALS
#define ENTY 16 // RLTV ENTRY ADDR OF PROGRAM
#define RP67 17 // 1442-5 SWITCH
#define TODR 18 // OBJECT WORK STORAGE DRIVE CODE
#define FHOL 20 // ADDR LARGEST HOLE IN FIXED AREA
#define FSZE 21 // BLK CNT LARGEST HOLE IN FXA
#define UHOL 22 // ADDR LAST HOLE IN USER AREA 2-10
#define USZE 23 // BLK CNT LAST HOLE IN UA 2-10
#define DCSW 24 // DUP CALL SWITCH
#define PIOD 25 // PRINCIPAL I/O DEVICE INDICATOR
#define PPTR 26 // PRINCIPAL PRINT DEVICE INDICATOR
#define CIAD 27 // RLTV ADDR IN @STRT OF CIL ADDR
#define ACIN 28 // AVAILABLE CARTRIDGE INDICATOR
#define GRPH 29 // 2250 INDICATOR 2G2
#define GCNT 30 // NO. G2250 RECORDS 2G2
#define LOSW 31 // LOCAL-CALLS-LOCAL SWITCH 2-2
#define X3SW 32 // SPECIAL ILS SWITCH 2-2
#define ECNT 33 // NO. OF *EQUAT RCDS 2-4
#define ANDU 35 // 1+BLK ADDR END OF UA (ADJUSTED)
#define BNDU 40 // 1+BLK ADDR END OF UA (BASE)
#define FPAD 45 // FILE PROTECT ADDR
#define PCID 50 // CARTRIDGE ID, PHYSICAL DRIVE
#define CIDN 55 // CARTRIDGE ID, LOGICAL DRIVE
#define CIBA 60 // SCTR ADDR OF CIB
#define SCRA 65 // SCTR ADDR OF SCRA
#define FMAT 70 // FORMAT OF PROG IN WORKING STG
#define FLET 75 // SCTR ADDR 1ST SCTR OF FLET
#define ULET 80 // SCTR ADDR 1ST SCTR OF LET
#define WSCT 85 // BLK CNT OF PROG IN WORKING STG
#define CSHN 90 // NO. SCTRS IN CUSHION AREA
struct tag_dcominfo {
char *nm;
int offset;
char *descr;
} dcominfo[] = {
"NAME", 4, "NAME OF PROGRAM/CORE LOAD",
"DBCT", 6, "BLOCK CT OF PROGRAM/CORE LOAD",
"FCNT", 7, "FILES SWITCH",
"SYSC", 8, "SYSTEM/NON-SYSTEM CARTRIDGE INDR",
"JBSW", 9, "JOBT SWITCH",
"CBSW", 10, "CLB-RETURN SWITCH",
"LCNT", 11, "NO. OF LOCALS",
"MPSW", 12, "CORE MAP SWITCH",
"MDF1", 13, "NO. DUP CTRL RECORDS (MODIF)",
"MDF2", 14, "ADDR OF MODIF BUFFER",
"NCNT", 15, "NO. OF NOCALS",
"ENTY", 16, "RLTV ENTRY ADDR OF PROGRAM",
"RP67", 17, "1442-5 SWITCH",
"TODR", 18, "OBJECT WORK STORAGE DRIVE CODE",
"FHOL", 20, "ADDR LARGEST HOLE IN FIXED AREA",
"FSZE", 21, "BLK CNT LARGEST HOLE IN FXA",
"UHOL", 22, "ADDR LAST HOLE IN USER AREA",
"USZE", 23, "BLK CNT LAST HOLE IN UA",
"DCSW", 24, "DUP CALL SWITCH",
"PIOD", 25, "PRINCIPAL I/O DEVICE INDICATOR",
"PPTR", 26, "PRINCIPAL PRINT DEVICE INDICATOR",
"CIAD", 27, "RLTV ADDR IN @STRT OF CIL ADDR",
"ACIN", 28, "AVAILABLE CARTRIDGE INDICATOR",
"GRPH", 29, "2250 INDICATOR",
"GCNT", 30, "NO. G2250 RECORDS",
"LOSW", 31, "LOCAL-CALLS-LOCAL SWITCH",
"X3SW", 32, "SPECIAL ILS SWITCH",
"ECNT", 33, "NO. OF *EQUAT RCDS",
"ANDU", 35, "1+BLK ADDR END OF UA (ADJUSTED)",
"BNDU", 40, "1+BLK ADDR END OF UA (BASE)",
"FPAD", 45, "FILE PROTECT ADDR",
"PCID", 50, "CARTRIDGE ID, PHYSICAL DRIVE",
"CIDN", 55, "CARTRIDGE ID, LOGICAL DRIVE",
"CIBA", 60, "SCTR ADDR OF CIB",
"SCRA", 65, "SCTR ADDR OF SCRA",
"FMAT", 70, "FORMAT OF PROG IN WORKING STG",
"FLET", 75, "SCTR ADDR 1ST SCTR OF FLET",
"ULET", 80, "SCTR ADDR 1ST SCTR OF LET",
"WSCT", 85, "BLK CNT OF PROG IN WORKING STG",
"CSHN", 90, "NO. SCTRS IN CUSHION AREA",
NULL
};
void dump_dcom (void)
{
struct tag_dcominfo *d;
char txt[50];
showmajor("Sector 1 - DCOM");
getsector(1, dcom);
for (d = dcominfo; d->nm != NULL; d++) {
sprintf(txt, "%-4.4s %s", d->nm, d->descr);
pbf(txt, dcom+d->offset, 1);
}
}
void dump_resmon (void)
{
showmajor("Sector 2 - Resident Image");
getsector(2, buf);
dump(verbose ? SECLEN : 32);
}
struct {
int pfrom, pto;
int printed;
char *name;
} sletinfo[] = {
0x01, 0x12, FALSE, "DUP",
0x1F, 0x39, FALSE, "Fortran",
0x51, 0x5C, FALSE, "Cobol",
0x6E, 0x74, FALSE, "Supervisor",
0x78, 0x84, FALSE, "Core Load Builder",
0x8C, 0x8C, FALSE, "Sys 1403 prt",
0x8D, 0x8D, FALSE, "Sys 1132 prt",
0x8E, 0x8E, FALSE, "Sys console prt",
0x8F, 0x8F, FALSE, "Sys 2501 rdr",
0x90, 0x90, FALSE, "Sys 1442 rdr/pun",
0x91, 0x91, FALSE, "Sys 1134 paper tape",
0x92, 0x92, FALSE, "Sys kbd",
0x93, 0x93, FALSE, "Sys 2501/1442 conv",
0x94, 0x94, FALSE, "Sys 1134 conv",
0x95, 0x95, FALSE, "Sys kbd conv",
0x96, 0x96, FALSE, "Sys diskz",
0x97, 0x97, FALSE, "Sys disk1",
0x98, 0x98, FALSE, "Sys diskn",
0x99, 0x99, FALSE, "(primary print)",
0x9A, 0x9A, FALSE, "(primary input)",
0x9B, 0x9B, FALSE, "(primary input excl kbd)",
0x9C, 0x9C, FALSE, "(primary sys conv)",
0x9D, 0x9D, FALSE, "(primary conv excl kbd)",
0xA0, 0xA1, FALSE, "Core Image Loader",
0xB0, 0xCC, FALSE, "RPG",
0xCD, 0xCE, FALSE, "Dup Part 2",
0xCF, 0xF6, FALSE, "Macro Assembler",
0
};
void dump_slet (void)
{
int i, j, iphase, nsecs, sec, max_sec = 0;
char sstr[16], *smark;
showmajor("Sectors 3-5 - SLET");
for (i = 0; i < 3; i++) {
getsector(3+i, buf);
memmove(((WORD *) slet)+SECLEN*i, buf, SECLEN*sizeof(WORD));
}
printf("# PHID Addr Len Sector Secs\n");
printf("------------------------------------------\n");
for (i = 0; i < SLETLEN; i++) {
if (slet[i].phid == 0)
break;
sec = slet[i].sector;
iphase = (int) (signed short) slet[i].phid;
nsecs = (slet[i].nwords + SECLEN-1)/SECLEN;
if (sec & 0xF800) {
smark = "*";
sec &= 0x7FF;
}
else
smark = " ";
for (j = 0; sletinfo[j].pfrom != 0; j++)
if (sletinfo[j].pfrom <= iphase && sletinfo[j].pto >= iphase)
break;
sprintf(sstr, "(%d.%d)", sec / DSK_SECCYL, slet[i].sector % DSK_SECCYL);
printf("%3d %04x %4d %04x %04x %04x %s %-7s %3x",
i, slet[i].phid, iphase, slet[i].addr, slet[i].nwords, slet[i].sector, smark, sstr, nsecs);
if (iphase < 0)
iphase = -iphase;
if (sletinfo[j].pfrom == 0)
printf(" ???");
else if (! sletinfo[j].printed) {
printf(" %s", sletinfo[j].name);
sletinfo[j].printed = TRUE;
}
for (j = 0; j < i; j++) {
if (sec == (slet[j].sector & 0x7FF)) {
printf(" (same as %04x)", slet[j].phid);
break;
}
}
max_sec = MAX(max_sec, sec+nsecs-1); // find last sector used
putchar('\n');
if (i >= 15 && ! verbose) {
printf("...\n");
break;
}
}
}
int ascii_to_ebcdic_table[128] =
{
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d,
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
};
int ebcdic_to_ascii (int ch)
{
int j;
for (j = 32; j < 128; j++)
if (ascii_to_ebcdic_table[j] == ch)
return j;
return '?';
}
#define HDR_LEN 120
void dump_hdng(void)
{
int i;
char str[HDR_LEN+1], *p = str;
showmajor("Sector 7 - Heading");
getsector(7, buf);
for (i = 0; i < (HDR_LEN/2); i++) {
*p++ = ebcdic_to_ascii((buf[i] >> 8) & 0xFF);
*p++ = ebcdic_to_ascii( buf[i] & 0xFF);
}
*p = '\0';
trim(str);
printf("%s\n", str);
}
BOOL mget (int offset, char *name)
{
char title[80];
if (dcom[offset] == 0)
return FALSE;
getsector(dcom[offset], buf);
sprintf(title, "Sector %x - %s", dcom[offset], name);
showmajor(title);
return TRUE;
}
void dump_scra (void)
{
if (! mget(SCRA, "SCRA"))
return;
dump(verbose ? SECLEN : 32);
}
void dump_let (void)
{
if (! mget(ULET, "LET"))
return;
}
void dump_flet (void)
{
if (! mget(FLET, "FLET"))
return;
}
void dump_cib (void)
{
if (! mget(CIBA, "CIB"))
return;
dump(verbose ? SECLEN : 32);
}
#define LFHD 5 // WORD COUNT OF LET/FLET HEADER PMN09970
#define LFEN 3 // NO OF WDS PER LET/FLET ENTRY PMN09980
#define SCTN 0 // RLTY ADDR OF LET/FLET SCTR NO. PMN09990
#define UAFX 1 // RLTV ADDR OF SCTR ADDR OF UA/FXA PMN10000
#define WDSA 3 // RLTV ADDR OF WDS AVAIL IN SCTR PMN10010
#define NEXT 4 // RLTV ADDR OF ADDR NEXT SCTR PMN10020
#define LFNM 0 // RLTV ADDR OF LET/FLET ENTRY NAME PMN10030
#define BLCT 2 // RLTV ADDR OF LET/FLET ENTRY DBCT PMN10040
void bail (char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, fmt, args);
va_end(args);
putchar('\n');
exit(1);
}
// ---------------------------------------------------------------------------------
// trim - remove trailing whitespace from string s
// ---------------------------------------------------------------------------------
char *trim (char *s)
{
char *os = s, *nb;
for (nb = s-1; *s; s++)
if (*s > ' ')
nb = s;
nb[1] = '\0';
return os;
}
/* ------------------------------------------------------------------------
* lowcase - force a string to lowercase (ASCII)
* ------------------------------------------------------------------------ */
char *lowcase (char *str)
{
char *s;
for (s = str; *s; s++) {
if (*s >= 'A' && *s <= 'Z')
*s += 32;
}
return str;
}

View file

@ -1,175 +0,0 @@
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=Win32 Debug
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
!ENDIF
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "diskview.mak" CFG="Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "Win32 Debug"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "WinRel"
# PROP BASE Intermediate_Dir "WinRel"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "WinRel"
# PROP Intermediate_Dir "WinRel"
OUTDIR=.\WinRel
INTDIR=.\WinRel
ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/ /c
CPP_OBJS=.\WinRel/
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc"
BSC32_SBRS= \
$(INTDIR)/diskview.sbr \
$(INTDIR)/util_io.sbr
$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
/INCREMENTAL:no /PDB:$(OUTDIR)/"diskview.pdb" /MACHINE:I386\
/OUT:$(OUTDIR)/"diskview.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/diskview.obj \
$(INTDIR)/util_io.obj
$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "WinDebug"
# PROP BASE Intermediate_Dir "WinDebug"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "WinDebug"
# PROP Intermediate_Dir "WinDebug"
OUTDIR=.\WinDebug
INTDIR=.\WinDebug
ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/\
/Fd$(OUTDIR)/"diskview.pdb" /c
CPP_OBJS=.\WinDebug/
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc"
BSC32_SBRS= \
$(INTDIR)/diskview.sbr \
$(INTDIR)/util_io.sbr
$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
/INCREMENTAL:yes /PDB:$(OUTDIR)/"diskview.pdb" /DEBUG /MACHINE:I386\
/OUT:$(OUTDIR)/"diskview.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/diskview.obj \
$(INTDIR)/util_io.obj
$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Group "Source Files"
################################################################################
# Begin Source File
SOURCE=.\diskview.c
$(INTDIR)/diskview.obj : $(SOURCE) $(INTDIR)
# End Source File
################################################################################
# Begin Source File
SOURCE=.\util_io.c
DEP_UTIL_=\
.\util_io.h
$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR)
# End Source File
# End Group
# End Project
################################################################################

View file

@ -1,705 +0,0 @@
/*
* (C) Copyright 2002, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
*/
// ---------------------------------------------------------------------------------
// MKBOOT - reads card loader format cards and produces an absolute core image that
// can then be dumped out in 1130 IPL, 1800 IPL or Core Image loader formats.
//
// Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]"
//
// Arguments:
// binfile - name of assembler output file (card loader format, absolute output)
// outfile - name of output file to create
// mode - output mode, default is 1130 IPL format
// loaddr - low address to dump. Default is lowest address loaded from binfile
// hiaddr - high address to dump. Defult is highest address loaded from binfile
// ident - ident string to write in last 8 columns. Omit when when writing an
// 1130 IPL card that requires all 80 columns of data.
//
// Examples:
// mkboot somefile.bin somefile.ipl 1130
//
// loads somefile.bin, writes object in 1130 IPL format to somefile.ipl
// Up to 80 columns will be written depending on what the object actually uses
//
// mkboot somefile.bin somefile.ipl 1130 0 48 SOMEF
//
// loads somefile.bin. Writes 72 columns (hex 48), with ident columns 73-80 = SOMEF001
//
// mkboot somefile.bin somefile.dat core 0 0 SOMEF001
//
// loads somefile.bin and writes a core image format deck with ident SOMEF001, SOMEF002, etc
//
// For other examples of usage, see MKDMS.BAT
//
// 1.00 - 2002Apr18 - first release. Tested only under Win32. The core image
// loader format is almost certainly wrong. Cannot handle
// relocatable input decks, but it works well enough to
// load DSYSLDR1 which is what we are after here.
// ---------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef TRUE
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif
#ifndef WIN32
int strnicmp (char *a, char *b, int n);
int strcmpi (char *a, char *b);
#endif
#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b)))
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
#define MAXADDR 4096
typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC;
typedef enum {B_1130, B_1800, B_CORE} BOOTMODE;
BOOL verbose = FALSE;
char *infile = NULL, *outfile = NULL;
BOOTMODE mode = B_1130;
int addr_from = 0, addr_to = 79;
int outcols = 0; // columns written in using card output
int maxiplcols = 80;
char cardid[9]; // characters used for IPL card ID
int pta = 0;
int load_low = 0x7FFFFFF;
int load_high = 0;
unsigned short mem[MAXADDR]; // small core!
// mkboot - load a binary object deck into core and dump requested bytes as a boot card
void bail (char *msg);
void verify_checksum(unsigned short *card);
char *upcase (char *str);
void unpack (unsigned short *card, unsigned short *buf);
void dump (char *fname);
void loaddata (char *fname);
void write_1130 (void);
void write_1800 (void);
void write_core (void);
void flushcard(void);
int ascii_to_hollerith (int ch);
void corecard_init (void);
void corecard_writecard (char *sbrk_text);
void corecard_writedata (void);
void corecard_flush (void);
void corecard_setorg (int neworg);
void corecard_writew (int word, RELOC relative);
void corecard_endcard (void);
char *fname = NULL;
FILE *fout;
int main (int argc, char **argv)
{
char *arg;
static char usestr[] = "Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]";
int i, ano = 0, ok;
for (i = 1; i < argc; i++) {
arg = argv[i];
if (*arg == '-') {
arg++;
while (*arg) {
switch (*arg++) {
case 'v':
verbose = TRUE;
break;
default:
bail(usestr);
}
}
}
else {
switch (ano++) {
case 0:
infile = arg;
break;
case 1:
outfile = arg;
break;
case 2:
if (strcmp(arg, "1130") == 0) mode = B_1130;
else if (strcmp(arg, "1800") == 0) mode = B_1800;
else if (strcmpi(arg, "core") == 0) mode = B_CORE;
else bail(usestr);
break;
case 3:
if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_from);
else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_from);
else ok = sscanf(arg, "%d", &addr_from);
if (ok != 1) bail(usestr);
break;
case 4:
if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_to);
else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_to);
else ok = sscanf(arg, "%d", &addr_to);
if (ok != 1) bail(usestr);
break;
case 5:
strncpy(cardid, arg, 9);
cardid[8] = '\0';
upcase(cardid);
break;
default:
bail(usestr);
}
}
}
if (*cardid == '\0')
maxiplcols = (mode == B_1130) ? 80 : 72;
else {
while (strlen(cardid) < 8)
strcat(cardid, "0");
maxiplcols = 72;
}
loaddata(infile);
if (mode == B_1800)
write_1800();
else if (mode == B_CORE)
write_core();
else
write_1130();
return 0;
}
void write_1130 (void)
{
int addr;
unsigned short word;
if ((fout = fopen(outfile, "wb")) == NULL) {
perror(outfile);
exit(1);
}
for (addr = addr_from; addr <= addr_to; addr++) {
if (outcols >= maxiplcols)
flushcard();
word = mem[addr];
// if F or L bits are set, or if high 2 bits of displacement are unequal, it's bad
if ((word & 0x0700) || ! (((word & 0x00C0) == 0) || ((word & 0x00C0) == 0x00C0)))
printf("Warning: word %04x @ %04x may not IPL properly\n", word & 0xFFFF, addr);
word = ((word & 0xF800) >> 4) | (word & 0x7F); // convert to 1130 IPL format
putc((word & 0x000F) << 4, fout); // write the 12 bits in little-endian binary AABBCC00 as CC00 AABB
putc((word & 0x0FF0) >> 4, fout);
outcols++;
}
flushcard();
fclose(fout);
}
void write_1800 (void)
{
int addr;
unsigned short word;
if ((fout = fopen(outfile, "wb")) == NULL) {
perror(outfile);
exit(1);
}
for (addr = addr_from; addr <= addr_to; addr++) {
word = mem[addr];
if (outcols >= maxiplcols)
flushcard();
putc(0, fout);
putc(word & 0xFF, fout); // write the low 8 bits in little-endian binary
outcols++;
putc(0, fout);
putc((word >> 8) & 0xFF, fout); // write the high 8 bits in little-endian binary
outcols++;
}
flushcard();
fclose(fout);
}
void write_core (void)
{
int addr;
if ((fout = fopen(outfile, "wb")) == NULL) {
perror(outfile);
exit(1);
}
addr_from = load_low;
addr_to = load_high;
maxiplcols = 72;
corecard_init();
corecard_setorg(addr_from);
for (addr = addr_from; addr <= addr_to; addr++) {
corecard_writew(mem[addr], 0);
}
corecard_flush();
corecard_endcard();
fclose(fout);
}
void flushcard (void)
{
int i, hol, ndig;
char fmt[20], newdig[20];
if (outcols <= 0)
return; // nothing to flush
while (outcols < maxiplcols) { // pad to required number of columns with blanks (no punches)
putc(0, fout);
putc(0, fout);
outcols++;
}
if (*cardid) { // add label
for (i = 0; i < 8; i++) { // write label as specified
hol = ascii_to_hollerith(cardid[i] & 0x7F);
putc(hol & 0xFF, fout);
putc((hol >> 8) & 0xFF, fout);
}
ndig = 0; // count trailing digits in the label
for (i = 8; --i >= 0; ndig++)
if (! isdigit(cardid[i]))
break;
i++; // index of first digit in trailing sequence
if (ndig > 0) { // if any, increment them
sprintf(fmt, "%%0%dd", ndig); // make, e.g. %03d
sprintf(newdig, fmt, atoi(cardid+i)+1);
newdig[ndig] = '\0'; // clip if necessary
strcpy(cardid+i, newdig); // replace for next card's sequence number
}
}
outcols = 0;
}
void show_data (unsigned short *buf)
{
int i, n, jrel, rflag, nout, ch, reloc;
n = buf[2] & 0x00FF;
printf("%04x: ", buf[0]);
jrel = 3;
nout = 0;
rflag = buf[jrel++];
for (i = 0; i < n; i++) {
if (nout >= 8) {
rflag = buf[jrel++];
putchar('\n');
printf(" ");
nout = 0;
}
reloc = (rflag >> 14) & 0x03;
ch = (reloc == R_ABSOLUTE) ? ' ' :
(reloc == R_RELATIVE) ? 'R' :
(reloc == R_LIBF) ? 'L' : '@';
printf("%04x%c ", buf[9+i], ch);
rflag <<= 2;
nout++;
}
putchar('\n');
}
void loadcard (unsigned short *buf)
{
int addr, n, i;
addr = buf[0];
n = buf[2] & 0x00FF;
for (i = 0; i < n; i++) {
if (addr >= MAXADDR)
bail("Program doesn't fit into 4K");
mem[addr] = buf[9+i];
load_low = MIN(addr, load_low);
load_high = MAX(addr, load_high);
addr++;
}
}
void loaddata (char *fname)
{
FILE *fp;
BOOL first = TRUE;
unsigned short card[80], buf[54], cardtype;
if ((fp = fopen(fname, "rb")) == NULL) {
perror(fname);
exit(1);
}
if (verbose)
printf("\n%s:\n", fname);
while (fread(card, sizeof(card[0]), 80, fp) > 0) {
unpack(card, buf);
verify_checksum(card);
cardtype = (buf[2] >> 8) & 0xFF;
if (cardtype == 1 && ! first) { // sector break
if (verbose)
printf("*SBRK\n");
continue;
}
else {
switch (cardtype) {
case 0x01:
if (verbose)
printf("*ABS\n");
break;
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
bail("Data must be in absolute format");
break;
case 0x0F:
pta = buf[3]; // save program transfer address
if (verbose)
printf("*END\n");
break;
case 0x0A:
if (verbose)
show_data(buf);
loadcard(buf);
break;
default:
bail("Unexpected card type");
}
}
first = FALSE;
}
fclose(fp);
}
void bail (char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
void unpack (unsigned short *card, unsigned short *buf)
{
int i, j;
unsigned short wd1, wd2, wd3, wd4;
for (i = j = 0; i < 54; i += 3, j += 4) {
wd1 = card[j];
wd2 = card[j+1];
wd3 = card[j+2];
wd4 = card[j+3];
buf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F);
buf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF);
buf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF);
}
}
void verify_checksum (unsigned short *card)
{
// unsigned short sum;
if (card[1] == 0) // no checksum
return;
// if (sum != card[1])
// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]);
}
typedef struct {
int hollerith;
char ascii;
} CPCODE;
static CPCODE cardcode_029[] =
{
0x0000, ' ',
0x8000, '&', // + in 026 Fortran
0x4000, '-',
0x2000, '0',
0x1000, '1',
0x0800, '2',
0x0400, '3',
0x0200, '4',
0x0100, '5',
0x0080, '6',
0x0040, '7',
0x0020, '8',
0x0010, '9',
0x9000, 'A',
0x8800, 'B',
0x8400, 'C',
0x8200, 'D',
0x8100, 'E',
0x8080, 'F',
0x8040, 'G',
0x8020, 'H',
0x8010, 'I',
0x5000, 'J',
0x4800, 'K',
0x4400, 'L',
0x4200, 'M',
0x4100, 'N',
0x4080, 'O',
0x4040, 'P',
0x4020, 'Q',
0x4010, 'R',
0x3000, '/',
0x2800, 'S',
0x2400, 'T',
0x2200, 'U',
0x2100, 'V',
0x2080, 'W',
0x2040, 'X',
0x2020, 'Y',
0x2010, 'Z',
0x0820, ':',
0x0420, '#', // = in 026 Fortran
0x0220, '@', // ' in 026 Fortran
0x0120, '\'',
0x00A0, '=',
0x0060, '"',
0x8820, 'c', // cent
0x8420, '.',
0x8220, '<', // ) in 026 Fortran
0x8120, '(',
0x80A0, '+',
0x8060, '|',
0x4820, '!',
0x4420, '$',
0x4220, '*',
0x4120, ')',
0x40A0, ';',
0x4060, 'n', // not
0x2820, 'x', // what?
0x2420, ',',
0x2220, '%', // ( in 026 Fortran
0x2120, '_',
0x20A0, '>',
0x2060, '>',
};
int ascii_to_hollerith (int ch)
{
int i;
for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++)
if (cardcode_029[i].ascii == ch)
return cardcode_029[i].hollerith;
return 0;
}
// ---------------------------------------------------------------------------------
// corecard - routines to write IBM 1130 Card object format
// ---------------------------------------------------------------------------------
unsigned short corecard[54]; // the 54 data words that can fit on a binary format card
int corecard_n = 0; // number of object words stored in corecard (0-45)
int corecard_seq = 1; // card output sequence number
int corecard_org = 0; // origin of current card-full
int corecard_maxaddr = 0;
BOOL corecard_first = TRUE; // TRUE when we're to write the program type card
// corecard_init - prepare a new object data output card
void corecard_init (void)
{
memset(corecard, 0, sizeof(corecard)); // clear card data
corecard_n = 0; // no data
corecard[0] = corecard_org; // store load address
corecard_maxaddr = MAX(corecard_maxaddr, corecard_org-1); // save highest address written-to (this may be a BSS)
}
// binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card
void corecard_writecard (char *sbrk_text)
{
unsigned short binout[80];
int i, j;
for (i = j = 0; i < 54; i += 3, j += 4) {
binout[j ] = ( corecard[i] & 0xFFF0);
binout[j+1] = ((corecard[i] << 12) & 0xF000) | ((corecard[i+1] >> 4) & 0x0FF0);
binout[j+2] = ((corecard[i+1] << 8) & 0xFF00) | ((corecard[i+2] >> 8) & 0x00F0);
binout[j+3] = ((corecard[i+2] << 4) & 0xFFF0);
}
for (i = 0; i < 72; i++) {
putc(binout[i] & 0xFF, fout);
putc((binout[i] >> 8) & 0xFF, fout);
}
outcols = 72; // add the ident
flushcard();
}
// binard_writedata - emit an object data card
void corecard_writedata (void)
{
corecard[1] = 0; // checksum
corecard[2] = 0x0000 | corecard_n; // data card type + word count
corecard_writecard(FALSE); // emit the card
}
// corecard_flush - flush any pending binary data
void corecard_flush (void)
{
if (corecard_n > 0)
corecard_writedata();
corecard_init();
}
// corecard_setorg - set the origin
void corecard_setorg (int neworg)
{
corecard_org = neworg; // set origin for next card
corecard_flush(); // flush any current data & store origin
}
// corecard_writew - write a word to the current output card.
void corecard_writew (int word, RELOC relative)
{
if (corecard_n >= 50) // flush full card buffer (must be even)
corecard_flush();
corecard[3+corecard_n++] = word;
corecard_org++;
}
// corecard_endcard - write end of program card
void corecard_endcard (void)
{
corecard_flush();
corecard[0] = 0; // effective length: add 1 to max origin, then 1 more to round up
corecard[1] = 0;
corecard[2] = 0x8000; // they look for negative bit but all else must be zero
corecard[52] = 0xabcd; // index register 3 value, this is for fun
corecard[53] = pta; // hmmm
corecard_writecard(NULL);
}
/* ------------------------------------------------------------------------
* upcase - force a string to uppercase (ASCII)
* ------------------------------------------------------------------------ */
char *upcase (char *str)
{
char *s;
for (s = str; *s; s++) {
if (*s >= 'a' && *s <= 'z')
*s -= 32;
}
return str;
}
#ifndef WIN32
int strnicmp (char *a, char *b, int n)
{
int ca, cb;
for (;;) {
if (--n < 0) // still equal after n characters? quit now
return 0;
if ((ca = *a) == 0) // get character, stop on null terminator
return *b ? -1 : 0;
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
ca -= 32;
cb = *b;
if (cb >= 'a' && cb <= 'z')
cb -= 32;
if ((ca -= cb) != 0) // if different, return comparison
return ca;
a++, b++;
}
}
int strcmpi (char *a, char *b)
{
int ca, cb;
for (;;) {
if ((ca = *a) == 0) // get character, stop on null terminator
return *b ? -1 : 0;
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
ca -= 32;
cb = *b;
if (cb >= 'a' && cb <= 'z')
cb -= 32;
if ((ca -= cb) != 0) // if different, return comparison
return ca;
a++, b++;
}
}
#endif

View file

@ -1,161 +0,0 @@
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=Win32 Debug
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
!ENDIF
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "mkboot.mak" CFG="Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "Win32 Debug"
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "WinRel"
# PROP BASE Intermediate_Dir "WinRel"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "WinRel"
# PROP Intermediate_Dir "WinRel"
OUTDIR=.\WinRel
INTDIR=.\WinRel
ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /c
CPP_OBJS=.\WinRel/
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc"
BSC32_SBRS= \
$(INTDIR)/mkboot.sbr
$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
/INCREMENTAL:no /PDB:$(OUTDIR)/"mkboot.pdb" /MACHINE:I386\
/OUT:$(OUTDIR)/"mkboot.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/mkboot.obj
$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "WinDebug"
# PROP BASE Intermediate_Dir "WinDebug"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "WinDebug"
# PROP Intermediate_Dir "WinDebug"
OUTDIR=.\WinDebug
INTDIR=.\WinDebug
ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"mkboot.pdb"\
/c
CPP_OBJS=.\WinDebug/
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc"
BSC32_SBRS= \
$(INTDIR)/mkboot.sbr
$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
/INCREMENTAL:yes /PDB:$(OUTDIR)/"mkboot.pdb" /DEBUG /MACHINE:I386\
/OUT:$(OUTDIR)/"mkboot.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/mkboot.obj
$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Group "Source Files"
################################################################################
# Begin Source File
SOURCE=.\mkboot.c
$(INTDIR)/mkboot.obj : $(SOURCE) $(INTDIR)
# End Source File
# End Group
# End Project
################################################################################

View file

@ -1,242 +0,0 @@
/* Simple program to display a binary card-image file in ASCII.
* We assume the deck was written with one card per 16-bit word, left-justified,
* and written in PC little-endian order
*
* (C) Copyright 2002, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to sim@ibm1130.org
*/
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef int BOOL;
int hollerith_to_ascii (unsigned short h);
void bail (char *msg);
void format_coldstart (unsigned short *buf);
int main (int argc, char **argv)
{
FILE *fd;
char *fname = NULL, line[82], *arg;
BOOL coldstart = FALSE;
unsigned short buf[80];
int i, lastnb;
static char usestr[] =
"Usage: viewdeck [-c] deckfile\n"
"\n"
"-c: convert cold start card to 16-bit format as a C array initializer\n";
for (i = 1; i < argc; i++) { // process command line arguments
arg = argv[i];
if (*arg == '-') {
arg++;
while (*arg) {
switch (*arg++) {
case 'c':
coldstart = TRUE;
break;
default:
bail(usestr);
}
}
}
else if (fname == NULL) // first non-switch arg is file name
fname = arg;
else
bail(usestr); // there can be only one name
}
if (fname == NULL) // there must be a name
bail(usestr);
if ((fd = fopen(fname, "rb")) == NULL) {
perror(fname);
return 1;
}
while (fread(buf, sizeof(short), 80, fd) == 80) {
if (coldstart) {
format_coldstart(buf);
break;
}
lastnb = -1;
for (i = 0; i < 80; i++) {
line[i] = hollerith_to_ascii(buf[i]);
if (line[i] > ' ')
lastnb = i;
}
line[++lastnb] = '\n';
line[++lastnb] = '\0';
fputs(line, stdout);
}
if (coldstart) {
if (fread(buf, sizeof(short), 1, fd) == 1)
bail("Coldstart deck has more than one card");
}
fclose(fd);
return 0;
}
void format_coldstart (unsigned short *buf)
{
int i, nout = 0;
unsigned short word;
for (i = 0; i < 80; i++) {
word = buf[i]; // expand 12-bit card data to 16-bit instruction
word = (word & 0xF800) | ((word & 0x0400) ? 0x00C0 : 0x0000) | ((word & 0x03F0) >> 4);
if (nout >= 8) {
fputs(",\n", stdout);
nout = 0;
}
else if (i > 0)
fputs(", ", stdout);
printf("0x%04x", word);
nout++;
}
putchar('\n');
}
typedef struct {
unsigned short hollerith;
char ascii;
} CPCODE;
static CPCODE cardcode_029[] =
{
0x0000, ' ',
0x8000, '&', // + in 026 Fortran
0x4000, '-',
0x2000, '0',
0x1000, '1',
0x0800, '2',
0x0400, '3',
0x0200, '4',
0x0100, '5',
0x0080, '6',
0x0040, '7',
0x0020, '8',
0x0010, '9',
0x9000, 'A',
0x8800, 'B',
0x8400, 'C',
0x8200, 'D',
0x8100, 'E',
0x8080, 'F',
0x8040, 'G',
0x8020, 'H',
0x8010, 'I',
0x5000, 'J',
0x4800, 'K',
0x4400, 'L',
0x4200, 'M',
0x4100, 'N',
0x4080, 'O',
0x4040, 'P',
0x4020, 'Q',
0x4010, 'R',
0x3000, '/',
0x2800, 'S',
0x2400, 'T',
0x2200, 'U',
0x2100, 'V',
0x2080, 'W',
0x2040, 'X',
0x2020, 'Y',
0x2010, 'Z',
0x0820, ':',
0x0420, '#', // = in 026 Fortran
0x0220, '@', // ' in 026 Fortran
0x0120, '\'',
0x00A0, '=',
0x0060, '"',
0x8820, '\xA2', // cent, in MS-DOS encoding
0x8420, '.',
0x8220, '<', // ) in 026 Fortran
0x8120, '(',
0x80A0, '+',
0x8060, '|',
0x4820, '!',
0x4420, '$',
0x4220, '*',
0x4120, ')',
0x40A0, ';',
0x4060, '\xAC', // not, in MS-DOS encoding
0x2420, ',',
0x2220, '%', // ( in 026 Fortran
0x2120, '_',
0x20A0, '>',
0xB000, 'a',
0xA800, 'b',
0xA400, 'c',
0xA200, 'd',
0xA100, 'e',
0xA080, 'f',
0xA040, 'g',
0xA020, 'h',
0xA010, 'i',
0xD000, 'j',
0xC800, 'k',
0xC400, 'l',
0xC200, 'm',
0xC100, 'n',
0xC080, 'o',
0xC040, 'p',
0xC020, 'q',
0xC010, 'r',
0x6800, 's',
0x6400, 't',
0x6200, 'u',
0x6100, 'v',
0x6080, 'w',
0x6040, 'x',
0x6020, 'y',
0x6010, 'z', // these odd punch codes are used by APL:
0x1010, '\001', // no corresponding ASCII using ^A
0x0810, '\002', // SYN using ^B
0x0410, '\003', // no corresponding ASCII using ^C
0x0210, '\004', // PUNCH ON using ^D
0x0110, '\005', // READER STOP using ^E
0x0090, '\006', // UPPER CASE using ^F
0x0050, '\013', // EOT using ^K
0x0030, '\016', // no corresponding ASCII using ^N
0x1030, '\017', // no corresponding ASCII using ^O
0x0830, '\020', // no corresponding ASCII using ^P
};
int hollerith_to_ascii (unsigned short h)
{
int i;
h &= 0xFFF0;
for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++)
if (cardcode_029[i].hollerith == h)
return cardcode_029[i].ascii;
return '?';
}
void bail (char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}

View file

@ -1,161 +0,0 @@
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
!IF "$(CFG)" == ""
CFG=Win32 Debug
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
!ENDIF
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "viewdeck.mak" CFG="Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
################################################################################
# Begin Project
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "WinRel"
# PROP BASE Intermediate_Dir "WinRel"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "WinRel"
# PROP Intermediate_Dir "WinRel"
OUTDIR=.\WinRel
INTDIR=.\WinRel
ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/ /c
CPP_OBJS=.\WinRel/
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc"
BSC32_SBRS= \
$(INTDIR)/viewdeck.sbr
$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\
/PDB:$(OUTDIR)/"viewdeck.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"viewdeck.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/viewdeck.obj
$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "WinDebug"
# PROP BASE Intermediate_Dir "WinDebug"
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "WinDebug"
# PROP Intermediate_Dir "WinDebug"
OUTDIR=.\WinDebug
INTDIR=.\WinDebug
ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc
$(OUTDIR) :
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
# ADD BASE CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
# ADD CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
CPP_PROJ=/nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
/FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/\
/Fd$(OUTDIR)/"viewdeck.pdb" /c
CPP_OBJS=.\WinDebug/
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc"
BSC32_SBRS= \
$(INTDIR)/viewdeck.sbr
$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<<
$(BSC32_FLAGS) $(BSC32_SBRS)
<<
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\
/PDB:$(OUTDIR)/"viewdeck.pdb" /DEBUG /MACHINE:I386\
/OUT:$(OUTDIR)/"viewdeck.exe"
DEF_FILE=
LINK32_OBJS= \
$(INTDIR)/viewdeck.obj
$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
.c{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
$(CPP) $(CPP_PROJ) $<
################################################################################
# Begin Group "Source Files"
################################################################################
# Begin Source File
SOURCE=.\viewdeck.c
$(INTDIR)/viewdeck.obj : $(SOURCE) $(INTDIR)
# End Source File
# End Group
# End Project
################################################################################

View file

@ -23,6 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
cpu Interdata 16b CPU
22-Sep-03 RMS Added additional instruction decode types
07-Feb-03 RMS Fixed bug in SETM, SETMR (found by Mark Pizzolato)
The register state for the Interdata 16b CPU is:
@ -266,7 +269,7 @@ const uint16 decrom[256] = {
OP_NO | OP_816, /* FXR */
OP_NO | OP_816, /* FLR */
0, 0, 0, /* 30:32 */
OP_RR | OP_816E | OP_PRV, /* LPSR */
OP_NO | OP_816E | OP_PRV, /* LPSR */
0, 0, 0, 0, /* 34:37 */
OP_NO | OP_816 | OP_DPF, /* LDR */
OP_NO | OP_816 | OP_DPF, /* CDR */
@ -328,8 +331,8 @@ const uint16 decrom[256] = {
OP_NO | OP_716, /* SRLS */
OP_NO | OP_716, /* SLLS */
OP_NO, /* STBR */
OP_NO, /* LDBR */
OP_NO | OP_716, /* EXBR */
OP_RR, /* LDBR */
OP_RR | OP_716, /* EXBR */
OP_NO | OP_716 | OP_PRV, /* EPSR */
OP_RR | OP_PRV, /* WBR */
OP_RR | OP_PRV, /* RBR */
@ -364,8 +367,8 @@ const uint16 decrom[256] = {
OP_RX | OP_ID4, /* STM */
OP_RX | OP_ID4, /* LM */
OP_RX, /* STB */
OP_RX, /* LDB */
OP_RX | OP_716, /* CLB */
OP_RXB, /* LDB */
OP_RXB | OP_716, /* CLB */
OP_RX | OP_ID4 | OP_PRV, /* AL */
OP_RXH | OP_PRV, /* WB */
OP_RXH | OP_PRV, /* RB */
@ -552,6 +555,7 @@ while (reason == 0) { /* loop until halted */
uint32 dev, drom, inc, lim, opnd;
uint32 op, r1, r1p1, r2, ea, oPC;
uint32 rslt, t, map;
uint32 ir1, ir2, ityp;
int32 sr, st;
if (sim_interval <= 0) { /* check clock queue */
@ -606,11 +610,13 @@ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
sim_interval = sim_interval - 1;
t = ReadH (oPC = PC); /* fetch instr */
op = (t >> 8) & 0xFF; /* isolate op, R1, R2 */
r1 = (t >> 4) & 0xF;
r2 = t & 0xF;
ir1 = ReadH (oPC = PC); /* fetch instr */
op = (ir1 >> 8) & 0xFF; /* isolate op, R1, R2 */
r1 = (ir1 >> 4) & 0xF;
r2 = ir1 & 0xF;
drom = decrom[op];
ityp = drom & OP_MASK;
if ((drom == 0) || (drom & dec_flgs)) { /* not in model? */
if (stop_inst) reason = STOP_RSRV; /* stop or */
else cc = swap_psw (ILOPSW, cc); /* swap PSW */
@ -618,26 +624,41 @@ if ((drom == 0) || (drom & dec_flgs)) { /* not in model? */
if ((drom & OP_PRV) && (PSW & PSW_PRO)) { /* priv & protected? */
cc = swap_psw (ILOPSW, cc); /* swap PSW */
continue; }
switch (drom & OP_MASK) { /* decode instruction */
switch (ityp) { /* decode instruction */
case OP_NO: /* no operand */
opnd = r2; /* assume short */
break;
case OP_RR: /* reg-reg */
opnd = R[r2]; /* operand is R2 */
break;
case OP_RS: /* reg-storage */
case OP_RX: /* reg-mem */
PC = (PC + 2) & VAMASK; /* increment PC */
ea = ReadH (PC); /* fetch address */
if (r2) ea = (ea + R[r2]) & VAMASK; /* index calculation */
ir2 = ea = ReadH (PC); /* fetch address */
if (r2) ea = (ir2 + R[r2]) & VAMASK; /* index calculation */
opnd = ea; /* operand is ea */
break;
case OP_RXH: /* reg-mem read */
case OP_RXB: /* reg-mem byte */
PC = (PC + 2) & VAMASK; /* increment PC */
ea = ReadH (PC); /* fetch address */
ir2 = ea = ReadH (PC); /* fetch address */
if (r2) ea = (ea + R[r2]) & VAMASK; /* index calculation */
opnd = ReadB (ea); /* fetch operand */
break;
case OP_RXH: /* reg-mem halfword */
PC = (PC + 2) & VAMASK; /* increment PC */
ir2 = ea = ReadH (PC); /* fetch address */
if (r2) ea = (ea + R[r2]) & VAMASK; /* index calculation */
opnd = ReadH (ea); /* fetch operand */
break; }
break;
default:
return SCPE_IERR; }
PC = (PC + 2) & VAMASK; /* increment PC */
switch (op) { /* case on opcode */
@ -672,11 +693,9 @@ case 0xD0: /* STM - RX */
ea = (ea + 2) & VAMASK; } /* incr mem addr */
break;
case 0x93: /* LDBR - NO */
R[r1] = R[r2] & DMASK8; /* load byte */
break;
case 0xD3: /* LDB - RX */
R[r1] = ReadB (ea); /* load byte */
case 0x93: /* LDBR - RR */
case 0xD3: /* LDB - RXB */
R[r1] = opnd & DMASK8; /* load byte */
break;
case 0x92: /* STBR - NO */
@ -686,8 +705,8 @@ case 0xD2: /* STB - RX */
WriteB (ea, R[r1] & DMASK8); /* store byte */
break;
case 0x94: /* EXBR - NO */
R[r1] = (R[r2] >> 8) | ((R[r2] & DMASK8) << 8);
case 0x94: /* EXBR - RR */
R[r1] = (opnd >> 8) | ((opnd & DMASK8) << 8);
break;
/* Control instructions */
@ -792,8 +811,7 @@ case 0xC5: /* CLHI - RS */
if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN16) cc = cc | CC_V;
break;
case 0xD4: /* CLB - RX */
opnd = ReadB (ea); /* get operand */
case 0xD4: /* CLB - RXB */
t = R[r1] & DMASK8;
rslt = (t - opnd) & DMASK16; /* result */
CC_GL_16 (rslt); /* set G,L */
@ -1118,7 +1136,7 @@ case 0xC2: /* LPSW - RX */
if (PSW & PSW_SQI) cc = testsysq (cc); /* test for q */
break;
case 0x95: /* EPSR - RR */
case 0x95: /* EPSR - NO */
R[r1] = BUILD_PSW (cc); /* save PSW */
case 0x33: /* LPSR - NO */
cc = newPSW (R[r2]); /* load new PSW */

View file

@ -1,6 +1,6 @@
/* id32_cpu.c: Interdata 32b CPU simulator
Copyright (c) 2000-2003, Robert M. Supnik
Copyright (c) 2000-2004, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,12 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
cpu Interdata 32b CPU
31-Dec-03 RMS Fixed bug in cpu_set_hist
22-Sep-03 RMS Added additional instruction decode types
Added instruction history
The register state for an Interdata 32b CPU is:
REG[0:F][2]<0:31> general register sets
@ -156,6 +162,18 @@
#define UNIT_832 (1 << UNIT_V_832)
#define UNIT_TYPE (UNIT_DPFP | UNIT_832)
#define HIST_PC 0x40000000
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
uint32 pc;
uint32 ir1;
uint32 ir2;
uint32 ir3;
uint32 r1;
uint32 ea;
uint32 opnd; };
#define SEXT32(x) (((x) & SIGN32)? ((int32) ((x) | ~0x7FFFFFFF)): \
((int32) ((x) & 0x7FFFFFFF)))
#define SEXT16(x) (((x) & SIGN16)? ((int32) ((x) | ~0x7FFF)): \
@ -202,6 +220,9 @@ uint32 dec_flgs = 0; /* decode flags */
uint32 fp_in_hwre = 0; /* ucode vs hwre fp */
uint32 pawidth = PAWIDTH32; /* addr mask */
uint32 cpu_log = 0; /* debug logging */
uint32 hst_p = 0; /* history pointer */
uint32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
jmp_buf save_env; /* abort handler */
struct BlockIO blk_io; /* block I/O status */
uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL };
@ -229,6 +250,8 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
void set_r_display (uint32 *rbase);
extern t_bool devtab_init (void);
@ -329,8 +352,8 @@ const uint16 decrom[256] = {
OP_RXF, /* S */
OP_RXF, /* M */
OP_RXF, /* D */
OP_RX, /* CRC12 */
OP_RX, /* CRC16 */
OP_RXH, /* CRC12 */
OP_RXH, /* CRC16 */
OP_RX, /* STE */
OP_RXH, /* AHM */
0, /* PB - 8/32C */
@ -349,7 +372,7 @@ const uint16 decrom[256] = {
OP_RX | OP_DPF, /* STD */
OP_RX, /* SME */
OP_RX, /* LME */
OP_RX, /* LHL */
OP_RXH, /* LHL */
OP_RX, /* TBT */
OP_RX, /* SBT */
OP_RX, /* RBT */
@ -367,8 +390,8 @@ const uint16 decrom[256] = {
OP_NO, /* SRHLS */
OP_NO, /* SLHLS */
OP_NO, /* STBR */
OP_NO, /* LDBR */
OP_NO, /* EXBR */
OP_RR, /* LDBR */
OP_RR, /* EXBR */
OP_NO | OP_PRV, /* EPSR */
OP_RR | OP_PRV, /* WBR */
OP_RR | OP_PRV, /* RBR */
@ -403,8 +426,8 @@ const uint16 decrom[256] = {
OP_RX, /* STM */
OP_RX, /* LM */
OP_RX, /* STB */
OP_RX, /* LDB */
OP_RX, /* CLB */
OP_RXB, /* LDB */
OP_RXB, /* CLB */
OP_RX | OP_PRV, /* AL */
OP_RXF | OP_PRV, /* WB */
OP_RXF | OP_PRV, /* RB */
@ -419,7 +442,7 @@ const uint16 decrom[256] = {
OP_RXH, /* TS */
OP_RX, /* SVC */
OP_RI1 | OP_PRV, /* SINT */
OP_RX | OP_PRV, /* SCP */
OP_RXH | OP_PRV, /* SCP */
0, 0, /* E4:E5 */
OP_RX, /* LA */
OP_RXF, /* TLATE */
@ -534,6 +557,8 @@ MTAB cpu_mod[] = {
{ UNIT_TYPE, UNIT_DPFP | UNIT_832, "8/32", "832", NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
&cpu_set_consint, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } };
DEVICE cpu_dev = {
@ -586,6 +611,7 @@ uint32 dev, drom, opnd, inc, lim, bufa;
uint32 op, r1, r1p1, r2, rx2, ea;
uint32 mpy, mpc, dvr;
uint32 i, rslt, rlo, t;
uint32 ir1, ir2, ir3, ityp;
int32 sr, st;
if (sim_interval <= 0) { /* check clock queue */
@ -644,11 +670,13 @@ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
sim_interval = sim_interval - 1;
t = ReadH (oPC = PC, VE); /* fetch instr */
op = (t >> 8) & 0xFF; /* extract op,R1,R2 */
r1 = (t >> 4) & 0xF;
r2 = t & 0xF;
ir1 = ReadH (oPC = PC, VE); /* fetch instr */
op = (ir1 >> 8) & 0xFF; /* extract op,R1,R2 */
r1 = (ir1 >> 4) & 0xF;
r2 = ir1 & 0xF;
drom = decrom[op]; /* get decode flags */
ityp = drom & OP_MASK; /* instruction type */
if ((drom == 0) || (drom & dec_flgs)) { /* not in model? */
if (stop_inst) reason = STOP_RSRV; /* stop or */
else cc = exception (ILOPSW, cc, 0); /* exception */
@ -657,55 +685,70 @@ if ((drom & OP_PRV) && (PSW & PSW_PRO)) { /* priv & protected? */
cc = exception (ILOPSW, cc, 0); /* exception */
continue; }
switch (drom & OP_MASK) { /* decode instruction */
switch (ityp) { /* decode instruction */
case OP_NO: /* no operand */
opnd = r2; /* assume short */
PC = (PC + 2) & VAMASK; /* increment PC */
break;
case OP_RR: /* reg-reg */
ea = opnd = R[r2]; /* operand is R2 */
opnd = R[r2]; /* ea/operand is R2 */
PC = (PC + 2) & VAMASK; /* increment PC */
break;
case OP_RI1: /* reg-imm 1 */
t = ReadH ((PC + 2) & VAMASK, VE); /* fetch immed */
opnd = SEXT16 (t); /* sign extend */
ir2 = ReadH ((PC + 2) & VAMASK, VE); /* fetch immed */
opnd = SEXT16 (ir2); /* sign extend */
if (r2) opnd = (opnd + R[r2]) & DMASK32; /* index calculation */
PC = (PC + 4) & VAMASK; /* increment PC */
break;
case OP_RI2: /* reg-imm 2 */
t = ReadH ((PC + 2) & VAMASK, VE); /* fetch imm hi */
opnd = t << 16; /* shift to place */
t = ReadH ((PC + 4) & VAMASK, VE); /* fetch imm lo */
opnd = opnd | t; /* complete imm */
ir2 = ReadH ((PC + 2) & VAMASK, VE); /* fetch imm hi */
ir3 = ReadH ((PC + 4) & VAMASK, VE); /* fetch imm lo */
opnd = (ir2 << 16) | ir3; /* 32b immediate */
if (r2) opnd = (opnd + R[r2]) & DMASK32; /* index calculation */
PC = (PC + 6) & VAMASK; /* increment PC */
break;
case OP_RX: case OP_RXH: case OP_RXF: /* reg-mem */
t = ReadH ((PC + 2) & VAMASK, VE); /* fetch addr */
if ((t & 0xC000) == 0) { /* displacement? */
case OP_RX: case OP_RXB: case OP_RXH: case OP_RXF: /* reg-mem */
ir2 = ReadH ((PC + 2) & VAMASK, VE); /* fetch addr */
if ((ir2 & 0xC000) == 0) { /* displacement? */
PC = (PC + 4) & VAMASK; /* increment PC */
ea = t; } /* abs 14b displ */
else if (t & 0x8000) { /* relative? */
ea = ir2; } /* abs 14b displ */
else if (ir2 & 0x8000) { /* relative? */
PC = (PC + 4) & VAMASK; /* increment PC */
ea = PC + SEXT15 (t); } /* add to incr PC */
ea = PC + SEXT15 (ir2); } /* add to incr PC */
else { /* absolute */
rx2 = (t >> 8) & 0xF; /* get second index */
ea = (t & 0xFF) << 16; /* shift to place */
t = ReadH ((PC + 4) & VAMASK, VE); /* fetch addr lo */
ea = ea | t; /* finish addr */
rx2 = (ir2 >> 8) & 0xF; /* get second index */
ea = (ir2 & 0xFF) << 16; /* shift to place */
ir3 = ReadH ((PC + 4) & VAMASK, VE); /* fetch addr lo */
ea = ea | ir3; /* finish addr */
if (rx2) ea = ea + R[rx2]; /* index calc 2 */
PC = (PC + 6) & VAMASK; } /* increment PC */
if (r2) ea = ea + R[r2]; /* index calculation */
ea = ea & VAMASK;
if ((drom & OP_MASK) == OP_RXF) /* get fw operand? */
opnd = ReadF (ea, VR); /* read fullword */
else if ((drom & OP_MASK) == OP_RXH) { /* get hw operand? */
if (ityp == OP_RXF) opnd = ReadF (ea, VR); /* get fw operand? */
else if (ityp == OP_RXH) { /* get hw operand? */
t = ReadH (ea, VR); /* read halfword */
opnd = SEXT16 (t); } /* sign extend */
else opnd = ea; /* for sloppy code */
else if (ityp == OP_RXB) opnd = ReadB (ea, VR); /* get byte opnd? */
else opnd = ea; /* just address */
break;
case OP_UNDEF:
default:
return SCPE_IERR; }
if (hst_lnt) { /* instruction history? */
hst[hst_p].pc = oPC | HIST_PC; /* save decode state */
hst[hst_p].ir1 = ir1;
hst[hst_p].ir2 = ir2;
hst[hst_p].ir3 = ir3;
hst[hst_p].r1 = R[r1];
hst[hst_p].ea = ea;
hst[hst_p].opnd = opnd;
hst_p = hst_p + 1;
if (hst_p >= hst_lnt) hst_p = 0; }
if (qevent & EV_MAC) continue; /* MAC abort on fetch? */
switch (op) { /* case on opcode */
@ -721,8 +764,8 @@ case 0xF8: /* LI - RI2 */
CC_GL_32 (R[r1]); /* set G,L */
break;
case 0x73: /* LHL - RX */
R[r1] = ReadH (ea, VR); /* get op, zero ext */
case 0x73: /* LHL - RXH */
R[r1] = opnd & DMASK16; /* get op, zero ext */
CC_GL_32 (R[r1]); /* set G, L */
break;
@ -764,11 +807,9 @@ case 0xE0: /* TS - RXH */
WriteH (ea, opnd | SIGN16, VW); /* set MSB */
break;
case 0x93: /* LDBR - NO */
R[r1] = R[r2] & DMASK8; /* load byte */
break;
case 0xD3: /* LDB - RX */
R[r1] = ReadB (ea, VR); /* load byte */
case 0x93: /* LDBR - RR */
case 0xD3: /* LDB - RXB */
R[r1] = opnd & DMASK8; /* load byte */
break;
case 0x92: /* STBR - NO */
@ -778,13 +819,13 @@ case 0xD2: /* STB - RX */
WriteB (ea, R[r1], VW); /* store byte */
break;
case 0x34: /* EXHR - NO */
R[r1] = ((R[r2] >> 16) & DMASK16) | ((R[r2] & DMASK16) << 16);
case 0x34: /* EXHR - RR */
R[r1] = ((opnd >> 16) & DMASK16) | ((opnd & DMASK16) << 16);
break;
case 0x94: /* EXBR - NO */
case 0x94: /* EXBR - RR */
R[r1] = (R[r1] & ~DMASK16) |
((R[r2] >> 8) & DMASK8) | ((R[r2] & DMASK8) << 8);
((opnd >> 8) & DMASK8) | ((opnd & DMASK8) << 8);
break;
/* Control instructions */
@ -793,14 +834,14 @@ case 0x01: /* BALR - RR */
case 0x41: /* BAL - RX */
PCQ_ENTRY; /* save old PC */
R[r1] = PC; /* save cur PC */
PC = ea; /* branch */
PC = opnd; /* branch */
break;
case 0x02: /* BTCR - RR */
case 0x42: /* BTC - RX */
if (cc & r1) { /* test CC's */
PCQ_ENTRY; /* branch if true */
PC = ea; }
PC = opnd; }
break;
case 0x20: /* BTBS - NO */
@ -819,7 +860,7 @@ case 0x03: /* BFCR - RR */
case 0x43: /* BFC - RX */
if ((cc & r1) == 0) { /* test CC's */
PCQ_ENTRY; /* branch if false */
PC = ea; }
PC = opnd; }
break;
case 0x22: /* BFBS - NO */
@ -840,16 +881,16 @@ case 0xC0: /* BXH - RX */
R[r1] = (R[r1] + inc) & DMASK32; /* R1 = R1 + inc */
if (R[r1] > lim) { /* if R1 > lim */
PCQ_ENTRY; /* branch */
PC = ea; }
PC = opnd; }
break;
case 0xC1: /* BXLE - RS */
case 0xC1: /* BXLE - RX */
inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */
lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */
R[r1] = (R[r1] + inc) & DMASK32; /* R1 = R1 + inc */
if (R[r1] <= lim) { /* if R1 <= lim */
PCQ_ENTRY; /* branch */
PC = ea; }
PC = opnd; }
break;
/* Logical instructions */
@ -898,8 +939,7 @@ case 0xF5: /* CI - RI2 */
if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN32) cc = cc | CC_V;
break;
case 0xD4: /* CLB - RX */
opnd = ReadB (ea, VR); /* get operand */
case 0xD4: /* CLB - RXB */
t = R[r1] & DMASK8;
rslt = (t - opnd) & DMASK16; /* result */
CC_GL_16 (rslt); /* set G,L 16b */
@ -1278,8 +1318,8 @@ case 0xE2: /* SINT - RI1 */
int_eval ();
break;
case 0xE3: /* SCP - RX */
opnd = ReadH (ea, VR); /* zero ext operand */
case 0xE3: /* SCP - RXH */
opnd = opnd & DMASK16; /* zero ext operand */
if (opnd & CCW32_B1) t = ea + CCB32_B1C; /* point to buf */
else t = ea + CCB32_B0C;
sr = ReadH (t & VAMASK, VR); /* get count */
@ -1335,7 +1375,7 @@ case 0x67: /* RBL - RX */
break;
case 0x5E: /* CRC12 - RXH */
opnd = ReadH (ea, VR); /* zero ext opnd */
opnd = opnd & DMASK16; /* zero ext opnd */
t = (R[r1] & 0x3F) ^ opnd;
for (i = 0; i < 6; i++) {
if (t & 1) t = (t >> 1) ^ 0x0F01;
@ -1344,7 +1384,7 @@ case 0x5E: /* CRC12 - RXH */
break;
case 0x5F: /* CRC16 - RXH */
opnd = ReadH (ea, VR); /* zero ext opnd */
opnd = opnd & DMASK16; /* zero ext opnd */
t = (R[r1] & 0xFF) ^ opnd;
for (i = 0; i < 8; i++) {
if (t & 1) t = (t >> 1) ^ 0xA001;
@ -1417,7 +1457,7 @@ case 0xDB: /* RD - RX */
break;
case 0x99: /* RHR - RR */
case 0xD9: /* RH - RS */
case 0xD9: /* RH - RX */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) { /* dev exist? */
if (dev_tab[dev] (dev, IO_ADR, 0)) /* select, hw ok? */
@ -1436,7 +1476,7 @@ case 0xD9: /* RH - RS */
break;
case 0x9D: /* SSR - RR */
case 0xDD: /* SS - RS */
case 0xDD: /* SS - RX */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) { /* dev exist? */
dev_tab[dev] (dev, IO_ADR, 0); /* select */
@ -2026,3 +2066,61 @@ t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc)
if (PSW & PSW_EXI) SET_INT (v_DS);
return SCPE_OK;
}
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (uint32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
uint32 op, k, di;
t_value sim_eval[6];
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
fprintf (st, "PC r1 operand ea IR\n\n");
di = hst_p; /* work forward */
for (k = 0; k < hst_lnt; k++) { /* print specified */
h = &hst[(di++) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
fprintf (st, "%06X %08X %08X ", h->pc & VAMASK32, h->r1, h->opnd);
sim_eval[0] = op = (h->ir1 >> 8) & 0xFF;
sim_eval[1] = h->ir1 & 0xFF;
sim_eval[2] = (h->ir2 >> 8) & 0xFF;
sim_eval[3] = h->ir2 & 0xFF;
sim_eval[4] = (h->ir3 >> 8) & 0xFF;
sim_eval[5] = h->ir3 & 0xFF;
if (OP_TYPE (op) >= OP_RX) fprintf (st, "%06X ", h->ea);
else fprintf (st, " ");
if ((fprint_sym (st, h->pc & VAMASK32, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %04X", h->ir1);
fputc ('\n', st); /* end line */
} /* end if instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -26,6 +26,7 @@
The author gratefully acknowledges the help of Carl Friend and Al Kossow,
who provided key documents about the Interdata product line.
22-Sep-03 RMS Added additional instruction decode types
21-Jun-03 RMS Changed subroutine argument for ARM compiler conflict
25-Apr-03 RMS Revised for extended file support
28-Feb-03 RMS Changed magtape device default to 0x85
@ -188,9 +189,10 @@ struct BlockIO {
#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_RXB 0x0005 /* all: reg-mem, rd BY */
#define OP_RXH 0x0006 /* all: reg-mem, rd HW */
#define OP_RXF 0x0007 /* 32b: reg-mem, rd FW */
#define OP_RI2 0x0008 /* 32b: reg-imm 32b */
#define OP_MASK 0x000F
#define OP_ID4 0x0010 /* 16b: ID4 */

View file

@ -69,7 +69,7 @@ sim> boot pt0
Breakpoint: PC: 00C2 (EXBR R8,R6)
sim> run 100
sim> run 2d0
MODEL 8/16E PROCESSOR TEST PART 2 06-212R00
CPU
@ -96,7 +96,7 @@ Breakpoint, PC: 00C0 (8800)
sim> d 234a 0202 ; patch to use
sim> d 234c a4a8 ; TTY as console
sim> d 17a b1e4
sim> d 17a b 1e4
sim> run 100
SERIES SIXTEEN PROCESSOR TEST PART 1 06-242F01R00

View file

@ -259,6 +259,16 @@ control registers for the interrupt system.
most recent PC change first
WRU 8 interrupt character
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, display length = n
SHOW CPU HISTORY print CPU history
The maximum length for the history is 65536 entries.
2.3 Selector Channel (SELCH)
An Interdata system can have 1 to 4 selector channels (SELCH0, SELCH1,

View file

@ -276,6 +276,7 @@ return 0;
t_stat fd_svc (UNIT *uptr)
{
uint32 i, u, tk, sc, crc, fnc, da;
uint8 *fbuf = uptr->filebuf;
u = uptr - fd_dev.units; /* get unit number */
fnc = GET_FNC (uptr->FNC); /* get function */
@ -296,9 +297,9 @@ case FNC_RD: /* read, buf empty */
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 */
fdxb[i] = fbuf[da + i];
if (fbuf[FD_SIZE + uptr->LRN - 1]) { /* deleted? set err */
fd_sta = fd_sta | STA_DEL;
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);
@ -313,9 +314,8 @@ case FNC_WR: case FNC_DEL: /* write block */
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 */
fbuf[da + i] = fdxb[i]; /* then dir */
fbuf[FD_SIZE + uptr->LRN - 1] = ((fnc == FNC_DEL)? 1: 0);
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);

View file

@ -546,9 +546,9 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */
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 */
dmsk = 1u << (t & 0x1F); /* bit to test */
doff = t / 32; /* word to test */
if (dmap[doff] & dmsk) { /* in use? */
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);

View file

@ -25,6 +25,7 @@
tt console
29-Dec-03 RMS Added support for console backpressure
25-Apr-03 RMS Revised for extended file support
11-Jan-03 RMS Added TTP support
22-Dec-02 RMS Added break support
@ -192,16 +193,18 @@ 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 */
if ((uptr->flags & UNIT_8B) || /* KSR or 7b? */
((ch != 0) && (ch != 0x7F))) { /* supr NULL, DEL */
if ((r = sim_putchar_s (ch)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } }
if (!tt_rd) { /* write mode? */
tt_sta = tt_sta & ~STA_BSY; /* clear busy */
if (tt_arm) SET_INT (v_TT); } /* if armed, intr */
uptr->pos = uptr->pos + 1; /* incr count */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* id_ttp.c: Interdata PASLA console interface
Copyright (c) 2000-2003, Robert M. Supnik
Copyright (c) 2000-2004, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
ttp console (on PAS)
29-Dec-03 RMS Added support for console backpressure
25-Apr-03 RMS Revised for extended file support
*/
@ -195,16 +196,18 @@ 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 */
if ((uptr->flags & UNIT_8B) || /* UC or 7b? */
((c != 0) && (c != 0x7F))){ /* supr NULL, DEL */
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } }
ttp_sta = ttp_sta & ~STA_BSY; /* not busy */
if (ttp_tarm) SET_INT (v_TTP + 1); /* set intr */
uptr->pos = uptr->pos + 1; /* incr count */
return SCPE_OK;
}

File diff suppressed because it is too large Load diff

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-03 CEO Added support for PIT device
19-Jan-03 RMS Changed CMASK to CDMASK for Apple Dev kit conflict
03-Oct-02 RMS Added device information structure
22-Dec-00 RMS Added Bruce Ray's second terminal support
@ -174,6 +175,7 @@
#define DEV_ADCV 030 /* A/D converter */
#define DEV_DKP 033 /* disk pack */
#define DEV_CAS 034 /* cassette */
#define DEV_PIT 043 /* programmable interval timer */
#define DEV_TTI1 050 /* second console input */
#define DEV_TTO1 051 /* second console output */
#define DEV_CPU 077 /* CPU control */
@ -211,6 +213,7 @@ typedef struct nova_dib DIB;
Priority (for INTA) runs from low numbers to high
*/
#define INT_V_PIT 2 /* PIT */
#define INT_V_DKP 3 /* moving head disk */
#define INT_V_DSK 4 /* fixed head disk */
#define INT_V_MTA 5 /* magnetic tape */
@ -227,6 +230,7 @@ typedef struct nova_dib DIB;
#define INT_V_NO_ION_PENDING 16 /* ion delay */
#define INT_V_ION 17 /* interrupts on */
#define INT_PIT (1 << INT_V_PIT)
#define INT_DKP (1 << INT_V_DKP)
#define INT_DSK (1 << INT_V_DSK)
#define INT_MTA (1 << INT_V_MTA)
@ -247,6 +251,7 @@ typedef struct nova_dib DIB;
/* PI disable bits */
#define PI_PIT 0001000
#define PI_DKP 0000400
#define PI_DSK 0000100
#define PI_MTA 0000040

View file

@ -25,6 +25,9 @@
dkp moving head disk
28-Nov-03 CEO Boot from DP now puts device address in SR
24-Nov-03 CEO Added support for disk sizing on 6099/6103
19-Nov-03 CEO Corrected major DMA Mapping bug
25-Apr-03 RMS Revised autosizing
08-Oct-02 RMS Added DIB
06-Jan-02 RMS Revised enable/disable support
@ -225,7 +228,7 @@
#define TYPE_6070 8
#define SECT_6070 24
#define SURF_6070 4
#define CYL_6070 408
#define CYL_6070 408
#define SIZE_6070 (SECT_6070 * SURF_6070 * CYL_6070 * DKP_NUMWD)
#define NFMT_6070 TRUE
@ -278,11 +281,13 @@ extern UNIT cpu_unit;
extern int32 int_req, dev_busy, dev_done, dev_disable;
int32 dkp_ma = 0; /* memory address */
int32 dkp_map = 0; /* DCH map 0=A 3=B */
int32 dkp_ussc = 0; /* unit/sf/sc/cnt */
int32 dkp_fccy = 0; /* flags/cylinder */
int32 dkp_sta = 0; /* status register */
int32 dkp_swait = 100; /* seek latency */
int32 dkp_rwait = 100; /* rotate latency */
int32 dkp_diagmode = 0; /* diagnostic mode */
DEVICE dkp_dev;
int32 dkp (int32 pulse, int32 code, int32 AC);
@ -322,6 +327,8 @@ REG dkp_reg[] = {
{ FLDATA (BUSY, dev_busy, INT_V_DKP) },
{ FLDATA (DONE, dev_done, INT_V_DKP) },
{ FLDATA (DISABLE, dev_disable, INT_V_DKP) },
{ FLDATA (DIAG, dkp_diagmode, 0) },
{ ORDATA (MAP, dkp_map, 2) },
{ DRDATA (STIME, dkp_swait, 24), PV_LEFT },
{ DRDATA (RTIME, dkp_rwait, 24), PV_LEFT },
{ URDATA (CAPAC, dkp_unit[0].capac, 10, T_ADDR_W, 0,
@ -452,22 +459,32 @@ case ioDIA: /* DIA */
rval = dkp_sta;
break;
case ioDOA: /* DOA */
if (AC & 0100000) /* clear rw done? */
dkp_sta = dkp_sta & ~(STA_CYL|STA_XCY|STA_UNS|STA_CRC);
if ((dev_busy & INT_DKP) == 0) {
dkp_fccy = AC; /* save cmd, cyl */
dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS); }
if ((dkp_sta & STA_DFLGS) == 0) /* done flags = 0? */
dev_done = dev_done & ~INT_DKP; /* clear intr */
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].newf? DMASK: AMASK);
if ((dev_busy & INT_DKP) == 0) {
dkp_ma = AC & (drv_tab[dtype].newf? DMASK: AMASK);
if (AC & 0100000) dkp_map = 3; /* high bit is map */
else dkp_map = 0;
}
break;
case ioDIC: /* DIC */
rval = dkp_ussc; /* return unit, sect */
break;
case ioDOC: /* DOC */
if ((dev_busy & INT_DKP) == 0) dkp_ussc = AC; /* save unit, sect */
if (((dtype == TYPE_6099) || /* for 6099 and 6103 */
(dtype == TYPE_6103)) && /* if data<0> set, */
AC & 010000) dkp_diagmode = 1; /* set diagnostic mode */
break; } /* end switch code */
/* IOT, continued */
@ -478,7 +495,14 @@ case iopS: /* start */
dev_busy = dev_busy | INT_DKP; /* set busy */
dev_done = dev_done & ~INT_DKP; /* clear done */
int_req = int_req & ~INT_DKP; /* clear int */
if (dkp_go ()) break; /* new cmd, error? */
if (dkp_diagmode) { /* in diagnostic mode? */
dkp_diagmode = 0; /* reset it */
if (dtype == TYPE_6099) dkp_ussc = 010002; /* return size bits */
if (dtype == TYPE_6103) dkp_ussc = 010003; /* for certain types */
}
else { /* normal mode ... */
if (dkp_go ()) break; /* new cmd, error? */
}
dev_busy = dev_busy & ~INT_DKP; /* clear busy */
dev_done = dev_done | INT_DKP; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
@ -558,6 +582,13 @@ static uint16 tbuf[DKP_NUMWD]; /* transfer buffer */
rval = SCPE_OK;
dtype = GET_DTYPE (uptr->flags); /* get drive type */
if (dkp_diagmode) { /* diagnostic mode? */
dkp_sta = (dkp_sta | STA_DONE); /* Set error bit only */
dev_busy = dev_busy & ~INT_DKP; /* clear busy */
dev_done = dev_done | INT_DKP; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
return SCPE_OK; /* do not do function */
}
if (uptr->FUNC == FCCY_SEEK) { /* seek? */
if (uptr->CYL >= drv_tab[dtype].cyl) /* bad cylinder? */
dkp_sta = dkp_sta | STA_ERR | STA_CYL;
@ -597,14 +628,14 @@ else { sc = 16 - GET_COUNT (dkp_ussc); /* get sector count */
for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0;
if (err = ferror (uptr->fileref)) break;
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */
pa = MapAddr (0, dkp_ma);
pa = MapAddr (dkp_map, (dkp_ma & AMASK));
if (MEM_ADDR_OK (pa)) M[pa] = tbuf[dx];
dkp_ma = (dkp_ma + 1) & AMASK; } } }
if (uptr->FUNC == FCCY_WRITE) { /* write? */
for (sx = 0; sx < sc; sx++) { /* loop thru sectors */
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop into buffer */
pa = MapAddr (0, dkp_ma);
pa = MapAddr (dkp_map, (dkp_ma & AMASK));
tbuf[dx] = M[pa];
dkp_ma = (dkp_ma + 1) & AMASK; }
fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr->fileref);
@ -641,6 +672,8 @@ dev_busy = dev_busy & ~INT_DKP; /* clear busy */
dev_done = dev_done & ~INT_DKP; /* clear done, int */
int_req = int_req & ~INT_DKP;
dkp_fccy = dkp_ussc = dkp_ma = dkp_sta = 0; /* clear registers */
dkp_diagmode = 0; /* clear diagnostic mode */
dkp_map = 0;
for (u = 0; u < DKP_NUMDR; u++) { /* loop thru units */
uptr = dkp_dev.units + u;
sim_cancel (uptr); /* cancel activity */
@ -685,33 +718,33 @@ return SCPE_OK;
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = {
060233, /* NIOC 0,DKP ; clear disk */
020420, /* LDA 0,USSC ; unit, sfc, sec, cnt */
063033, /* DOC 0,DKP ; select disk */
020417, /* LDA 0,SEKCMD ; command, cylinder */
061333, /* DOAP 0,DKP ; start seek */
024415, /* LDA 1,SEKDN */
060433, /* DIA 0,DKP ; get status */
0060233, /* NIOC 0,DKP ; clear disk */
0020420, /* LDA 0,USSC ; unit, sfc, sec, cnt */
0063033, /* DOC 0,DKP ; select disk */
0020417, /* LDA 0,SEKCMD ; command, cylinder */
0061333, /* DOAP 0,DKP ; start seek */
0024415, /* LDA 1,SEKDN */
0060433, /* DIA 0,DKP ; get status */
0123415, /* AND# 1,0,SZR ; skip if done */
000776, /* JMP .-2 */
0000776, /* JMP .-2 */
0102400, /* SUB 0,0 ; mem addr = 0 */
062033, /* DOB 0,DKP */
020411, /* LDA 0,REDCMD ; command, cylinder */
061133, /* DOAS 0,DKP ; start read */
060433, /* DIA 0, DKP ; get status */
0062033, /* DOB 0,DKP */
0020411, /* LDA 0,REDCMD ; command, cylinder */
0061133, /* DOAS 0,DKP ; start read */
0060433, /* DIA 0, DKP ; get status */
0101113, /* MOVL# 0,0,SNC ; skip if done */
000776, /* JMP .-2 */
000377, /* JMP 377 */
000016, /* USSC: 0.B1+0.B7+0.B11+16 */
0000776, /* JMP .-2 */
0000377, /* JMP 377 */
0000016, /* USSC: 0.B1+0.B7+0.B11+16 */
0175000, /* SEKCMD: 175000 */
074000, /* SEKDN: 074000 */
0074000, /* SEKDN: 074000 */
0174000 /* REDCMD: 174000 */
};
t_stat dkp_boot (int32 unitno, DEVICE *dptr)
{
int32 i, dtype;
extern int32 saved_PC;
extern int32 saved_PC, SR;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
unitno = unitno & USSC_M_UNIT;
@ -719,5 +752,6 @@ dtype = GET_DTYPE (dkp_unit[unitno].flags);
M[BOOT_UNIT] = M[BOOT_UNIT] | (unitno << USSC_V_UNIT);
if (drv_tab[dtype].newf) M[BOOT_SEEK] = 0176000;
saved_PC = BOOT_START;
SR = 0100000 + DEV_DKP;
return SCPE_OK;
}

View file

@ -485,6 +485,8 @@ The moving head disk controller implements these registers:
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
DIAG 1 diagnostic mode flag
MAP 2 map select
STIME 24 seek time, per cylinder
RTIME 24 rotational delay

View file

@ -205,6 +205,7 @@ return rval;
t_stat dsk_svc (UNIT *uptr)
{
int32 i, da, pa;
int16 *fbuf = uptr->filebuf;
dev_busy = dev_busy & ~INT_DSK; /* clear busy */
dev_done = dev_done | INT_DSK; /* set done */
@ -218,13 +219,12 @@ 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); }
if (MEM_ADDR_OK (pa)) M[pa] = fbuf[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]; }
fbuf[da + i] = M[pa]; }
if (((uint32) (da + i)) >= uptr->hwmark) /* past end? */
uptr->hwmark = da + i + 1; /* upd hwmark */
dsk_ma = (dsk_ma + DSK_NUMWD + 3) & AMASK; }

View file

@ -25,6 +25,8 @@
mta magnetic tape
22-Nov-03 CEO DIB returns # records skipped after space fwd
22-Nov-03 CEO Removed cancel of tape events in IORST
25-Apr-03 RMS Revised for extended file support
28-Mar-03 RMS Added multiformat support
28-Feb-03 RMS Revised for magtape library
@ -397,6 +399,7 @@ case CU_SPACEF: /* space forward */
}
while (mta_wc != 0);
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
mta_ma = mta_wc; /* Word count = # records */
break;
case CU_SPACER: /* space reverse */
@ -408,6 +411,7 @@ case CU_SPACER: /* space reverse */
}
while (mta_wc != 0);
mta_upddsta (uptr, uptr->USTAT | STA_RDY);
mta_ma = mta_wc; /* Word count = # records */
break;
default: /* reserved */
@ -503,8 +507,15 @@ dev_done = dev_done & ~INT_MTA; /* clear done, int */
int_req = int_req & ~INT_MTA;
mta_cu = mta_wc = mta_ma = mta_sta = 0; /* clear registers */
mta_ep = 0;
/* AOS Installer does an IORST after a tape rewind command but before it can
be serviced, yet expects the tape to have been rewound */
for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
uptr = mta_dev.units + u;
if (sim_is_active (uptr) && /* active and */
(uptr->flags & STA_REW)) /* rewinding? */
sim_tape_rewind (uptr); /* update tape */
sim_tape_reset (uptr); /* clear pos flag */
sim_cancel (uptr); /* cancel activity */
if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY |
@ -556,34 +567,35 @@ return SCPE_OK;
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = {
060222, /* NIOC 0,MTA ; clear disk */
020417, /* LDA 0,UNIT ; unit */
024417, /* LDA 1,REWIND ; cmd */
0060222, /* NIOC 0,MTA ; clear disk */
0020417, /* LDA 0,UNIT ; unit */
0024417, /* LDA 1,REWIND ; cmd */
0107000, /* ADD 0,1 ; cmd + unit */
065122, /* DOAS 1,MTA ; start rewind */
070422, /* DIA 2,MTA ; get status */
0065122, /* DOAS 1,MTA ; start rewind */
0070422, /* DIA 2,MTA ; get status */
0151213, /* MOVR# 2,2,SNC ; skip if done */
000776, /* JMP .-2 */
0000776, /* JMP .-2 */
0126400, /* SUB 1,1 ; ma, wc = 0 */
066022, /* DOB 1,MTA */
067022, /* DOC 1,MTA */
061122, /* DOAS 0,MTA ; start read */
070422, /* DIA 2,MTA ; get status */
0066022, /* DOB 1,MTA */
0067022, /* DOC 1,MTA */
0061122, /* DOAS 0,MTA ; start read */
0070422, /* DIA 2,MTA ; get status */
0151213, /* MOVR# 2,2,SNC ; skip if done */
000776, /* JMP .-2 */
000377, /* JMP 377 */
000000, /* UNIT: */
000010 /* REWIND: 10 */
0000776, /* JMP .-2 */
0000377, /* JMP 377 */
0000000, /* UNIT: */
0000010 /* REWIND: 10 */
};
t_stat mta_boot (int32 unitno, DEVICE *dptr)
{
int32 i;
extern int32 saved_PC;
extern int32 saved_PC, SR;
sim_tape_rewind (&mta_unit[unitno]);
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
M[BOOT_UNIT] = (unitno & CU_M_UNIT) << CU_V_UNIT;
saved_PC = BOOT_START;
SR = 0100000 + DEV_MTA;
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.
24-Nov-03 CEO Added symbolic support for LEF instruction
17-Sep-01 RMS Removed multiconsole support
31-May-01 RMS Added multiconsole support
14-Mar-01 RMS Revised load/dump interface (again)
@ -43,16 +44,23 @@ extern DEVICE cpu_dev;
extern UNIT cpu_unit;
#if defined (ECLIPSE)
extern DEVICE map_dev;
extern DEVICE fpu_dev;
extern DEVICE pit_dev;
extern int32 Usermap;
extern int32 MapStat;
#endif
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE plt_dev;
extern DEVICE tti_dev, tto_dev;
extern DEVICE tti1_dev, tto1_dev;
extern DEVICE clk_dev, lpt_dev;
extern DEVICE dkp_dev, dsk_dev;
extern DEVICE tti_dev;
extern DEVICE tto_dev;
extern DEVICE tti1_dev;
extern DEVICE tto1_dev;
extern DEVICE clk_dev;
extern DEVICE lpt_dev;
extern DEVICE dkp_dev;
extern DEVICE dsk_dev;
extern DEVICE mta_dev;
extern UNIT tti_unit, tto_unit;
extern UNIT tti1_unit, tto1_unit;
extern REG cpu_reg[];
extern uint16 M[];
extern int32 saved_PC;
@ -81,13 +89,21 @@ DEVICE *sim_devices[] = {
&cpu_dev,
#if defined (ECLIPSE)
&map_dev,
&fpu_dev,
&pit_dev,
#endif
&ptr_dev, &ptp_dev,
&tti_dev, &tto_dev,
&tti1_dev, &tto1_dev,
&clk_dev, &plt_dev,
&lpt_dev, &dsk_dev,
&dkp_dev, &mta_dev,
&ptr_dev,
&ptp_dev,
&tti_dev,
&tto_dev,
&tti1_dev,
&tto1_dev,
&clk_dev,
&plt_dev,
&lpt_dev,
&dsk_dev,
&dkp_dev,
&mta_dev,
NULL };
const char *sim_stop_messages[] = {
@ -256,7 +272,7 @@ static const char *opcode[] = {
"BTO", "BTZ", "SBZ", "SZBO",
"LOB", "LRB", "COB", "LDB",
"STB", "PSH", "POP",
"LMP", "SYSC",
"LMP", "SYC",
"PSHR", "POPB", "BAM", "POPJ",
"RTN", "BLM", "DIVX",
"MUL", "MULS", "DIV", "DIVS",
@ -366,6 +382,9 @@ static const char *opcode[] = {
"DIC", "DICS", "DICC", "DICP",
"DOC", "DOCS", "DOCC", "DOCP",
"SKPBN", "SKPBZ", "SKPDN", "SKPDZ",
#if defined (ECLIPSE)
"LEF", "LEF", "LEF", "LEF",
#endif
NULL };
static const opc_val[] = {
@ -379,7 +398,7 @@ static const opc_val[] = {
0102010+I_2AC, 0102110+I_2AC, 0102210+I_2AC, 0102310+I_2AC,
0102410+I_2AC, 0102510+I_2AC, 0102610+I_2AC, 0102710+I_2AC,
0103010+I_2AC, 0103110+I_2AC, 0103210+I_2AC,
0113410+I_NPN, 0103510+I_RSI,
0113410+I_NPN, 0103510+I_2AC,
0103710+I_NPN, 0107710+I_NPN, 0113710+I_NPN, 0117710+I_NPN,
0127710+I_NPN, 0133710+I_NPN, 0137710+I_NPN,
0143710+I_NPN, 0147710+I_NPN, 0153710+I_NPN, 0157710+I_NPN,
@ -489,6 +508,9 @@ static const opc_val[] = {
0062400+I_RD, 0062500+I_RD, 0062600+I_RD, 0062700+I_RD,
0063000+I_RD, 0063100+I_RD, 0063200+I_RD, 0063300+I_RD,
0063400+I_D, 0063500+I_D, 0063600+I_D, 0063700+I_D,
#if defined (ECLIPSE)
0064000+I_D, 0070000+I_D, 0074000+I_D, 0076000+I_D,
#endif
-1 };
static const char *skip[] = {
@ -579,8 +601,8 @@ int32 ind, mode, disp, dev;
int32 byac, extind, extdisp, xop;
cflag = (uptr == NULL) || (uptr == &cpu_unit);
c1 = (val[0] >> 8) & 0177;
c2 = val[0] & 0177;
c1 = ((int32) val[0] >> 8) & 0177;
c2 = (int32) val[0] & 0177;
if (sw & SWMASK ('A')) { /* ASCII? */
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
return SCPE_OK; }
@ -592,7 +614,7 @@ if (!(sw & SWMASK ('M'))) return SCPE_ARG; /* mnemonic? */
/* Instruction decode */
inst = val[0];
inst = (int32) val[0];
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((opc_val[i] & 0177777) == (inst & masks[j])) { /* match? */
@ -605,8 +627,8 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
dev = I_GETDEV (inst); /* IOT fields */
byac = I_GETPULSE (inst); /* byte fields */
xop = I_GETXOP (inst); /* XOP fields */
extind = val[1] & A_IND; /* extended fields */
extdisp = val[1] & AMASK;
extind = (int32) val[1] & A_IND; /* extended fields */
extdisp = (int32) val[1] & AMASK;
for (dv = 0; (dev_val[dv] >= 0) && (dev_val[dv] != dev); dv++) ;
switch (j) { /* switch on class */
@ -617,6 +639,13 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
fprintf (of, "%s %-o", opcode[i], dst);
break;
case I_V_D: /* dev only */
#if defined (ECLIPSE)
if (Usermap && (MapStat & 0100)) { /* the evil LEF mode */
fprintf (of, "LEF %-o,", dst);
fprint_addr (of, addr, ind, mode, disp, FALSE, cflag);
break;
}
#endif
if (dev_val[dv] >= 0)
fprintf (of, "%s %s", opcode[i], device[dv]);
else fprintf (of, "%s %-o", opcode[i], dev);
@ -671,7 +700,10 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
return -1;
case I_V_XP: /* XOP */
fprintf (of, "%s %-o,%-o,%-o", opcode[i], src, dst, xop);
break; } /* end case */
break; /* end case */
default:
fprintf (of, "??? [%-o]", inst);
break; }
return SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
@ -726,12 +758,12 @@ else if (*cptr == '-') { /* - sign? */
cptr++; }
if (*cptr != 0) { /* number? */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
d = get_uint (gbuf, 8, AMASK, &r);
d = (int32) get_uint (gbuf, 8, AMASK, &r);
if (r != SCPE_OK) return NULL;
pflag = pflag | A_NUM; }
if (*cptr != 0) { /* index? */
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
x = get_uint (gbuf, 8, I_M_DST, &r);
x = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if ((r != SCPE_OK) || (x < 2)) return NULL;
pflag = pflag | A_NX; }
@ -786,10 +818,10 @@ char gbuf[CBUFSIZE];
t_stat r;
cptr = get_glyph (cptr, gbuf, ','); /* get register */
val[0] = get_uint (gbuf, 8, I_M_SRC, &r);
val[0] = (int32) get_uint (gbuf, 8, I_M_SRC, &r);
if (r != SCPE_OK) return NULL;
cptr = get_glyph (cptr, gbuf, term); /* get register */
val[1] = get_uint (gbuf, 8, I_M_DST, &r);
val[1] = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return NULL;
return cptr;
}
@ -837,13 +869,13 @@ case I_V_NPN: /* no operand */
break;
case I_V_R: /* IOT reg */
cptr = get_glyph (cptr, gbuf, 0); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
d = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
break;
case I_V_RD: /* IOT reg,dev */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
d = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
case I_V_D: /* IOT dev */
@ -852,13 +884,13 @@ case I_V_D: /* IOT dev */
(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);
d = (int32) 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 */
d = get_uint (gbuf, 8, I_M_DST, &r);
d = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
case I_V_M: /* addr */
@ -889,33 +921,33 @@ case I_V_2AC: /* reg, reg */
break;
case I_V_RSI: /* reg, short imm */
cptr = get_glyph (cptr, gbuf, ','); /* get immediate */
d = get_uint (gbuf, 8, I_M_SRC + 1, &r);
d = (int32) get_uint (gbuf, 8, I_M_SRC + 1, &r);
if ((d == 0) || (r != SCPE_OK)) return SCPE_ARG;
val[0] = val[0] | ((d - 1) << I_V_SRC); /* put in place */
cptr = get_glyph (cptr, gbuf, 0); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
d = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
break;
case I_V_RLI: /* reg, long imm */
cptr = get_glyph (cptr, gbuf, ','); /* get immediate */
val[1] = get_uint (gbuf, 8, DMASK, &r);
val[1] = (int32) get_uint (gbuf, 8, DMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, 0); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
d = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
rtn = -1;
break;
case I_V_LI: /* long imm */
cptr = get_glyph (cptr, gbuf, 0); /* get immediate */
val[1] = get_uint (gbuf, 8, DMASK, &r);
val[1] = (int32) get_uint (gbuf, 8, DMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
rtn = -1;
break;
case I_V_RLM: /* reg, long mem */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
d = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
case I_V_LM: /* long mem */
@ -927,7 +959,7 @@ case I_V_LM: /* long mem */
break;
case I_V_FRM: /* flt reg, long mem */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
d = (int32) get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
cptr = get_addr (cptr, addr, TRUE, cflag, amd);
@ -948,7 +980,7 @@ case I_V_XP: /* XOP */
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST);
cptr = get_glyph (cptr, gbuf, 0); /* get argument */
d = get_uint (gbuf, 8, I_M_XOP, &r);
d = (int32) get_uint (gbuf, 8, I_M_XOP, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_XOP);
break; } /* end case */

View file

@ -1,6 +1,6 @@
/* nova_tt.c: NOVA console terminal simulator
Copyright (c) 1993-2003, Robert M. Supnik
Copyright (c) 1993-2004, 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
29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support
05-Jan-02 RMS Fixed calling sequence for setmod
03-Oct-02 RMS Added DIBs
@ -188,14 +189,17 @@ return 0;
t_stat tto_svc (UNIT *uptr)
{
int32 c, temp;
int32 c;
t_stat r;
c = tto_unit.buf & 0177;
if ((tto_unit.flags & UNIT_DASHER) && (c == 031)) c = '\b';
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */
dev_busy = dev_busy & ~INT_TTO; /* clear busy */
dev_done = dev_done | INT_TTO; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
c = tto_unit.buf & 0177;
if ((tto_unit.flags & UNIT_DASHER) && (c == 031)) c = '\b';
if ((temp = sim_putchar (c)) != SCPE_OK) return temp;
tto_unit.pos = tto_unit.pos + 1;
return SCPE_OK;
}

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
08-Dec-03 RMS Added support for parallel drum
18-Oct-03 RMS Added DECtape off reel message
22-Jul-03 RMS Updated for "hardware" RIM loader
Revised to detect I/O wait hang
05-Dec-02 RMS Added IOT skip support (required by drum)
@ -36,6 +38,7 @@
Automatic multiply/divide Type 10
Memory extension control Type 15
Parallel drum Type 23
Serial drum Type 24
Line printer control Type 62
Microtape (DECtape) control Type 550
@ -51,6 +54,7 @@
#define STOP_XCT 4 /* nested XCT's */
#define STOP_IND 5 /* nested indirects */
#define STOP_WAIT 6 /* IO wait hang */
#define STOP_DTOFF 7 /* DECtape off reel */
/* Memory */
@ -92,6 +96,7 @@
#define IOS_V_SQB 11 /* sequence break */
#define IOS_V_PNT 2 /* print done */
#define IOS_V_SPC 1 /* space done */
#define IOS_V_DRP 0 /* parallel drum busy */
#define IOS_LPN (1 << IOS_V_LPN)
#define IOS_PTR (1 << IOS_V_PTR)
@ -102,6 +107,7 @@
#define IOS_SQB (1 << IOS_V_SQB)
#define IOS_PNT (1 << IOS_V_PNT)
#define IOS_SPC (1 << IOS_V_SPC)
#define IOS_DRP (1 << IOS_V_DRP)
/* Completion pulses */

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: PDP-1 Simulator Usage
Date: 15-Sep-2003
Date: 15-Dec-2003
COPYRIGHT NOTICE
@ -65,6 +65,7 @@ PTR,PTP integral paper tape reader/punch
TTY console typewriter
LPT Type 62 line printer
DRM Type 24 serial drum
DRP Type 23 parallel drum
DT Type 550 Microtape (DECtape)
The PDP-1 simulator implements the following unique stop conditions:
@ -77,6 +78,7 @@ The PDP-1 simulator implements the following unique stop conditions:
instruction execution
- I/O wait, and no I/O operations outstanding (i.e, no I/O
completion will ever occur)
- a simulated DECtape runs off the end of its reel
The PDP-1 loader supports RIM format tapes and BLK format tapes. If
the file to be loaded has an extension of .BIN, or switch -B is specified,
@ -302,7 +304,6 @@ The DECtape controller implements these registers:
BEF 1 block end flag
ERF 1 error flag
LTIME 31 time between lines
ACTIME 31 time to accelerate to full speed
DCTIME 31 time to decelerate to a full stop
SUBSTATE 2 read/write command substate
POS[0:7] 32 position, in lines, units 0-7
@ -313,10 +314,19 @@ among the DECtape parameters, or the DECtape simulator will fail to
operate correctly.
- LTIME must be at least 6
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
- DCTIME needs to be at least 100 times LTIME
2.4 Type 24 Serial Drum (DRM)
Acceleration time is set to 75% of deceleration time.
2.4 Drums
The PDP-1 supported two drums: the Type 23 parallel drum (DRP) and
the Type 24 serial drum (DRM). Both use device addresses 061-064;
accordingly, only one can be enabled at a time. By default, the
Type 24 serial drum is enabled, and the Type 23 parallel drum is
disabled.
2.4.1 Type 24 Serial Drum (DRM)
The serial drum (DRM) implements these registers:
@ -324,7 +334,6 @@ The serial drum (DRM) implements these registers:
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
@ -341,6 +350,35 @@ Error handling is as follows:
Drum data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.4.2 Type 23 Parallel Drum (DRP)
The parallel drum (DRP) implements these registers:
name size comments
TA 12 track address
RDF 5 read field
RDE 1 read enable flag
WRF 5 write field
WRF 1 write enable flag
MA 16 current memory address
WC 12 word count
BUSY 1 device busy flag
ERR 1 error flag
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

View file

@ -23,8 +23,12 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
drp Type 23 parallel drum
drm Type 24 serial drum
08-Dec-03 RMS Added parallel drum support
Fixed bug in DBL/DCN decoding
26-Oct-03 RMS Cleaned up buffer copy code
23-Jul-03 RMS Fixed incorrect logical, missing activate
05-Dec-02 RMS Cloned from pdp18b_drm.c
*/
@ -32,21 +36,36 @@
#include "pdp1_defs.h"
#include <math.h>
/* Constants */
/* Serial drum 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_SIZE (DRM_NUMTR * DRM_NUMWDT) /* words/drum */
#define DRM_SMASK ((DRM_NUMTR * DRM_NUMSC) - 1) /* sector mask */
/* Parallel drum constants */
#define DRP_NUMWDT 4096 /* words/track */
#define DRP_NUMTK 32 /* tracks/drum */
#define DRP_SIZE (DRP_NUMWDT * DRP_NUMTK) /* words/drum */
#define DRP_V_RWE 17 /* read/write enable */
#define DRP_V_FLD 12 /* drum field */
#define DRP_M_FLD 037
#define DRP_TAMASK 07777 /* track address */
#define DRP_WCMASK 07777 /* word count */
#define DRP_MAINCM 07777 /* mem addr incr */
#define DRP_GETRWE(x) (((x) >> DRP_V_RWE) & 1)
#define DRP_GETRWF(x) (((x) >> DRP_V_FLD) & DRP_M_FLD)
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
#define DRM_READ 000 /* read */
#define DRM_WRITE 010 /* write */
#define DRP_RW 000 /* read/write */
#define DRP_BRK 001 /* break on address */
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DRM_NUMWDT)))
@ -56,15 +75,34 @@ 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 */
/* Serial drum variables */
uint32 drm_da = 0; /* track address */
uint32 drm_ma = 0; /* memory address */
uint32 drm_err = 0; /* error flag */
uint32 drm_wlk = 0; /* write lock */
int32 drm_time = 4; /* inter-word time */
int32 drm_stopioe = 1; /* stop on error */
/* Parallel drum variables */
uint32 drp_rde = 0; /* read enable */
uint32 drp_wre = 0; /* write enable */
uint32 drp_rdf = 0; /* read field */
uint32 drp_wrf = 0; /* write field */
uint32 drp_ta = 0; /* track address */
uint32 drp_wc = 0; /* word count */
uint32 drp_ma = 0; /* memory address */
uint32 drp_err = 0; /* error */
int32 drp_time = 2; /* inter-word time */
int32 drp_stopioe = 1; /* stop on error */
/* Forward declarations */
t_stat drm_svc (UNIT *uptr);
t_stat drm_reset (DEVICE *dptr);
t_stat drp_svc (UNIT *uptr);
t_stat drp_reset (DEVICE *dptr);
/* DRM data structures
@ -93,6 +131,38 @@ DEVICE drm_dev = {
NULL, NULL, &drm_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE };
/* DRP data structures
drp_dev DRP device descriptor
drp_unit DRP unit descriptor
drp_reg DRP register list
*/
UNIT drp_unit =
{ UDATA (&drp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
DRM_SIZE) };
REG drp_reg[] = {
{ ORDATA (TA, drp_ta, 12) },
{ ORDATA (RDF, drp_rdf, 5) },
{ FLDATA (RDE, drp_rde, 0) },
{ FLDATA (WRF, drp_wrf, 5) },
{ FLDATA (WRE, drp_wre, 0) },
{ ORDATA (MA, drp_ma, 16) },
{ ORDATA (WC, drp_wc, 12) },
{ FLDATA (BUSY, iosta, IOS_V_DRP) },
{ FLDATA (ERR, drp_err, 0) },
{ DRDATA (TIME, drp_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, drp_stopioe, 0) },
{ NULL } };
DEVICE drp_dev = {
"DRP", &drp_unit, drp_reg, NULL,
1, 8, 20, 1, 8, 18,
NULL, NULL, &drp_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE | DEV_DIS };
/* IOT routines */
@ -101,39 +171,77 @@ int32 drm (int32 IR, int32 dev, int32 dat)
int32 t;
int32 pulse = (IR >> 6) & 037;
if (drm_dev.flags & DEV_DIS) /* disabled? */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
if ((pulse != 001) && (pulse != 011)) /* invalid pulse? */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
switch (dev) { /* switch on device */
case 061: /* DWR, DRD */
drm_ma = dat & 0177777; /* load mem addr */
drm_unit.FUNC = pulse & DRM_WRITE; /* save function */
break;
case 062: /* DBL, DCN */
if (pulse & 010) drm_da = dat & DRM_SMASK; /* load sector # */
iosta = iosta & ~IOS_DRM; /* clear flags */
drm_err = 0;
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t <= 0) t = t + DRM_NUMWDT; /* wrap around? */
sim_activate (&drm_unit, t); /* start operation */
break;
case 063: /* DTD */
if (pulse == 011) return (stop_inst << IOT_V_REASON) | dat;
if (iosta & IOS_DRM) return (dat | IOT_SKP); /* skip if done */
break;
case 064: /* DSE, DSP */
if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
return (dat | IOT_SKP);
}
return dat;
if ((drm_dev.flags & DEV_DIS) == 0) { /* serial enabled? */
if ((pulse != 001) && (pulse != 011)) /* invalid pulse? */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
switch (dev) { /* switch on device */
case 061: /* DWR, DRD */
drm_ma = dat & AMASK; /* load mem addr */
drm_unit.FUNC = pulse & DRM_WRITE; /* save function */
break;
case 062: /* DBL, DCN */
if ((pulse & 010) == 0) /* DBL? */
drm_da = dat & DRM_SMASK; /* load sector # */
iosta = iosta & ~IOS_DRM; /* clear flags */
drm_err = 0;
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t <= 0) t = t + DRM_NUMWDT; /* wrap around? */
sim_activate (&drm_unit, t); /* start operation */
break;
case 063: /* DTD */
if (pulse == 011) return (stop_inst << IOT_V_REASON) | dat;
if (iosta & IOS_DRM) return (dat | IOT_SKP); /* skip if done */
break;
case 064: /* DSE, DSP */
if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
return (dat | IOT_SKP);
} /* end case */
return dat; } /* end if serial */
if ((drp_dev.flags & DEV_DIS) == 0) { /* parallel enabled? */
switch (dev) { /* switch on device */
case 061: /* DIA, DBA */
drp_err = 0; /* clear error */
iosta = iosta & ~IOS_DRP; /* not busy */
drp_rde = DRP_GETRWE (dat); /* set read enable */
drp_rdf = DRP_GETRWF (dat); /* set read field */
drp_ta = dat & DRP_TAMASK; /* set track addr */
if (IR & 02000) { /* DBA? */
t = drp_ta - GET_POS (drp_time); /* delta words */
if (t <= 0) t = t + DRP_NUMWDT; /* wrap around? */
sim_activate (&drp_unit, t); /* start operation */
drp_unit.FUNC = DRP_BRK; } /* mark as break */
else drp_unit.FUNC = DRP_RW; /* no, read/write */
break;
case 062: /* DWC, DRA */
if (IR & 02000) dat = GET_POS (drp_time) | /* DRA, get position */
(drp_err? 0400000: 0);
else { /* DWC */
drp_wre = DRP_GETRWE (dat); /* set write enable */
drp_wrf = DRP_GETRWF (dat); /* set write field */
drp_wc = dat & DRP_WCMASK; } /* set word count */
break;
case 063: /* DCL */
drp_ma = dat & AMASK; /* set mem address */
t = drp_ta - GET_POS (drp_time); /* delta words */
if (t <= 0) t = t + DRP_NUMWDT; /* wrap around? */
sim_activate (&drp_unit, t); /* start operation */
iosta = iosta | IOS_DRP; /* set busy */
break;
case 064: /* not assigned */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
} /* end case */
return dat; } /* end if parallel */
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
}
/* Unit service - this code assumes the entire drum is buffered */
/* Serial unit service - this code assumes the entire drum is buffered */
t_stat drm_svc (UNIT *uptr)
{
uint32 i, da;
uint32 *fbuf = uptr->filebuf;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */
@ -143,15 +251,15 @@ if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
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 (uptr->FUNC == DRM_READ) { /* read? */
if (MEM_ADDR_OK (drm_ma)) /* if !nxm */
M[drm_ma] = fbuf[da]; } /* read word */
else { /* write */
if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1;
else {
*(((int32 *) uptr->filebuf) + da) = M[drm_ma];
else { /* not locked */
fbuf[da] = M[drm_ma]; /* write word */
if (da >= uptr->hwmark) uptr->hwmark = da + 1; } }
drm_ma = (drm_ma + 1) & 0177777; } /* incr mem addr */
drm_ma = (drm_ma + 1) & AMASK; } /* 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 */
@ -162,8 +270,57 @@ return SCPE_OK;
t_stat drm_reset (DEVICE *dptr)
{
if ((drm_dev.flags & DEV_DIS) == 0)
drp_dev.flags = drp_dev.flags | DEV_DIS;
drm_da = drm_ma = drm_err = 0;
iosta = iosta & ~IOS_DRM;
sim_cancel (&drm_unit);
drm_unit.FUNC = 0;
return SCPE_OK;
}
/* Parallel unit service - this code assumes the entire drum is buffered */
t_stat drp_svc (UNIT *uptr)
{
uint32 i, lim;
uint32 *fbuf = uptr->filebuf;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drp_err = 1; /* set error */
iosta = iosta & ~IOS_DRP; /* clear busy */
if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */
return IORETURN (drp_stopioe, SCPE_UNATT); }
if (uptr->FUNC == DRP_RW) { /* read/write? */
lim = drp_wc? drp_wc: DRP_TAMASK + 1; /* eff word count */
for (i = 0; i < lim; i++) { /* do transfer */
if (drp_wre) /* write enabled? */
fbuf[(drp_wrf << DRP_V_FLD) | drp_ta] = M[drp_ma];
if (drp_rde && MEM_ADDR_OK (drp_ma)) /* read enabled? */
M[drp_ma] = fbuf[(drp_rdf << DRP_V_FLD) | drp_ta];
drp_ta = (drp_ta + 1) & DRP_TAMASK; /* incr track addr */
drp_ma = ((drp_ma & ~DRP_MAINCM) | ((drp_ma + 1) & DRP_MAINCM));
} /* end for */
} /* end if */
iosta = iosta & ~IOS_DRP; /* clear busy */
if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */
return SCPE_OK;
}
/* Reset routine */
t_stat drp_reset (DEVICE *dptr)
{
if ((drp_dev.flags & DEV_DIS) == 0)
drm_dev.flags = drm_dev.flags | DEV_DIS;
drp_ta = 0;
drp_rde = drp_rdf = drp_wre = drp_wrf = 0;
drp_err = 0;
drp_ma = 0;
drp_wc = 0;
iosta = iosta & ~IOS_DRP;
sim_cancel (&drp_unit);
drp_unit.FUNC = 0;
return SCPE_OK;
}

View file

@ -25,6 +25,8 @@
dt Type 550/555 DECtape
26-Oct-03 RMS Cleaned up buffer copy code
18-Oct-03 RMS Added DECtape off reel message, simplified timing
25-Apr-03 RMS Revised for extended file support
14-Mar-03 RMS Fixed variable size interaction with save/restore
17-Oct-02 RMS Fixed bug in end of reel logic
@ -41,13 +43,16 @@
When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format.
DECtape motion is measured in 3b lines. Time between lines is 33.33us.
Tape density is nominally 300 lines per inch. The format of a DECtape is
Tape density is nominally 300 lines per inch. The format of a DECtape (as
taken from the TD8E formatter) is:
reverse end zone 36000 lines ~ 10 feet
reverse end zone 8192 reverse end zone codes ~ 10 feet
reverse buffer 200 interblock codes
block 0
:
block n
forward end zone 36000 lines ~ 10 feet
forward buffer 200 interblock codes
forward end zone 8192 forward end zone codes ~ 10 feet
A block consists of five 18b header words, a tape-specific number of data
words, and five 18b trailer words. All systems except the PDP-8 use a
@ -64,9 +69,9 @@
header word 0 0
header word 1 block number (for forward reads)
header words 2,3 0
header word 4 0
header word 4 checksum (for reverse reads)
:
trailer word 4 checksum
trailer word 4 checksum (for forward reads)
trailer words 3,2 0
trailer word 1 block number (for reverse reads)
trailer word 0 0
@ -97,13 +102,15 @@
/* System independent DECtape constants */
#define DT_EZLIN 36000 /* end zone length */
#define DT_HTLIN 30 /* header/trailer lines */
#define DT_BLKLN 6 /* blk no line in h/t */
#define DT_CSMLN 24 /* checksum line in h/t */
#define DT_HTWRD (DT_HTLIN / DT_WSIZE) /* header/trailer words */
#define DT_BLKWD (DT_BLKLN / DT_WSIZE) /* blk no word in h/t */
#define DT_CSMWD (DT_CSMLN / DT_WSIZE) /* checksum word in h/t */
#define DT_LPERMC 6 /* lines per mark track */
#define DT_BLKWD 1 /* blk no word in h/t */
#define DT_CSMWD 4 /* checksum word in h/t */
#define DT_HTWRD 5 /* header/trailer words */
#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */
#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */
#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */
#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */
#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */
/* 16b, 18b, 36b DECtape constants */
@ -249,8 +256,7 @@ int32 dtsa = 0; /* status A */
int32 dtsb = 0; /* status B */
int32 dtdb = 0; /* data buffer */
int32 dt_ltime = 12; /* interline time */
int32 dt_actime = 54000; /* accel time */
int32 dt_dctime = 72000; /* decel time */
int32 dt_dctime = 40000; /* decel time */
int32 dt_substate = 0;
int32 dt_log = 0;
int32 dt_logblk = 0;
@ -306,7 +312,6 @@ REG dt_reg[] = {
{ FLDATA (BEF, dtsb, DTB_V_BEF) },
{ FLDATA (ERF, dtsb, DTB_V_ERF) },
{ DRDATA (LTIME, dt_ltime, 31), REG_NZ },
{ DRDATA (ACTIME, dt_actime, 31), REG_NZ },
{ DRDATA (DCTIME, dt_dctime, 31), REG_NZ },
{ ORDATA (SUBSTATE, dt_substate, 2) },
{ ORDATA (LOG, dt_log, 4), REG_HIDDEN },
@ -441,7 +446,7 @@ if ((prev_mving | new_mving) == 0) return; /* stop to stop */
if (new_mving & ~prev_mving) { /* start? */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* stop current */
sim_activate (uptr, dt_actime); /* schedule accel */
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
return; }
@ -467,7 +472,7 @@ if (prev_dir ^ new_dir) { /* dir chg? */
if (prev_mot < DTS_ACCF) { /* not accel/at speed? */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* cancel cur */
sim_activate (uptr, dt_actime); /* schedule accel */
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
return; }
@ -588,11 +593,13 @@ case DTS_STOP: /* stop */
delta = 0;
break;
case DTS_DECF: /* slowing */
ulin = ut / (uint32) dt_ltime; udelt = dt_dctime / dt_ltime;
ulin = ut / (uint32) dt_ltime;
udelt = dt_dctime / dt_ltime;
delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
break;
case DTS_ACCF: /* accelerating */
ulin = ut / (uint32) dt_ltime; udelt = dt_actime / dt_ltime;
ulin = ut / (uint32) dt_ltime;
udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime;
delta = (ulin * ulin) / (2 * udelt);
break;
case DTS_ATSF: /* at speed */
@ -621,7 +628,7 @@ t_stat dt_svc (UNIT *uptr)
int32 mot = DTS_GETMOT (uptr->STATE);
int32 dir = mot & DTS_DIR;
int32 fnc = DTS_GETFNC (uptr->STATE);
int32 *bptr = uptr->filebuf;
int32 *fbuf = uptr->filebuf;
int32 unum = uptr - dt_dev.units;
int32 blk, wrd, ma, relpos;
uint32 ba;
@ -635,10 +642,10 @@ uint32 ba;
switch (mot) {
case DTS_DECF: case DTS_DECR: /* decelerating */
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */
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_dctime - (dt_dctime >> 2)); /* reversing */
return SCPE_OK;
case DTS_ACCF: case DTS_ACCR: /* accelerating */
dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
@ -656,7 +663,7 @@ default: /* other */
Off reel - detach unit (it must be deselected)
*/
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */
if (DT_QEZ (uptr)) { /* in end zone? */
dt_seterr (uptr, DTB_END); /* end zone error */
return SCPE_OK; }
@ -693,7 +700,7 @@ case FNC_READ: case FNC_RALL:
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
dtdb = bptr[ba]; /* get tape word */
dtdb = fbuf[ba]; /* get tape word */
dtsb = dtsb | DTB_DTF; } /* set flag */
else {
ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1;
@ -722,8 +729,8 @@ case FNC_WRIT: case FNC_WALL:
(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 (dir) fbuf[ba] = dt_comobv (dtdb); /* get data word */
else fbuf[ba] = dtdb;
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1))
dtsb = dtsb | DTB_BEF; /* end block */
@ -791,13 +798,13 @@ return dat;
int32 dt_csum (UNIT *uptr, int32 blk)
{
int32 *bptr = uptr->filebuf;
int32 *fbuf = uptr->filebuf;
int32 ba = blk * DTU_BSIZE (uptr);
int32 i, csum, wrd;
csum = 0777777;
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
wrd = bptr[ba + i]; /* get word */
wrd = fbuf[ba + i]; /* get word */
csum = csum + wrd; /* 1's comp add */
if (csum > 0777777) csum = (csum + 1) & 0777777; }
return (csum ^ 0777777); /* 1's comp res */
@ -868,7 +875,7 @@ t_stat dt_attach (UNIT *uptr, char *cptr)
{
uint16 pdp8b[D8_NBSIZE];
uint16 pdp11b[D18_BSIZE];
uint32 ba, sz, k, *bptr;
uint32 ba, sz, k, *fbuf;
int32 u = uptr - dt_dev.units;
t_stat r;
@ -891,7 +898,7 @@ uptr->filebuf = calloc (uptr->capac, sizeof (int32));
if (uptr->filebuf == NULL) { /* can't alloc? */
detach_unit (uptr);
return SCPE_MEM; }
bptr = uptr->filebuf; /* file buffer */
fbuf = uptr->filebuf; /* file buffer */
printf ("%s%d: ", sim_dname (&dt_dev), u);
if (uptr->flags & UNIT_8FMT) printf ("12b format");
else if (uptr->flags & UNIT_11FMT) printf ("16b format");
@ -903,9 +910,9 @@ if (uptr->flags & UNIT_8FMT) { /* 12b? */
if (k == 0) break;
for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0;
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */
bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
fbuf[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
((uint32) (pdp8b[k + 1] >> 6) & 077);
bptr[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) |
fbuf[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) |
(pdp8b[k + 2] & 07777);
ba = ba + 2; } /* end blk loop */
} /* end file loop */
@ -916,7 +923,7 @@ else if (uptr->flags & UNIT_11FMT) { /* 16b? */
if (k == 0) break;
for ( ; k < D18_BSIZE; k++) pdp11b[k] = 0;
for (k = 0; k < D18_BSIZE; k++)
bptr[ba++] = pdp11b[k]; }
fbuf[ba++] = pdp11b[k]; }
uptr->hwmark = ba; } /* end elif */
else uptr->hwmark = fxread (uptr->filebuf, sizeof (int32),
uptr->capac, uptr->fileref);
@ -939,27 +946,27 @@ t_stat dt_detach (UNIT* uptr)
{
uint16 pdp8b[D8_NBSIZE];
uint16 pdp11b[D18_BSIZE];
uint32 ba, k, *bptr;
uint32 ba, k, *fbuf;
int32 u = uptr - dt_dev.units;
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
if (sim_is_active (uptr)) {
sim_cancel (uptr);
if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) {
dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
DT_UPDINT; }
uptr->STATE = uptr->pos = 0; }
bptr = uptr->filebuf; /* file buffer */
fbuf = uptr->filebuf; /* file buffer */
if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u);
rewind (uptr->fileref); /* start of file */
if (uptr->flags & UNIT_8FMT) { /* 12b? */
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */
pdp8b[k] = (bptr[ba] >> 6) & 07777;
pdp8b[k + 1] = ((bptr[ba] & 077) << 6) |
((bptr[ba + 1] >> 12) & 077);
pdp8b[k + 2] = bptr[ba + 1] & 07777;
pdp8b[k] = (fbuf[ba] >> 6) & 07777;
pdp8b[k + 1] = ((fbuf[ba] & 077) << 6) |
((fbuf[ba + 1] >> 12) & 077);
pdp8b[k + 2] = fbuf[ba + 1] & 07777;
ba = ba + 2; } /* end loop blk */
fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref);
if (ferror (uptr->fileref)) break; } /* end loop file */
@ -967,7 +974,7 @@ if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
else if (uptr->flags & UNIT_11FMT) { /* 16b? */
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
for (k = 0; k < D18_BSIZE; k++) /* loop blk */
pdp11b[k] = bptr[ba++] & 0177777;
pdp11b[k] = fbuf[ba++] & 0177777;
fxwrite (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref);
if (ferror (uptr->fileref)) break; } /* end loop file */
} /* end if 16b */

View file

@ -143,27 +143,27 @@ if (cpls & CPLS_LPT) { /* completion pulse? */
sbs = sbs | SB_RQ; /* req seq break */
if (lpt_spc) { /* space? */
iosta = iosta | IOS_SPC; /* set flag */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
fputs (lpt_cc[lpt_spc & 07], lpt_unit.fileref); /* print cctl */
if (ferror (lpt_unit.fileref)) { /* error? */
fputs (lpt_cc[lpt_spc & 07], uptr->fileref); /* print cctl */
if (ferror (uptr->fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
clearerr (uptr->fileref);
return SCPE_IOERR; }
lpt_ovrpr = 0; } /* dont overprint */
else { iosta = iosta | IOS_PNT; /* print */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
if (lpt_ovrpr) fputc ('\r', lpt_unit.fileref); /* overprint? */
fputs (lpt_buf, lpt_unit.fileref); /* print buffer */
if (ferror (lpt_unit.fileref)) { /* test error */
if (lpt_ovrpr) fputc ('\r', uptr->fileref); /* overprint? */
fputs (lpt_buf, uptr->fileref); /* print buffer */
if (ferror (uptr->fileref)) { /* test error */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
clearerr (uptr->fileref);
return SCPE_IOERR; }
lpt_bptr = 0;
for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
lpt_ovrpr = 1; } /* set overprint */
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
lpt_unit.pos = ftell (uptr->fileref); /* update position */
return SCPE_OK;
}

View file

@ -28,6 +28,7 @@
tti keyboard
tto teleprinter
29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (from Phil Budne)
07-Sep-03 RMS Changed ioc to ios
30-Aug-03 RMS Revised PTR to conform to Maintenance Manual;
added deadlock prevention on errors
@ -42,10 +43,14 @@
07-Sep-01 RMS Moved function prototypes
10-Jun-01 RMS Fixed comment
30-Oct-00 RMS Standardized device naming
Note: PTP timeout must be >10X faster that TTY output timeout for Macro
to work correctly!
*/
#include "pdp1_defs.h"
#define FIODEC_STOP 013 /* stop code */
#define FIODEC_UC 074
#define FIODEC_LC 072
#define UC_V 6 /* upper case */
@ -55,10 +60,16 @@
#define TT_WIDTH 077
#define TTI 0
#define TTO 1
#define UNIT_V_ASCII (UNIT_V_UF + 0) /* ASCII/binary mode */
#define UNIT_ASCII (1 << UNIT_V_ASCII)
#define PTR_LEADER 20 /* ASCII leader chars */
int32 ptr_state = 0;
int32 ptr_wait = 0;
int32 ptr_stopioe = 0;
int32 ptr_uc = 0; /* upper/lower case */
int32 ptr_hold = 0; /* holding buffer */
int32 ptr_leader = PTR_LEADER; /* leader count */
int32 ptp_stopioe = 0;
int32 tti_hold = 0; /* tti hold buf */
int32 tty_buf = 0; /* tty buffer */
@ -68,6 +79,7 @@ extern int32 sbs, ios, ioh, cpls, iosta;
extern int32 PF, IO, PC, TA;
extern int32 M[];
int ptr_get_ascii (UNIT *uptr);
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat tti_svc (UNIT *uptr);
@ -76,6 +88,7 @@ t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_reset (DEVICE *dptr);
t_stat tty_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
t_stat ptr_attach (UNIT *uptr, char *cptr);
/* Character translation tables */
@ -128,20 +141,28 @@ UNIT ptr_unit = {
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 18) },
{ FLDATA (UC, ptr_uc, UC_V) },
{ FLDATA (DONE, iosta, IOS_V_PTR) },
{ FLDATA (RPLS, cpls, CPLS_V_PTR) },
{ ORDATA (HOLD, ptr_hold, 9), REG_HRO },
{ ORDATA (STATE, ptr_state, 5), REG_HRO },
{ FLDATA (WAIT, ptr_wait, 0), REG_HRO },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ DRDATA (LEADER, ptr_leader, 6), REG_HRO },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ NULL } };
MTAB ptr_mod[] = {
{ UNIT_ASCII, UNIT_ASCII, "ASCII", "ASCII", NULL },
{ UNIT_ASCII, 0, "FIODEC", "FIODEC", NULL },
{ 0 } };
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
"PTR", &ptr_unit, ptr_reg, ptr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
&ptr_boot, NULL, NULL,
&ptr_boot, &ptr_attach, NULL,
NULL, 0 };
/* PTP data structures
@ -179,7 +200,7 @@ DEVICE ptp_dev = {
UNIT tty_unit[] = {
{ UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT } };
{ UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 } };
REG tty_reg[] = {
{ ORDATA (BUF, tty_buf, 6) },
@ -240,35 +261,74 @@ t_stat ptr_svc (UNIT *uptr)
{
int32 temp;
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
if (ptr_wait) ptr_wait = ioh = 0; /* if wait, clr ioh */
if ((cpls & CPLS_PTR) || ptr_stopioe) return SCPE_UNATT;
return SCPE_OK; }
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
if ((uptr->flags & UNIT_ASCII) && (ptr_state == 0)) /* ASCII mode, alpha read? */
temp = ptr_get_ascii (uptr); /* get processed char */
else if ((temp = getc (uptr->fileref)) != EOF) /* no, get raw char */
uptr->pos = uptr->pos + 1; /* if not eof, count */
if (temp == EOF) { /* end of file? */
if (ptr_wait) ptr_wait = ioh = 0; /* if wait, clr ioh */
if (feof (ptr_unit.fileref)) {
if (feof (uptr->fileref)) {
if ((cpls & CPLS_PTR) || ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
clearerr (uptr->fileref);
return SCPE_IOERR; }
ptr_unit.pos = ptr_unit.pos + 1;
if (ptr_state == 0) ptr_unit.buf = temp & 0377; /* alpha */
if (ptr_state == 0) uptr->buf = temp & 0377; /* alpha */
else if (temp & 0200) { /* binary */
ptr_state = ptr_state - 6;
ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); }
uptr->buf = uptr->buf | ((temp & 077) << ptr_state); }
if (ptr_state == 0) { /* done? */
if (cpls & CPLS_PTR) { /* completion pulse? */
iosta = iosta & ~IOS_PTR; /* clear flag */
IO = ptr_unit.buf; /* fill IO */
IO = uptr->buf; /* fill IO */
ios = 1; /* restart */
cpls = cpls & ~CPLS_PTR; }
else { /* no, interrupt */
iosta = iosta | IOS_PTR; /* set flag */
sbs = sbs | SB_RQ; } } /* req seq break */
else sim_activate (&ptr_unit, ptr_unit.wait); /* get next char */
else sim_activate (uptr, uptr->wait); /* get next char */
return SCPE_OK;
}
/* Read next ASCII character */
int ptr_get_ascii (UNIT *uptr)
{
int c;
int32 in;
if (ptr_leader > 0) { /* leader? */
ptr_leader = ptr_leader - 1; /* count down */
return 0; }
if (ptr_hold & CW) { /* char waiting? */
in = ptr_hold & TT_WIDTH; /* return char */
ptr_hold = 0; } /* not waiting */
else { for (;;) { /* until valid char */
if ((c = getc (uptr->fileref)) == EOF) /* get next char, EOF? */
return FIODEC_STOP; /* return STOP */
uptr->pos = uptr->pos + 1; /* count char */
c = c & 0177; /* cut to 7b */
if (c == '\n') c = '\r'; /* NL -> CR */
else if (c == '\r') continue; /* ignore CR */
in = ascii_to_fiodec[c]; /* convert char */
if ((in == 0) && (c != ' ')) continue; /* ignore unknowns */
if ((in & BOTH) || ((in & UC) == ptr_uc)) /* case match? */
in = in & TT_WIDTH; /* cut to 6b */
else { /* no, case shift */
ptr_hold = in | CW; /* set char waiting */
ptr_uc = in & UC; /* set case */
in = ptr_uc? FIODEC_UC: FIODEC_LC; } /* return case */
break; }
} /* end else */
in = in * 010040201; /* even parity from */
in = in | 027555555400; /* HACKMEM 167 */
in = in % (9 << 7);
return in & 0377;
}
/* Reset routine */
@ -276,6 +336,8 @@ t_stat ptr_reset (DEVICE *dptr)
{
ptr_state = 0; /* clear state */
ptr_wait = 0;
ptr_hold = 0;
ptr_uc = 0;
ptr_unit.buf = 0;
cpls = cpls & ~CPLS_PTR;
iosta = iosta & ~IOS_PTR; /* clear flag */
@ -283,6 +345,14 @@ sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
}
/* Attach routine */
t_stat ptr_attach (UNIT *uptr, char *cptr)
{
ptr_leader = PTR_LEADER; /* set up leader */
return attach_unit (uptr, cptr);
}
/* Bootstrap routine */
int32 ptr_getw (UNIT *uptr)
@ -341,13 +411,13 @@ if (cpls & CPLS_PTP) { /* completion pulse? */
cpls = cpls & ~CPLS_PTP; }
iosta = iosta | IOS_PTP; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */
if (putc (uptr->buf, uptr->fileref) == EOF) { /* I/O error? */
perror ("PTP I/O error");
clearerr (ptp_unit.fileref);
clearerr (uptr->fileref);
return SCPE_IOERR; }
ptp_unit.pos = ptp_unit.pos + 1;
uptr->pos = uptr->pos + 1;
return SCPE_OK;
}
@ -417,24 +487,22 @@ return SCPE_OK;
t_stat tto_svc (UNIT *uptr)
{
int32 out;
int32 c;
t_stat r;
if (tty_buf == FIODEC_UC) tty_uc = UC; /* upper case? */
else if (tty_buf == FIODEC_LC) tty_uc = 0; /* lower case? */
else { c = fiodec_to_ascii[tty_buf | tty_uc]; /* translate */
if (c && ((r = sim_putchar_s (c)) != SCPE_OK)) {/* output; error? */
sim_activate (uptr, uptr->wait); /* retry */
return ((r == SCPE_STALL)? SCPE_OK: r); } }
if (cpls & CPLS_TTO) { /* completion pulse? */
ios = 1; /* restart */
cpls = cpls & ~CPLS_TTO; }
iosta = iosta | IOS_TTO; /* set flag */
sbs = sbs | SB_RQ; /* req seq break */
if (tty_buf == FIODEC_UC) { /* upper case? */
tty_uc = UC;
return SCPE_OK; }
if (tty_buf == FIODEC_LC) { /* lower case? */
tty_uc = 0;
return SCPE_OK; }
out = fiodec_to_ascii[tty_buf | tty_uc]; /* translate */
if (out == 0) return SCPE_OK; /* no translation? */
sim_putchar (out);
uptr->pos = uptr->pos + 1;
if (out == '\r') { /* cr? add lf */
if (c == '\r') { /* cr? add lf */
sim_putchar ('\n');
uptr->pos = uptr->pos + 1; }
return SCPE_OK;

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
08-Dec-03 RMS Added parallel drum support, drum mnemonics
18-Oct-03 RMS Added DECtape off reel message
01-Sep-03 RMS Added support for loading in multiple fields
22-Jul-03 RMS Updated for "hardware" RIM loader
05-Dec-02 RMS Added drum support
@ -48,6 +50,7 @@ extern DEVICE tty_dev;
extern DEVICE lpt_dev;
extern DEVICE dt_dev;
extern DEVICE drm_dev;
extern DEVICE drp_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern int32 M[];
@ -80,6 +83,7 @@ DEVICE *sim_devices[] = {
&lpt_dev,
&dt_dev,
&drm_dev,
&drp_dev,
NULL };
const char *sim_stop_messages[] = {
@ -89,11 +93,12 @@ const char *sim_stop_messages[] = {
"Breakpoint",
"Nested XCT's",
"Nested indirect addresses",
"Infinite I/O wait state" };
"Infinite I/O wait state",
"DECtape off reel" };
/* Binary loader - supports both RIM format and Macro block format */
int32 getw (FILE *inf)
int32 pdp1_getw (FILE *inf)
{
int32 i, tmp, word;
@ -111,11 +116,11 @@ t_stat rim_load (FILE *inf, int32 fld)
int32 origin, val;
for (;;) {
if ((val = getw (inf)) < 0) return SCPE_FMT;
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT;
if (((val & 0760000) == OP_DIO) || /* DIO? */
((val & 0760000) == OP_DAC)) { /* hack - Macro1 err */
origin = val & DAMASK;
if ((val = getw (inf)) < 0) return SCPE_FMT;
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT;
M[fld | origin] = val; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */
PC = fld | (val & DAMASK);
@ -130,23 +135,23 @@ t_stat blk_load (FILE *inf, int32 fld)
int32 val, start, count, csum;
for (;;) {
if ((val = getw (inf)) < 0) return SCPE_FMT; /* get word, EOF? */
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT; /* get word, EOF? */
if ((val & 0760000) == OP_DIO) { /* DIO? */
csum = val; /* init checksum */
start = val & DAMASK; /* starting addr */
if ((val = getw (inf)) < 0) return SCPE_FMT;
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT;
if ((val & 0760000) != OP_DIO) return SCPE_FMT;
csum = csum + val;
if (csum > 0777777) csum = (csum + 1) & 0777777;
count = (val & DAMASK) - start + 1; /* block count */
if (count <= 0) return SCPE_FMT;
while (count--) { /* loop on data */
if ((val = getw (inf)) < 0) return SCPE_FMT;
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT;
csum = csum + val;
if (csum > 0777777) csum = (csum + 1) & 0777777;
M[fld | start] = val;
start = (start + 1) & DAMASK; }
if ((val = getw (inf)) < 0) return SCPE_FMT;
if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT;
if (val != csum) return SCPE_CSUM; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */
PC = fld | (val & DAMASK);
@ -213,6 +218,9 @@ static const char *opcode[] = {
"LSM", "ESM", "CBS",
"LEM", "EEM", "CKS",
"MSE", "MLC", "MRD", "MWR", "MRS",
"DIA", "DBA", "DWC", "DRA", "DCL",
"DRD", "DWR", "DBL", "DCN",
"DTD", "DSE", "DSP",
"SKP", "SKP I", "CLO",
"SFT", "LAW", "OPR",
@ -265,6 +273,9 @@ static const int32 opc_val[] = {
0720054+I_NPN, 0720055+I_NPN, 0720056+I_NPN,
0720074+I_NPN, 0724074+I_NPN, 0720033+I_NPN,
0720301+I_NPN, 0720401+I_NPN, 0720501+I_NPN, 0720601+I_NPN, 0720701+I_NPN,
0720061+I_NPN, 0722061+I_NPN, 0720062+I_NPN, 0722062+I_NPN, 0720063+I_NPN,
0720161+I_NPN, 0721161+I_NPN, 0720162+I_NPN, 0721162+I_NPN,
0720163+I_NPN, 0720164+I_NPN, 0721164+I_NPN,
0640000+I_NPN, 0650000+I_NPN, 0651600+I_NPN,
0660000+I_NPN, 0700000+I_LAW, 0760000+I_NPN,

View file

@ -1,6 +1,6 @@
/* pdp10_defs.h: PDP-10 simulator definitions
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, 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.
29-Dec-03 RMS Added Q18 definition for PDP11 compatibility
19-May-03 RMS Revised for new conditional compilation scheme
09-Jan-03 RMS Added DEUNA/DELUA support
29-Sep-02 RMS Added variable vector, RX211 support
@ -609,9 +610,11 @@ typedef struct pdp_dib DIB;
#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */
#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */
#define DEV_V_FLTA (DEV_V_UF + 2) /* float addr */
#define DEV_V_Q18 (DEV_V_UF + 2) /* Qbus, mem <= 256KB */
#define DEV_V_FLTA (DEV_V_UF + 3) /* float addr */
#define DEV_UBUS (1u << DEV_V_UBUS)
#define DEV_QBUS (1u << DEV_V_QBUS)
#define DEV_Q18 (1u << DEV_V_Q18)
#define DEV_FLTA (1u << DEV_V_FLTA)
#define UNIBUS TRUE /* 18b only */

View file

@ -1,6 +1,6 @@
/* pdp10_fe.c: PDP-10 front end (console terminal) simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
fe KS10 console front end
29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support
30-May-02 RMS Widened COUNT to 32b
@ -108,9 +109,8 @@ void fe_intr (void)
{
if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */
feo_unit.buf = (int32) M[FE_CTYOUT] & 0177; /* pick it up */
sim_putchar (feo_unit.buf); /* type it */
feo_unit.pos = feo_unit.pos + 1;
sim_activate (&feo_unit, feo_unit.time); } /* sched completion */
sim_activate (&feo_unit, feo_unit.wait); } /* sched completion */
else if ((M[FE_CTYIN] & FE_CVALID) == 0) { /* input char taken? */
sim_cancel (&fei_unit); /* sched immediate */
sim_activate (&fei_unit, 0); }; /* keyboard poll */
@ -119,6 +119,11 @@ return;
t_stat feo_svc (UNIT *uptr)
{
t_stat r;
if ((r = sim_putchar_s (uptr->buf)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */
M[FE_CTYOUT] = 0; /* clear char */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK;

View file

@ -1,6 +1,6 @@
/* pdp10_lp20.c: PDP-10 LP20 line printer simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
lp20 line printer
29-Dec-03 RMS Fixed bug in scheduling
25-Apr-03 RMS Revised for extended file support
29-Sep-02 RMS Added variable vector support
Modified to use common Unibus routines
@ -283,7 +284,7 @@ case 00: /* LPCSA */
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); } }
sim_activate (&lp20_unit, lp20_unit.wait); } }
else sim_cancel (&lp20_unit); /* go clr, stop DMA */
lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW);
break;

View file

@ -1,6 +1,6 @@
/* pdp11_cpu.c: PDP-11 CPU simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
cpu PDP-11 CPU (J-11 microprocessor)
29-Dec-03 RMS Formalized 18b Qbus support
21-Dec-03 RMS Added autoconfiguration controls
05-Jun-03 RMS Fixed bugs in memory size table
12-Mar-03 RMS Added logical name support
01-Feb-03 RMS Changed R display to follow PSW<rs>, added SP display
@ -276,6 +278,7 @@ int32 stop_vecabort = 1; /* stop on vec abort */
int32 stop_spabort = 1; /* stop on SP abort */
int32 wait_enable = 0; /* wait state enable */
int32 cpu_log = 0; /* logging */
int32 autcon_enb = 1; /* autoconfig enable */
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
@ -323,6 +326,8 @@ void set_r_display (int32 rs, int32 cm);
extern t_stat build_dib_tab (int32 ubm);
extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc);
extern t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc);
extern t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc);
extern t_stat iopageR (int32 *data, uint32 addr, int32 access);
extern t_stat iopageW (int32 data, uint32 addr, int32 access);
extern int32 calc_ints (int32 nipl, int32 trq);
@ -532,6 +537,7 @@ REG cpu_reg[] = {
{ GRDATA (UDPAR7, APRFILE[077], 8, 16, 16) },
{ GRDATA (UDPDR7, APRFILE[077], 8, 16, 0) },
{ BRDATA (UBMAP, ub_map, 8, 22, UBM_LNT_LW) },
{ FLDATA (AUTOCON, autcon_enb, 0), REG_HRO },
{ BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC },
{ ORDATA (PCQP, pcq_p, 6), REG_HRO },
{ ORDATA (WRU, sim_int_char, 8) },
@ -539,10 +545,10 @@ REG cpu_reg[] = {
{ NULL} };
MTAB cpu_mod[] = {
{ UNIT_MAP, UNIT_18B, "18b addressing", "18B", NULL },
{ UNIT_MAP, UNIT_18B, "18b Unibus", "U18", &cpu_set_bus },
{ UNIT_MAP, UNIT_UBM, "22b Unibus + RH70", "URH70", &cpu_set_bus },
{ UNIT_MAP, UNIT_UBM + UNIT_RH11, "22b Unibus + RH11", "URH11", &cpu_set_bus },
{ UNIT_MAP, 0, "22b addressing", "22B", &cpu_set_bus },
{ UNIT_MAP, 0, "22b Qbus", "Q22", &cpu_set_bus },
{ UNIT_CIS, UNIT_CIS, "CIS", "CIS", NULL },
{ UNIT_CIS, 0, "no CIS", "NOCIS", NULL },
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size},
@ -566,6 +572,10 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 4186112, NULL, "4M", &cpu_set_size},
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
NULL, &show_iospace },
{ MTAB_XTD|MTAB_VDV, 1, "AUTOCONFIG", "AUTOCONFIG",
&set_autocon, &show_autocon },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOAUTOCONFIG",
&set_autocon, NULL },
{ 0 } };
DEVICE cpu_dev = {
@ -2467,23 +2477,24 @@ for (i = 0; i < clim; i = i + 2) nM[i >> 1] = M[i >> 1];
free (M);
M = nM;
MEMSIZE = val;
return cpu_set_bus (uptr, (cpu_unit.flags & UNIT_MAP) | 1, cptr, desc); }
return cpu_set_bus (uptr, cpu_unit.flags, cptr, desc); }
/* Bus configuration, disable Unibus or Qbus devices */
t_stat cpu_set_bus (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
uint32 i, target;
uint32 i, mask;
if ((MEMSIZE <= UNIMEMSIZE) || (val & UNIT_18B) ||
(!(val & 1) && ((uint32) val == (cpu_unit.flags & UNIT_MAP)))) return SCPE_OK;
if (val & UNIT_MAP) target = DEV_QBUS; /* going to Ubus? */
else target = DEV_UBUS; /* going to Qbus */
if ((val & UNIT_MAP) || (val & UNIT_18B)) /* Unibus variant? */
mask = DEV_UBUS;
else if (MEMSIZE <= UNIMEMSIZE) /* 18b Qbus? */
mask = DEV_QBUS | DEV_Q18;
else mask = DEV_QBUS; /* must be 22b */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
if ((dptr->flags & DEV_DISABLE) && /* disable-able? */
!(dptr->flags & DEV_DIS) && /* enabled? */
((dptr->flags & (DEV_QBUS|DEV_UBUS)) == target)) {
((dptr->flags & mask) == 0)) { /* not allowed? */
printf ("Disabling %s\n", sim_dname (dptr));
if (sim_log) fprintf (sim_log, "Disabling %s\n", sim_dname (dptr));
dptr->flags = dptr->flags | DEV_DIS; } }

View file

@ -26,6 +26,8 @@
The author gratefully acknowledges the help of Max Burnet, Megan Gentry,
and John Wilson in resolving questions about the PDP-11
22-Dec-03 RMS Added second DEUNA/DELUA support
18-Oct-03 RMS Added DECtape off reel message
19-May-03 RMS Revised for new conditional compilation
05-Apr-03 RMS Fixed bug in MMR1 update (found by Tim Stark)
28-Feb-03 RMS Added TM logging support
@ -295,6 +297,7 @@ typedef struct fpac fpac_t;
#define STOP_SPABORT (TRAP_V_MAX + 5) /* abort trap push */
#define STOP_RQ (TRAP_V_MAX + 6) /* RQDX3 panic */
#define STOP_SANITY (TRAP_V_MAX + 7) /* sanity timer exp */
#define STOP_DTOFF (TRAP_V_MAX + 8) /* DECtape off reel */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
/* Timers */
@ -312,9 +315,11 @@ typedef struct fpac fpac_t;
#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */
#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */
#define DEV_V_FLTA (DEV_V_UF + 2) /* flt addr */
#define DEV_V_Q18 (DEV_V_UF + 2) /* Qbus with <= 256KB */
#define DEV_V_FLTA (DEV_V_UF + 3) /* flt addr */
#define DEV_UBUS (1u << DEV_V_UBUS)
#define DEV_QBUS (1u << DEV_V_QBUS)
#define DEV_Q18 (1u << DEV_V_Q18)
#define DEV_FLTA (1u << DEV_V_FLTA)
#define UNIBUS (cpu_18b || cpu_ubm) /* T if 18b */
@ -341,11 +346,13 @@ struct pdp_dib {
typedef struct pdp_dib DIB;
/* I/O page layout - RQB,RQC,RQD float based on number of DZ's */
/* I/O page layout - XUB, RQB,RQC,RQD float based on number of DZ's */
#define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */
#define IOLN_DZ 010
#define IOBA_RQB (IOPAGEBASE + 000334 + (020 * (DZ_MUXES / 2)))
#define IOBA_XUB (IOPAGEBASE + 000330 + (020 * (DZ_MUXES / 2)))
#define IOLN_XUB 010
#define IOBA_RQB (IOPAGEBASE + 000334 + (020 * (DZ_MUXES / 2)))
#define IOLN_RQB 004
#define IOBA_RQC (IOPAGEBASE + IOBA_RQB + IOLN_RQB)
#define IOLN_RQC 004

View file

@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: PDP-11 Simulator Usage
Date: 15-Sep-2003
Date: 15-Dec-2003
COPYRIGHT NOTICE
@ -127,6 +127,7 @@ The PDP-11 simulator implements several unique stop conditions:
- trap condition 'n' occurs, and register STOP_TRAP<n> is set
- wait state entered, and no I/O operations outstanding
(ie, no interrupt can ever occur)
- a simulated DECtape runs off the end of its reel
The PDP-11 loader supports standard binary format tapes. The DUMP command
is not implemented.
@ -289,11 +290,13 @@ In addition to autoconfiguration, most devices support the SET ADDRESS
command, which allows the I/O page address of the device to be changed,
and the SET VECTOR command, which allows the vector of the device to be
changed. Explicitly setting the I/O address of a device which normally
uses autoconfiguration DISABLES autoconfiguration for that device. As
a consequence, the user may have to manually configure all other
autoconfigured devices, because the autoconfiguration algorithm no
longer recognizes the explicitly configured device. A device can be
reset to autoconfigure with the SET <device> AUTOCONFIGURE command.
uses autoconfiguration DISABLES autoconfiguration for that device and for
the entire system. As a consequence, the user may have to manually configure
all other autoconfigured devices, because the autoconfiguration algorithm
no longer recognizes the explicitly configured device. A device can be
reset to autoconfigure with the SET <device> AUTOCONFIGURE command. Auto-
configuration can be restored for the entire system with the SET CPU
AUTOCONFIGURE command.
The current I/O map can be displayed with the SHOW CPU IOSPACE command.
Addresses that have set by autoconfiguration are marked with an asterisk (*).
@ -994,7 +997,6 @@ The TC controller implements these registers:
IE 1 interrupt enable flag
CTIME 31 time to complete transport stop
LTIME 31 time between lines
ACTIME 31 time to accelerate to full speed
DCTIME 31 time to decelerate to a full stop
SUBSTATE 2 read/write command substate
POS[0:7] 32 position, in lines, units 0-7
@ -1005,8 +1007,9 @@ among the DECtape parameters, or the DECtape simulator will fail to
operate correctly.
- LTIME must be at least 6
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
- DCTIME needs to be at least 100 times LTIME
Acceleration time is set to 75% of deceleration time.
2.9 Magnetic Tape Controllers

View file

@ -25,6 +25,7 @@
hk RK611/RK06/RK07 disk
29-Dec-03 RMS Added 18b Qbus support
25-Apr-03 RMS Revised for extended file support
This is a somewhat abstracted implementation of the RK611, more closely
@ -438,7 +439,7 @@ DEVICE hk_dev = {
HK_NUMDR, HK_RDX, 24, 1, HK_RDX, HK_WID,
NULL, NULL, &hk_reset,
&hk_boot, &hk_attach, &hk_detach,
&hk_dib, DEV_DISABLE | DEV_UBUS };
&hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 };
/* I/O dispatch routines, I/O addresses 17777440 - 17777476 */

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls
21-Nov-03 RMS Added check for interrupt slot conflict (found by Dave Hittner)
12-Mar-03 RMS Added logical name support
08-Oct-02 RMS Trimmed I/O bus addresses
Added support for dynamic tables
@ -43,6 +45,7 @@ extern UNIT cpu_unit;
extern int32 cpu_bme, cpu_18b, cpu_ubm;
extern int32 trap_req, ipl;
extern int32 cpu_log;
extern int32 autcon_enb;
extern FILE *sim_log;
extern DEVICE *sim_devices[];
@ -297,6 +300,24 @@ else { /* physical */
return (lim - alim); }
}
/* Enable/disable autoconfiguration */
t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (cptr != NULL) return SCPE_ARG;
autcon_enb = val;
return auto_config (0, 0);
}
/* Show autoconfiguration status */
t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc)
{
fprintf (st, "autoconfiguration ");
fprintf (st, autcon_enb? "enabled": "disabled");
return SCPE_OK;
}
/* Change device address */
t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)
@ -318,7 +339,8 @@ if ((newba <= IOPAGEBASE) || /* > IO page base? */
(newba % ((uint32) val))) return SCPE_ARG; /* check modulus */
dibp->ba = newba; /* store */
dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */
return auto_config (0, 0); /* autoconfigure */
autcon_enb = 0; /* autoconfig off */
return SCPE_OK;
}
/* Show device address */
@ -374,6 +396,8 @@ if ((r != SCPE_OK) || (newvec <= VEC_Q) ||
((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) ||
(newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG;
dibp->vec = newvec;
dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */
autcon_enb = 0; /* autoconfig off */
return SCPE_OK;
}
@ -427,14 +451,20 @@ return FALSE;
/* Build interrupt tables */
void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) )
t_bool build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) )
{
int32 ilvl = vloc / 32;
int32 ibit = vloc % 32;
if (iack != NULL) int_ack[ilvl][ibit] = iack;
else int_vec[ilvl][ibit] = ivec;
return;
if (iack != NULL) {
if (int_ack[ilvl][ibit] &&
(int_ack[ilvl][ibit] != iack)) return TRUE;
int_ack[ilvl][ibit] = iack; }
else if (ivec != 0) {
if (int_vec[ilvl][ibit] &&
(int_vec[ilvl][ibit] != ivec)) return TRUE;
int_vec[ilvl][ibit] = ivec; }
return FALSE;
}
/* Build dib_tab from device list */
@ -453,9 +483,15 @@ for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */
if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;
for (k = 0; k < dibp->vnum; k++) /* loop thru vec */
build_int_vec (dibp->vloc + k, /* add vector */
dibp->vec + (k * 4), dibp->ack[k]);
for (k = 0; k < dibp->vnum; k++) { /* loop thru vec */
if (build_int_vec (dibp->vloc + k, /* add vector */
dibp->vec + (k * 4), dibp->ack[k])) {
printf ("Device %s interrupt slot conflict at %d\n",
sim_dname (dptr), dibp->vloc + k);
if (sim_log) fprintf (sim_log,
"Device %s interrupt slot conflict at %d\n",
sim_dname (dptr), dibp->vloc + k);
return SCPE_IERR; } }
if (dibp->lnt != 0) { /* I/O addresses? */
dib_tab[j++] = dibp; /* add DIB to dib_tab */
if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */
@ -575,6 +611,7 @@ DIB *dibp;
int32 i, j, k;
extern DEVICE *find_dev (char *ptr);
if (autcon_enb == 0) return SCPE_OK; /* enabled? */
if (rank > AUTO_LNT) return SCPE_IERR; /* legal rank? */
if (rank) auto_tab[rank - 1].num = nctrl; /* update num? */
for (i = 0, autp = auto_tab; i < AUTO_LNT; i++) { /* loop thru table */

View file

@ -1,6 +1,6 @@
/* pdp11_rk.c: RK11 cartridge disk simulator
/* pdp11_rk.c: RK11/RKV11 cartridge disk simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, 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,8 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rk RK11/RK05 cartridge disk
rk RK11/RKV11/RK05 cartridge disk
29-Dec-03 RMS Added RKV11 support
29-Sep-02 RMS Added variable address support to bootstrap
Added vector change/display support
Revised mapping mnemonics
@ -261,7 +262,7 @@ DEVICE rk_dev = {
RK_NUMDR, 8, 24, 1, 8, 16,
NULL, NULL, &rk_reset,
&rk_boot, NULL, NULL,
&rk_dib, DEV_DISABLE | DEV_UBUS };
&rk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 };
/* I/O dispatch routine, I/O addresses 17777400 - 17777416

View file

@ -26,6 +26,8 @@
rq RQDX3 disk controller
07-Oct-03 RMS Fixed problem with multiple RAUSER drives
17-Sep-03 RMS Fixed MB to LBN conversion to be more accurate
11-Jul-03 RMS Fixed bug in user disk size (found by Chaskiel M Grundman)
19-May-03 RMS Revised for new conditional compilation scheme
25-Apr-03 RMS Revised for extended file support
@ -1422,7 +1424,8 @@ int32 rq_rw_valid (MSC *cp, int32 pkt, UNIT *uptr, uint32 cmd)
uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
uint32 lbn = GETP32 (pkt, RW_LBNL); /* get lbn */
uint32 bc = GETP32 (pkt, RW_BCL); /* get byte cnt */
uint32 maxlbn = drv_tab[dtyp].lbn; /* get max lbn */
uint32 maxlbn = uptr->capac / RQ_NUMBY; /* get max lbn */
/* uint32 maxlbn = drv_tab[dtyp].lbn; /* get max lbn */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return (ST_OFL | SB_OFL_NV); /* offl no vol */
@ -1866,6 +1869,7 @@ return;
void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all)
{
uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
uint32 maxlbn = uptr->capac / RQ_NUMBY; /* get max lbn */
cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */
cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr);
@ -1878,7 +1882,7 @@ cp->pak[pkt].d[ONL_UIDD] = (UID_DISK << ONL_UIDD_V_CLS) |
(drv_tab[dtyp].mod << ONL_UIDD_V_MOD); /* UID hi */
PUTP32 (pkt, ONL_MEDL, drv_tab[dtyp].med); /* media type */
if (all) { /* if long form */
PUTP32 (pkt, ONL_SIZL, drv_tab[dtyp].lbn); /* user LBNs */
PUTP32 (pkt, ONL_SIZL, maxlbn); /* user LBNs */
cp->pak[pkt].d[ONL_VSNL] = 01234 + lu; /* vol serial # */
cp->pak[pkt].d[ONL_VSNH] = 0; }
return;
@ -2012,13 +2016,13 @@ if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
if (cptr) {
cap = (int32) get_uint (cptr, 10, max, &r);
if ((r != SCPE_OK) || (cap < RA8U_MINC)) return SCPE_ARG;
drv_tab[val].lbn = cap << (20 - 9); }
drv_tab[val].lbn = cap * 1954; }
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (val << UNIT_V_DTYPE);
uptr->capac = ((t_addr) drv_tab[val].lbn) * RQ_NUMBY;
return SCPE_OK;
}
/* Show unit type (and capacity if user defined) */
/* Show unit type */
t_stat rq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc)
{
@ -2034,7 +2038,6 @@ int32 dtyp = GET_DTYPE (uptr->flags);
MSC *cp = rq_ctxmap[uptr->cnum];
t_stat r;
uptr->capac = drv_tab[dtyp].lbn * RQ_NUMBY;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
if (cp->csta == CST_UP) uptr->flags = uptr->flags | UNIT_ATP;

View file

@ -121,7 +121,7 @@ int32 rx_cwait = 100; /* command time */
int32 rx_swait = 10; /* seek, per track */
int32 rx_xwait = 1; /* tr set time */
uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */
static int32 bptr = 0; /* buffer pointer */
int32 rx_bptr = 0; /* buffer pointer */
int32 rx_enb = 1; /* device enable */
DEVICE rx_dev;
@ -157,7 +157,7 @@ REG rx_reg[] = {
{ ORDATA (RXTA, rx_track, 8) },
{ ORDATA (RXSA, rx_sector, 8) },
{ DRDATA (STAPTR, rx_state, 3), REG_RO },
{ DRDATA (BUFPTR, bptr, 7) },
{ DRDATA (BUFPTR, rx_bptr, 7) },
{ FLDATA (INT, IREQ (RX), INT_V_RX) },
{ FLDATA (ERR, rx_csr, RXCS_V_ERR) },
{ FLDATA (TR, rx_csr, RXCS_V_TR) },
@ -237,7 +237,7 @@ case 0: /* RXCS */
if ((data & CSR_GO) && (rx_state == IDLE)) { /* new function? */
rx_csr = data & (RXCS_IE + RXCS_DRV + RXCS_FUNC);
drv = ((rx_csr & RXCS_DRV)? 1: 0); /* reselect drive */
bptr = 0; /* clear buf pointer */
rx_bptr = 0; /* clear buf pointer */
switch (RXCS_GETFNC (data)) { /* case on func */
case RXCS_FILL:
rx_state = FILL; /* state = fill */
@ -287,10 +287,10 @@ return SCPE_OK;
RWDS Save sector, set TR, set RWDT
RWDT Save track, set RWXFR
RWXFR Read/write buffer
FILL copy ir to rx_buf[bptr], advance ptr
if bptr > max, finish command, else set tr
EMPTY if bptr > max, finish command, else
copy rx_buf[bptr] to ir, advance ptr, set tr
FILL copy ir to rx_buf[rx_bptr], advance ptr
if rx_bptr > max, finish command, else set tr
EMPTY if rx_bptr > max, finish command, else
copy rx_buf[rx_bptr] to ir, advance ptr, set tr
CMD_COMPLETE copy requested data to ir, finish command
INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
@ -302,6 +302,7 @@ t_stat rx_svc (UNIT *uptr)
{
int32 i, func;
uint32 da;
int8 *fbuf = uptr->filebuf;
func = RXCS_GETFNC (rx_csr); /* get function */
switch (rx_state) { /* case on state */
@ -310,17 +311,17 @@ case IDLE: /* idle */
return SCPE_IERR; /* done */
case EMPTY: /* empty buffer */
if (bptr >= RX_NUMBY) rx_done (0, 0); /* done all? */
if (rx_bptr >= RX_NUMBY) rx_done (0, 0); /* done all? */
else {
rx_dbr = rx_buf[bptr]; /* get next */
bptr = bptr + 1;
rx_dbr = rx_buf[rx_bptr]; /* get next */
rx_bptr = rx_bptr + 1;
rx_csr = rx_csr | RXCS_TR; } /* set xfer */
break;
case FILL: /* fill buffer */
rx_buf[bptr] = rx_dbr; /* write next */
bptr = bptr + 1;
if (bptr < RX_NUMBY) rx_csr = rx_csr | RXCS_TR; /* if more, set xfer */
rx_buf[rx_bptr] = rx_dbr; /* write next */
rx_bptr = rx_bptr + 1;
if (rx_bptr < RX_NUMBY) rx_csr = rx_csr | RXCS_TR; /* more? set xfer */
else rx_done (0, 0); /* else done */
break;
@ -350,13 +351,13 @@ case RWXFR:
if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */
if (func == RXCS_READ) { /* read? */
for (i = 0; i < RX_NUMBY; i++)
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); }
rx_buf[i] = fbuf[da + i]; }
else {
if (uptr->flags & UNIT_WPRT) { /* write and locked? */
rx_done (RXES_WLK, 0100); /* done, error */
break; }
for (i = 0; i < RX_NUMBY; i++) /* write */
*(((int8 *) uptr->filebuf) + da + i) = rx_buf[i];
fbuf[da + i] = rx_buf[i];
da = da + RX_NUMBY;
if (da > uptr->hwmark) uptr->hwmark = da; }
rx_done (0, 0); /* done */
@ -377,7 +378,7 @@ case INIT_COMPLETE: /* init complete */
break; }
da = CALC_DA (1, 1); /* track 1, sector 1 */
for (i = 0; i < RX_NUMBY; i++) /* read sector */
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i);
rx_buf[i] = fbuf[da + i];
rx_done (RXES_ID, 0); /* set done */
if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020;
break; } /* end case state */

View file

@ -1,6 +1,6 @@
/* pdp11_ry.c: RY11/RX02 floppy disk simulator
/* pdp11_ry.c: RX211/RXV21/RX02 floppy disk simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, 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,8 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ry RY11/RX02 floppy disk
ry RX211/RXV21/RX02 floppy disk
29-Dec-03 RMS Added RXV21 support
19-May-03 RMS Revised for new conditional compilation scheme
25-Apr-03 RMS Revised for extended file support
14-Mar-03 RMS Fixed variable size interaction with save/restore
@ -146,7 +147,6 @@ int32 ry_cwait = 100; /* command time */
int32 ry_swait = 10; /* seek, per track */
int32 ry_xwait = 1; /* tr set time */
uint8 rx2xb[RY_NUMBY] = { 0 }; /* sector buffer */
int32 ry_enb = 0; /* device enable */
DEVICE ry_dev;
t_stat ry_rd (int32 *data, int32 PA, int32 access);
@ -227,7 +227,7 @@ DEVICE ry_dev = {
RX_NUMDR, 8, 20, 1, 8, 8,
NULL, NULL, &ry_reset,
&ry_boot, &ry_attach, NULL,
&ry_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS };
&ry_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_Q18 };
/* I/O dispatch routine, I/O addresses 17777170 - 17777172
@ -341,6 +341,7 @@ t_stat ry_svc (UNIT *uptr)
int32 i, t, func, bps;
static uint8 estat[8];
uint32 ba, da;
int8 *fbuf = uptr->filebuf;
func = RYCS_GETFNC (ry_csr); /* get function */
bps = (ry_csr & RYCS_DEN)? RY_NUMBY: RX_NUMBY; /* get sector size */
@ -401,12 +402,12 @@ case RWXFR: /* read/write */
if (func == RYCS_WRDEL) ry_esr = ry_esr | RYES_DD; /* del data? */
if (func == RYCS_READ) { /* read? */
for (i = 0; i < bps; i++)
rx2xb[i] = *(((int8 *) uptr->filebuf) + da + i); }
rx2xb[i] = fbuf[da + i]; }
else { if (uptr->flags & UNIT_WPRT) { /* write and locked? */
ry_done (0, 0100); /* done, error */
break; }
for (i = 0; i < bps; i++) /* write */
*(((int8 *) uptr->filebuf) + da + i) = rx2xb[i];
fbuf[da + i] = rx2xb[i];
da = da + bps;
if (da > uptr->hwmark) uptr->hwmark = da; }
ry_done (0, 0); /* done */
@ -420,8 +421,7 @@ case SDCNF: /* confirm set density */
sim_activate (uptr, ry_cwait * 100); /* schedule operation */
break;
case SDXFR: /* erase disk */
for (i = 0; i < (int32) uptr->capac; i++)
*(((int8 *) uptr->filebuf) + i) = 0;
for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0;
uptr->hwmark = uptr->capac;
if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN;
else uptr->flags = uptr->flags & ~UNIT_DEN;
@ -462,7 +462,7 @@ case INIT_COMPLETE: /* init complete */
break; }
da = CALC_DA (1, 1, bps); /* track 1, sector 1 */
for (i = 0; i < bps; i++) /* read sector */
rx2xb[i] = *(((int8 *) uptr->filebuf) + da + i);
rx2xb[i] = fbuf[da + i];
ry_done (RYES_ID, 0); /* set done */
if ((ry_unit[1].flags & UNIT_ATT) == 0) ry_ecode = 0020;
break; } /* end case state */

View file

@ -1,6 +1,6 @@
/* pdp11_stddev.c: PDP-11 standard I/O devices simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, 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,tto DL11 terminal input/output
clk KW11L line frequency clock
29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support
01-Mar-03 RMS Added SET/SHOW CLOCK FREQ, SET TTI CTRL-C
22-Nov-02 RMS Changed terminal default to 7B for UNIX
@ -319,10 +320,12 @@ t_stat tto_svc (UNIT *uptr)
int32 c;
t_stat r;
c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */
tto_csr = tto_csr | CSR_DONE;
if (tto_csr & CSR_IE) SET_INT (TTO);
c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
if ((r = sim_putchar (c)) != SCPE_OK) return r;
tto_unit.pos = tto_unit.pos + 1;
return SCPE_OK;
}

View file

@ -23,8 +23,10 @@
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-Dec-03 RMS Added second DEUNA/DELUA support
18-Oct-03 RMS Added DECtape off reel message
06-May-03 RMS Added support for second DEQNA/DELQA
09-Jan-03 RMS Added DELUA support
09-Jan-03 RMS Added DELUA/DEUNA support
17-Oct-02 RMS Fixed bugs in branch, SOB address parsing
09-Oct-02 RMS Added DELQA support
12-Sep-02 RMS Added TMSCP, KW11P, RX211 support, RAD50 examine
@ -64,7 +66,7 @@ extern DEVICE dt_dev;
extern DEVICE tm_dev, ts_dev;
extern DEVICE tq_dev;
extern DEVICE xq_dev, xqb_dev;
extern DEVICE xu_dev;
extern DEVICE xu_dev, xub_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern uint16 *M;
@ -113,6 +115,7 @@ DEVICE *sim_devices[] = {
&xq_dev,
&xqb_dev,
&xu_dev,
&xub_dev,
NULL };
const char *sim_stop_messages[] = {
@ -138,7 +141,8 @@ const char *sim_stop_messages[] = {
"Trap vector fetch abort",
"Trap stack push abort",
"RQDX3 consistency error",
"Sanity timer expired" };
"Sanity timer expired"
"DECtape off reel" };
/* Binary loader.

View file

@ -1,6 +1,6 @@
/* pdp11_tc.c: PDP-11 DECtape simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,10 @@
tc TC11/TU56 DECtape
29-Dec-03 RMS Changed initial status to disabled (in Qbus system)
18-Oct-03 RMS Fixed reverse checksum in read all
Added DECtape off reel message
Simplified timing
25-Apr-03 RMS Revised for extended file support
14-Mar-03 RMS Fixed variable size interaction with save/restore
29-Sep-02 RMS Added variable address support to bootstrap
@ -58,13 +62,16 @@
When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format.
DECtape motion is measured in 3b lines. Time between lines is 33.33us.
Tape density is nominally 300 lines per inch. The format of a DECtape is
Tape density is nominally 300 lines per inch. The format of a DECtape (as
taken from the TD8E formatter) is:
reverse end zone 36000 lines ~ 10 feet
reverse end zone 8192 reverse end zone codes ~ 10 feet
reverse buffer 200 interblock codes
block 0
:
block n
forward end zone 36000 lines ~ 10 feet
forward buffer 200 interblock codes
forward end zone 8192 forward end zone codes ~ 10 feet
A block consists of five 18b header words, a tape-specific number of data
words, and five 18b trailer words. All systems except the PDP-8 use a
@ -79,9 +86,9 @@
header word 0 0
header word 1 block number (for forward reads)
header words 2,3 0
header word 4 0
header word 4 checksum (for reverse reads)
:
trailer word 4 checksum
trailer word 4 checksum (for forward reads)
trailer words 3,2 0
trailer word 1 block number (for reverse reads)
trailer word 0 0
@ -106,13 +113,15 @@
/* System independent DECtape constants */
#define DT_EZLIN 36000 /* end zone length */
#define DT_HTLIN 30 /* header/trailer lines */
#define DT_BLKLN 6 /* blk no line in h/t */
#define DT_CSMLN 24 /* checksum line in h/t */
#define DT_HTWRD (DT_HTLIN / DT_WSIZE) /* header/trailer words */
#define DT_BLKWD (DT_BLKLN / DT_WSIZE) /* blk no word in h/t */
#define DT_CSMWD (DT_CSMLN / DT_WSIZE) /* checksum word in h/t */
#define DT_LPERMC 6 /* lines per mark track */
#define DT_BLKWD 1 /* blk no word in h/t */
#define DT_CSMWD 4 /* checksum word in h/t */
#define DT_HTWRD 5 /* header/trailer words */
#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */
#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */
#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */
#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */
#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */
/* 16b, 18b, 36b DECtape constants */
@ -270,8 +279,7 @@ int32 tcba = 0; /* bus address */
int32 tcdt = 0; /* data */
int32 dt_ctime = 100; /* fast cmd time */
int32 dt_ltime = 12; /* interline time */
int32 dt_actime = 54000; /* accel time */
int32 dt_dctime = 72000; /* decel time */
int32 dt_dctime = 40000; /* decel time */
int32 dt_substate = 0;
int32 dt_logblk = 0;
@ -340,7 +348,6 @@ REG dt_reg[] = {
{ FLDATA (IE, tccm, CSR_V_DONE) },
{ DRDATA (CTIME, dt_ctime, 31), REG_NZ },
{ DRDATA (LTIME, dt_ltime, 31), REG_NZ },
{ DRDATA (ACTIME, dt_actime, 31), REG_NZ },
{ DRDATA (DCTIME, dt_dctime, 31), REG_NZ },
{ ORDATA (SUBSTATE, dt_substate, 1) },
{ DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN },
@ -371,7 +378,7 @@ DEVICE dt_dev = {
DT_NUMDR + 1, 8, 24, 1, 8, 18,
NULL, NULL, &dt_reset,
&dt_boot, &dt_attach, &dt_detach,
&dt_dib, DEV_DISABLE | DEV_UBUS };
&dt_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS };
/* IO dispatch routines, I/O addresses 17777340 - 17777350 */
@ -523,7 +530,7 @@ if (new_fnc == FNC_SSEL) { /* stop unit? */
if (prev_mot == DTS_STOP) { /* start? */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* stop current */
sim_activate (uptr, dt_actime); /* schedule accel */
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
return; }
@ -537,7 +544,7 @@ if (prev_dir ^ new_dir) { /* dir chg? */
if (prev_mot < DTS_ACCF) { /* not accel/at speed? */
if (dt_setpos (uptr)) return; /* update pos */
sim_cancel (uptr); /* cancel cur */
sim_activate (uptr, dt_actime); /* schedule accel */
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
return; }
@ -674,11 +681,13 @@ case DTS_STOP: /* stop */
delta = 0;
break;
case DTS_DECF: /* slowing */
ulin = ut / (uint32) dt_ltime; udelt = dt_dctime / dt_ltime;
ulin = ut / (uint32) dt_ltime;
udelt = dt_dctime / dt_ltime;
delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
break;
case DTS_ACCF: /* accelerating */
ulin = ut / (uint32) dt_ltime; udelt = dt_actime / dt_ltime;
ulin = ut / (uint32) dt_ltime;
udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime;
delta = (ulin * ulin) / (2 * udelt);
break;
case DTS_ATSF: /* at speed */
@ -715,7 +724,7 @@ t_stat dt_svc (UNIT *uptr)
int32 mot = DTS_GETMOT (uptr->STATE);
int32 dir = mot & DTS_DIR;
int32 fnc = DTS_GETFNC (uptr->STATE);
int32 *bptr = uptr->filebuf;
int32 *fbuf = uptr->filebuf;
int32 blk, wrd, relpos, dat;
uint32 ba, ma, mma;
@ -728,10 +737,10 @@ uint32 ba, ma, mma;
switch (mot) {
case DTS_DECF: case DTS_DECR: /* decelerating */
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */
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_dctime - (dt_dctime >> 2)); /* reversing */
return SCPE_OK;
case DTS_ACCF: case DTS_ACCR: /* accelerating */
dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
@ -748,7 +757,7 @@ default: /* other */
Off reel - detach unit (it must be deselected)
*/
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */
if (DT_QEZ (uptr)) { /* in end zone? */
dt_seterr (uptr, STA_END); /* end zone error */
return SCPE_OK; }
@ -785,7 +794,7 @@ case FNC_READ: /* read */
dt_seterr (uptr, STA_NXM);
break; }
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
M[mma >> 1] = tcdt = bptr[ba] & DMASK; /* read word */
M[mma >> 1] = tcdt = fbuf[ba] & DMASK; /* read word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm);
@ -822,7 +831,7 @@ case FNC_WRIT: /* write */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm); }
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
bptr[ba] = tcdt; /* write word */
fbuf[ba] = tcdt; /* write word */
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
if (tcwc == 0) dt_substate = 1;
if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */
@ -844,7 +853,7 @@ case FNC_RALL:
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
dat = bptr[ba]; } /* get tape word */
dat = fbuf[ba]; } /* get tape word */
else dat = dt_gethdr (uptr, blk, relpos); /* get hdr */
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
tcdt = dat & DMASK; /* low 16b */
@ -866,7 +875,7 @@ case FNC_WALL:
dat = (STA_GETXD (tcst) << 16) | tcdt; /* get data word */
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
bptr[ba] = dat; /* write word */
fbuf[ba] = dat; /* write word */
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; }
/* else /* ignore hdr */
sim_activate (uptr, DT_WSIZE * dt_ltime);
@ -941,13 +950,13 @@ return dat;
int32 dt_csum (UNIT *uptr, int32 blk)
{
int32 *bptr = uptr->filebuf;
int32 *fbuf = uptr->filebuf;
int32 ba = blk * DTU_BSIZE (uptr);
int32 i, csum, wrd;
csum = 077; /* init csum */
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
wrd = bptr[ba + i] ^ 0777777; /* get ~word */
wrd = fbuf[ba + i] ^ 0777777; /* get ~word */
csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; }
return (csum & 077);
}
@ -959,6 +968,7 @@ int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos)
int32 wrd = relpos / DT_WSIZE;
if (wrd == DT_BLKWD) return blk; /* fwd blknum */
if (wrd == DT_CSMWD) return 077; /* rev csum */
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
return (dt_csum (uptr, blk) << 12);
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */
@ -1067,7 +1077,7 @@ t_stat dt_attach (UNIT *uptr, char *cptr)
{
uint16 pdp8b[D8_NBSIZE];
uint16 pdp11b[D18_BSIZE];
uint32 ba, sz, k, *bptr;
uint32 ba, sz, k, *fbuf;
int32 u = uptr - dt_dev.units;
t_stat r;
@ -1089,7 +1099,7 @@ uptr->filebuf = calloc (uptr->capac, sizeof (int32));
if (uptr->filebuf == NULL) { /* can't alloc? */
detach_unit (uptr);
return SCPE_MEM; }
bptr = uptr->filebuf; /* file buffer */
fbuf = uptr->filebuf; /* file buffer */
printf ("%s%d: ", sim_dname (&dt_dev), u);
if (uptr->flags & UNIT_8FMT) printf ("12b format");
else if (uptr->flags & UNIT_11FMT) printf ("16b format");
@ -1101,9 +1111,9 @@ if (uptr->flags & UNIT_8FMT) { /* 12b? */
if (k == 0) break;
for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0;
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */
bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
fbuf[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
((uint32) (pdp8b[k + 1] >> 6) & 077);
bptr[ba + 1] = ((pdp8b[k + 1] & 077) << 12) |
fbuf[ba + 1] = ((pdp8b[k + 1] & 077) << 12) |
((uint32) (pdp8b[k + 2] & 07777));
ba = ba + 2; } /* end blk loop */
} /* end file loop */
@ -1114,7 +1124,7 @@ else if (uptr->flags & UNIT_11FMT) { /* 16b? */
if (k == 0) break;
for ( ; k < D18_BSIZE; k++) pdp11b[k] = 0;
for (k = 0; k < D18_BSIZE; k++)
bptr[ba++] = pdp11b[k]; }
fbuf[ba++] = pdp11b[k]; }
uptr->hwmark = ba; } /* end elif */
else uptr->hwmark = fxread (uptr->filebuf, sizeof (int32),
uptr->capac, uptr->fileref);
@ -1137,7 +1147,7 @@ t_stat dt_detach (UNIT* uptr)
{
uint16 pdp8b[D8_NBSIZE];
uint16 pdp11b[D18_BSIZE];
uint32 ba, k, *bptr;
uint32 ba, k, *fbuf;
int32 u = uptr - dt_dev.units;
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
@ -1148,17 +1158,17 @@ if (sim_is_active (uptr)) { /* active? cancel op */
tccm = tccm | CSR_ERR | CSR_DONE;
if (tccm & CSR_IE) SET_INT (DTA); }
uptr->STATE = uptr->pos = 0; }
bptr = uptr->filebuf; /* file buffer */
fbuf = uptr->filebuf; /* file buffer */
if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u);
rewind (uptr->fileref); /* start of file */
if (uptr->flags & UNIT_8FMT) { /* 12b? */
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */
pdp8b[k] = (bptr[ba] >> 6) & 07777;
pdp8b[k + 1] = ((bptr[ba] & 077) << 6) |
((bptr[ba + 1] >> 12) & 077);
pdp8b[k + 2] = bptr[ba + 1] & 07777;
pdp8b[k] = (fbuf[ba] >> 6) & 07777;
pdp8b[k + 1] = ((fbuf[ba] & 077) << 6) |
((fbuf[ba + 1] >> 12) & 077);
pdp8b[k + 2] = fbuf[ba + 1] & 07777;
ba = ba + 2; } /* end loop blk */
fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref);
if (ferror (uptr->fileref)) break; } /* end loop file */
@ -1166,7 +1176,7 @@ if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
else if (uptr->flags & UNIT_11FMT) { /* 16b? */
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
for (k = 0; k < D18_BSIZE; k++) /* loop blk */
pdp11b[k] = bptr[ba++] & DMASK;
pdp11b[k] = fbuf[ba++] & DMASK;
fxwrite (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref);
if (ferror (uptr->fileref)) break; } /* end loop file */
} /* end if 16b */

View file

@ -1,6 +1,6 @@
/* pdp11_tm.c: PDP-11 magnetic tape simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
tm TM11/TU10 magtape
29-Dec-03 RMS Added 18b Qbus support
25-Apr-03 RMS Revised for extended file support
28-Mar-03 RMS Added multiformat support
28-Feb-03 RMS Revised for magtape library, added logging
@ -231,7 +232,7 @@ DEVICE tm_dev = {
TM_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &tm_reset,
&tm_boot, &tm_attach, &tm_detach,
&tm_dib, DEV_DISABLE | DEV_UBUS };
&tm_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 };
/* I/O dispatch routine, I/O addresses 17772520 - 17772532

View file

@ -69,6 +69,27 @@
Modification history:
03-Dec-03 DTH Added minimum name length to show xq eth
25-Nov-03 DTH Reworked interrupts to fix broken XQB implementation
19-Nov-03 MP Rearranged timer reset sequencing to allow for a device to be
disabled after it had been enabled.
17-Nov-03 DTH Standardized #include of timeb.h
28-Sep-03 MP - Fixed bug in xq_process_setup which would leave the
device in promiscuous or all multicast mode once it
ever had been there.
- Fixed output format in show_xq_sanity to end in "\n"
- Added display of All Multicase and promiscuous to
xq_show_filters
- The stuck in All Multicast or Promiscuous issue is
worse than previously thought. See comments in
xq_process_setup.
- Change xq_setmac to also allow ":" as a address
separator character, since sim_ether's eth_mac_fmt
formats them with this separator character.
- Changed xq_sw_reset to behave more like the set of
actions described in Table 3-6 of the DELQA manua.
The manual mentions "N/A" which I'm interpreting to
mean "Not Affected".
05-Jun-03 DTH Added receive packet splitting
03-Jun-03 DTH Added SHOW XQ FILTERS
02-Jun-03 DTH Added SET/SHOW XQ STATS (packet statistics), runt & giant processing
@ -92,7 +113,7 @@
of Receiver Enabled. This was an issue since the
it seems that at least VMS's XQ driver makes this
transition often and the resulting overhead reduces
the simulated CPU instruction execution thruput by
the simulated CPU instruction execution throughput by
about 40%. I start the system id timer on device
reset and it fires once a second so that it can
leverage the reasonably recalibrated tmr_poll value.
@ -100,7 +121,7 @@
dynamically computed clock values to achieve an
approximate interval of 100 per second. This is
more than sufficient for normal system behaviour
expecially since we service recieves with every
expecially since we service receives with every
transmit. The previous fixed value of 2500
attempted to get 200/sec but it was a guess that
didn't adapt. On faster host systems (possibly
@ -128,7 +149,7 @@
05-Dec-02 MP Restructured the flow of processing in xq_svc so that eth_read
is called repeatedly until either a packet isn't found or
there is no room for another one in the queue. Once that has
been done, xq_processrdbl is called to pass the queued packets
been done, xq_process_rdbl is called to pass the queued packets
into the simulated system as space is available there.
xq_process_rdbl is also called at the beginning of xq_svc to
drain the queue into the simulated system, making more room
@ -216,8 +237,6 @@ t_stat xq_process_xbdl(CTLR* xq);
t_stat xq_dispatch_xbdl(CTLR* xq);
void xq_start_receiver(void);
void xq_sw_reset(CTLR* xq);
int32 xq_inta (void);
int32 xq_intb (void);
t_stat xq_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
void xq_start_santmr(CTLR* xq);
@ -230,6 +249,9 @@ void xqa_read_callback(int status);
void xqb_read_callback(int status);
void xqa_write_callback(int status);
void xqb_write_callback(int status);
void xq_setint (CTLR* xq);
void xq_clrint (CTLR* xq);
int32 xq_int (void);
struct xq_device xqa = {
xqa_read_callback, /* read callback routine */
@ -249,7 +271,7 @@ struct xq_device xqb = {
/* SIMH device structures */
DIB xqa_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr,
1, IVCL (XQ), 0, { &xq_inta } };
1, IVCL (XQ), 0, { &xq_int } };
UNIT xqa_unit[] = {
{ UDATA (&xq_svc, UNIT_ATTABLE + UNIT_DISABLE, 2047) }, /* receive timer */
@ -268,6 +290,7 @@ REG xqa_reg[] = {
{ GRDATA ( XBDL, xqa.xbdl, XQ_RDX, 32, 0) },
{ GRDATA ( VAR, xqa.var, XQ_RDX, 16, 0) },
{ GRDATA ( CSR, xqa.csr, XQ_RDX, 16, 0) },
{ FLDATA ( INT, xqa.irq, 0) },
{ GRDATA ( SETUP_PRM, xqa.setup.promiscuous, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_MLT, xqa.setup.multicast, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_L1, xqa.setup.l1, XQ_RDX, 32, 0), REG_HRO},
@ -279,7 +302,7 @@ REG xqa_reg[] = {
};
DIB xqb_dib = { IOBA_XQB, IOLN_XQB, &xq_rd, &xq_wr,
1, IVCL (XQ), 0, { &xq_intb } };
1, IVCL (XQ), 0, { &xq_int } };
UNIT xqb_unit[] = {
{ UDATA (&xq_svc, UNIT_ATTABLE + UNIT_DISABLE, 2047) }, /* receive timer */
@ -298,6 +321,7 @@ REG xqb_reg[] = {
{ GRDATA ( XBDL, xqb.xbdl, XQ_RDX, 32, 0) },
{ GRDATA ( VAR, xqb.var, XQ_RDX, 16, 0) },
{ GRDATA ( CSR, xqb.csr, XQ_RDX, 16, 0) },
{ FLDATA ( INT, xqb.irq, 0) },
{ GRDATA ( SETUP_PRM, xqb.setup.promiscuous, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_MLT, xqb.setup.multicast, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_L1, xqb.setup.l1, XQ_RDX, 32, 0), REG_HRO},
@ -372,7 +396,7 @@ void xq_csr_changes(CTLR* xq, uint16 data);
void xq_var_changes(CTLR* xq, uint16 data);
/* sanity timer debugging */
#include <sys\timeb.h>
#include <sys/timeb.h>
struct timeb start, finish;
#endif /* XQ_DEBUG */
@ -575,7 +599,9 @@ t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc)
if (len != 17) return SCPE_ARG;
/* make sure byte separators are OK */
for (i=2; i<len; i=i+3) {
if ((cptr[i] != '-') && (cptr[i] != '.')) return SCPE_ARG;
if ((cptr[i] != '-') &&
(cptr[i] != '.') &&
(cptr[i] != ':')) return SCPE_ARG;
cptr[i] = '\0';
}
/* get and set address bytes */
@ -601,15 +627,17 @@ t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc)
t_stat xq_showeth (FILE* st, UNIT* uptr, int32 val, void* desc)
{
#define XQ_MAX_LIST 10
int i;
ETH_LIST list[XQ_MAX_LIST];
int number = eth_devices(XQ_MAX_LIST, list);
fprintf(st, "ETH devices:\n");
if (number)
if (number) {
int i, min, len;
for (i=0, min=0; i<number; i++)
if ((len = strlen(list[i].name)) > min) min = len;
for (i=0; i<number; i++)
fprintf(st," %d %s (%s)\n", i, list[i].name, list[i].desc);
else
fprintf(st," %d %-*s (%s)\n", i, min, list[i].name, list[i].desc);
} else
fprintf(st, " no network devices are available\n");
return SCPE_OK;
}
@ -662,6 +690,10 @@ t_stat xq_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc)
eth_mac_fmt((ETH_MAC*)xq->var->setup.macs[i], buffer);
fprintf(st, " [%2d]: %s\n", i, buffer);
};
if (xq->var->setup.multicast)
fprintf(st, "All Multicast Receive Mode\n");
if (xq->var->setup.promiscuous)
fprintf(st, "Promiscuous Receive Mode\n");
return SCPE_OK;
}
@ -695,8 +727,8 @@ t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc)
fprintf(st, "sanity=");
switch (xq->var->sanity.enabled) {
case 0: fprintf(st, "OFF"); break;
case 1: fprintf(st, "ON"); break;
case 0: fprintf(st, "OFF\n"); break;
case 1: fprintf(st, "ON\n"); break;
}
return SCPE_OK;
}
@ -724,7 +756,7 @@ t_stat xq_nxm_error(CTLR* xq)
/* interrupt if required */
if (xq->var->csr & XQ_CSR_IE)
SET_INT(XQ);
xq_setint(xq);
return SCPE_OK;
}
@ -761,7 +793,7 @@ void xq_write_callback (CTLR* xq, int status)
/* update csr */
xq->var->csr |= XQ_CSR_XI;
if (xq->var->csr & XQ_CSR_IE)
SET_INT(XQ);
xq_setint(xq);
/* reset sanity timer */
xq_reset_santmr(xq);
@ -846,7 +878,7 @@ t_stat xq_process_rbdl(CTLR* xq)
uint16 b_length, w_length, rbl;
uint32 address;
struct xq_msg_itm* item;
char* rbuf;
uint8* rbuf;
#ifdef XQ_DEBUG
fprintf(stderr,"%s: CSR - Processing read\n", xq->dev->name);
@ -906,7 +938,7 @@ t_stat xq_process_rbdl(CTLR* xq)
#endif
/* pad runts with zeros up to minimum size - this allows "legal" (size - 60)
processing of those weird short ARP packets that seem to occur occasionally */
memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET);
memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET-rbl);
rbl = ETH_MIN_PACKET;
};
@ -976,7 +1008,7 @@ t_stat xq_process_rbdl(CTLR* xq)
/* mark transmission complete */
xq->var->csr |= XQ_CSR_RI;
if (xq->var->csr & XQ_CSR_IE)
SET_INT(XQ);
xq_setint(xq);
/* set to next bdl (implicit chain) */
xq->var->rbdl_ba += 12;
@ -1059,15 +1091,42 @@ t_stat xq_process_setup(CTLR* xq)
xq->var->setup.macs[i+7][j] = xq->var->write_buffer.msg[(i + 0101) + (j * 8)];
}
/*
Under VMS the setup packet that is passed to turn promiscuous
off after it has been on doesn't seem to follow the rules documented
in both the DEQNA and DELQA manuals.
These rules seem to say that setup packets less than 128 should only
modify the address filter set and probably not the All-Multicast and
Promiscuous modes, however, VMS V5-5 and V7.3 seem to send a 127 byte
packet to turn this functionality off. I'm not sure how real hardware
behaves in this case, since the only consequence is extra interrupt
load. To realize and retain the benefits of the newly added BPF
functionality in sim_ether, I've modified the logic implemented here
to disable Promiscuous mode when a "small" setup packet is processed.
I'm deliberately not modifying the All-Multicast mode the same way
since I don't have an observable case of its behavior. These two
different modes come from very different usage situations:
1) Promiscuous mode is usually entered for relatively short periods
of time due to the needs of a specific application program which
is doing some sort of management/monitoring function (i.e. tcpdump)
2) All-Multicast mode is only entered by the OS Kernel Port Driver
when it happens to have clients (usually network stacks or service
programs) which as a group need to listen to more multicast ethernet
addresses than the 12 (or so) which the hardware supports directly.
so, I believe that the All-Multicast mode, is first rarely used, and if
it ever is used, once set, it will probably be set either forever or for
long periods of time, and the additional interrupt processing load to
deal with the distinctly lower multicast traffic set is clearly lower than
that of the promiscuous mode.
*/
xq->var->setup.promiscuous = 0;
/* process high byte count */
if (xq->var->write_buffer.len > 128) {
uint16 len = xq->var->write_buffer.len;
uint16 led, san;
if (len & XQ_SETUP_MC)
xq->var->setup.multicast = 1;
if (len & XQ_SETUP_PM)
xq->var->setup.promiscuous = 1;
xq->var->setup.multicast = (0 != (len & XQ_SETUP_MC));
xq->var->setup.promiscuous = (0 != (len & XQ_SETUP_PM));
if (led = (len & XQ_SETUP_LD) >> 2) {
switch (led) {
case 1: xq->var->setup.l1 = 0; break;
@ -1214,7 +1273,7 @@ t_stat xq_process_xbdl(CTLR* xq)
/* mark transmission complete */
xq->var->csr |= XQ_CSR_XI;
if (xq->var->csr & XQ_CSR_IE)
SET_INT(XQ);
xq_setint(xq);
/* now trigger "read" of setup or loopback packet */
if (~xq->var->csr & XQ_CSR_RL)
@ -1446,13 +1505,26 @@ void xq_sw_reset(CTLR* xq)
xq->var->csr |= XQ_CSR_OK;
/* clear CPU interrupts */
CLR_INT(XQ);
xq_clrint(xq);
/* flush read queue */
xq_clear_queue(&xq->var->ReadQ);
/* clear setup info */
memset (&xq->var->setup, 0, sizeof(xq->var->setup));
xq->var->setup.multicast = 0;
xq->var->setup.promiscuous = 0;
if (xq->var->etherface) {
int count = 0;
ETH_MAC zeros = {0, 0, 0, 0, 0, 0};
ETH_MAC filters[XQ_FILTER_MAX + 1];
/* set ethernet filter */
/* memcpy (filters[count++], xq->mac, sizeof(ETH_MAC)); */
for (i = 0; i < XQ_FILTER_MAX; i++)
if (memcmp(zeros, &xq->var->setup.macs[i], sizeof(ETH_MAC)))
memcpy (filters[count++], xq->var->setup.macs[i], sizeof(ETH_MAC));
eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous);
}
}
/* write registers: */
@ -1676,7 +1748,7 @@ t_stat xq_process_bootrom (CTLR* xq)
/* mark transmission complete */
xq->var->csr |= XQ_CSR_RI;
if (xq->var->csr & XQ_CSR_IE)
SET_INT(XQ);
xq_setint(xq);
/* reset sanity timer */
xq_reset_santmr(xq);
@ -1724,8 +1796,8 @@ t_stat xq_wr_csr(CTLR* xq, int32 data)
/* check and correct CPU interrupt state */
old_int_state = (saved_csr & XQ_CSR_IE) && (saved_csr & (XQ_CSR_XI | XQ_CSR_RI));
new_int_state = (xq->var->csr & XQ_CSR_IE) && (xq->var->csr & (XQ_CSR_XI | XQ_CSR_RI));
if ( old_int_state && !new_int_state) CLR_INT(XQ);
if (!old_int_state && new_int_state) SET_INT(XQ);
if ( old_int_state && !new_int_state) xq_clrint(xq);
if (!old_int_state && new_int_state) xq_setint(xq);
#ifdef VM_PDP11
/* request boot/diagnostic rom? [PDP-11 only] */
@ -1803,12 +1875,6 @@ t_stat xq_reset(DEVICE* dptr)
/* init control status register */
xq->var->csr = XQ_CSR_RL | XQ_CSR_XL;
/* reset ethernet interface */
if (xq->var->etherface) {
status = eth_filter (xq->var->etherface, 1, &xq->var->mac, 0, 0);
xq->var->csr |= XQ_CSR_OK;
}
/* init read queue (first time only) */
status = xq_init_queue (xq, &xq->var->ReadQ);
if (status != SCPE_OK)
@ -1817,6 +1883,11 @@ t_stat xq_reset(DEVICE* dptr)
/* clear read queue */
xq_clear_queue(&xq->var->ReadQ);
/* reset ethernet interface */
if (xq->var->etherface) {
status = eth_filter (xq->var->etherface, 1, &xq->var->mac, 0, 0);
xq->var->csr |= XQ_CSR_OK;
/* start sanity timer if power-on SANITY is set */
switch (xq->var->type) {
case XQ_T_DEQNA:
@ -1830,6 +1901,8 @@ t_stat xq_reset(DEVICE* dptr)
xq_start_idtmr(xq);
break;
};
}
return SCPE_OK;
}
@ -1841,11 +1914,9 @@ void xq_start_santmr(CTLR* xq)
/* must be recalculated each time since tmr_poll is a dynamic number */
const int32 quarter_sec = (clk_tps * tmr_poll) / 4;
#if 0
#ifdef XQ_DEBUG
fprintf(stderr,"%s: SANITY TIMER ENABLED, qsecs: %d, poll:%d\n",
xq->dev->name, xq->var->sanity.quarter_secs, tmr_poll);
#endif
#endif
if (sim_is_active(xq_santmr)) /* cancel timer, just in case */
sim_cancel(xq_santmr);
@ -1897,12 +1968,10 @@ t_stat xq_sansvc(UNIT* uptr)
If this section is entered, it means that the sanity timer has expired
without being reset, and the controller must reboot the processor.
*/
#if 0
#ifdef XQ_DEBUG
ftime(&finish);
fprintf(stderr,"%s: SANITY TIMER EXPIRED, qsecs: %d, poll: %d, elapsed: %d\n",
xq->dev->name, xq->var->sanity.quarter_secs, tmr_poll, finish.time - start.time);
#endif
#endif
xq_boot_host();
}
@ -1944,6 +2013,9 @@ t_stat xq_system_id (CTLR* xq, const ETH_MAC dest, uint16 receipt_id)
uint8* const msg = &system_id.msg[0];
t_stat status;
#ifdef XQ_DEBUG
fprintf(stderr,"%s: SYSTEM ID BROADCAST\n", xq->dev->name);
#endif
memset (&system_id, 0, sizeof(system_id));
memcpy (&msg[0], dest, sizeof(ETH_MAC));
memcpy (&msg[6], xq->var->setup.valid ? xq->var->setup.macs[0] : xq->var->mac, sizeof(ETH_MAC));
@ -2089,6 +2161,9 @@ t_stat xq_attach(UNIT* uptr, char* cptr)
/* turn on transceiver power indicator */
xq->var->csr |= XQ_CSR_OK;
/* reset the device with the new attach info */
xq_reset(xq->dev);
return SCPE_OK;
}
@ -2098,6 +2173,7 @@ t_stat xq_detach(UNIT* uptr)
{
t_stat status;
CTLR* xq = xq_unit2ctlr(uptr);
int i;
if (uptr->flags & UNIT_ATT) {
status = eth_close (xq->var->etherface);
@ -2106,6 +2182,9 @@ t_stat xq_detach(UNIT* uptr)
free(uptr->filename);
uptr->filename = NULL;
uptr->flags &= ~UNIT_ATT;
/* cancel all timers (ethernet, sanity, system_id) */
for (i=0; i<3; i++)
sim_cancel(&xq->unit[i]);
}
/* turn off transceiver power indicator */
@ -2114,14 +2193,38 @@ t_stat xq_detach(UNIT* uptr)
return SCPE_OK;
}
int32 xq_inta (void)
void xq_setint(CTLR* xq)
{
return xqa_dib.vec;
xq->var->irq = 1;
SET_INT(XQ);
return;
}
int32 xq_intb (void)
void xq_clrint(CTLR* xq)
{
return xqb_dib.vec;
int i;
xq->var->irq = 0; /* set controller irq off */
/* clear master interrupt? */
for (i=0; i<XQ_MAX_CONTROLLERS; i++) /* check all controllers.. */
if (xq_ctrl[i].var->irq) { /* if any irqs enabled */
SET_INT(XQ); /* set master interrupt on */
return;
}
CLR_INT(XQ); /* clear master interrupt */
return;
}
int32 xq_int (void)
{
int i;
for (i=0; i<XQ_MAX_CONTROLLERS; i++) {
CTLR* xq = &xq_ctrl[i];
if (xq->var->irq) { /* if interrupt pending */
xq_clrint(xq); /* clear interrupt */
return xq->dib->vec; /* return vector */
}
}
return 0; /* no interrupt request active */
}
/*==============================================================================

View file

@ -28,6 +28,7 @@
Modification history:
25-Nov-03 DTH Added interrupt request flag
02-Jun-03 DTH Added struct xq_stats
28-May-03 DTH Made xq_msg_que.item dynamic
28-May-03 MP Optimized structures, removed rtime variable
@ -152,6 +153,7 @@ struct xq_device {
uint16 xbdl[2];
uint16 var;
uint16 csr;
uint32 irq; /* interrupt request flag */
/* buffers, etc. */
struct xq_setup setup;

View file

@ -24,6 +24,8 @@
in this Software without prior written authorization from Robert M Supnik.
xu DEUNA/DELUNA Ethernet interface (stub)
22-Dec-03 RMS Added second (stub) device
*/
#if defined (VM_PDP10) /* PDP10 version */
@ -61,3 +63,29 @@ DEVICE xu_dev = {
NULL, NULL, NULL,
NULL, NULL, NULL,
&xu_dib, DEV_DIS | DEV_UBUS };
#if defined (VM_PDP11)
/* XUB data structures
xub_dev XUB device descriptor
xub_unit XUB unit list
xub_reg XUB register list
*/
DIB xub_dib = { IOBA_XUB, IOLN_XUB, NULL, NULL,
1, IVCL (XU), VEC_XU, { NULL } };
UNIT xub_unit = { UDATA (NULL, 0, 0) };
REG xub_reg[] = {
{ NULL } };
DEVICE xub_dev = {
"XUB", &xub_unit, xub_reg, NULL,
1, 8, 8, 1, 8, 8,
NULL, NULL, NULL,
NULL, NULL, NULL,
&xub_dib, DEV_DIS | DEV_UBUS };
#endif

View file

@ -1,6 +1,6 @@
/* pdp18b_cpu.c: 18b PDP CPU simulator
Copyright (c) 1993-2003, Robert M Supnik
Copyright (c) 1993-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,10 @@
cpu PDP-4/7/9/15 central processor
31-Dec-03 RMS Fixed bug in cpu_set_hist
02-Nov-03 RMS Changed PDP-9,-15 default to API
26-Oct-03 RMS Fixed bug in PDP-4,-7,-9 autoincrement addressing
19-Sep-03 RMS Changed instruction history to be dynamically sized
31-Aug-03 RMS Added instruction history
Fixed PDP-15-specific implementation of API priorities
16-Aug-03 RMS Fixed PDP-15-specific handling of EAE unsigned mul/div
@ -277,9 +281,11 @@
#define UNIT_XVM (1 << UNIT_V_XVM)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define HIST_SIZE 4096
#define HIST_API 0x40000000
#define HIST_PI 0x20000000
#define HIST_PC 0x10000000
#define HIST_MIN 64
#define HIST_MAX 65536
#define HIST_M_LVL 0x3F
#define HIST_V_LVL 6
struct InstHistory {
@ -303,7 +309,7 @@ struct InstHistory {
#define PROT_DFLT 0
#define ASW_DFLT 017763
#else
#define API_DFLT UNIT_NOAPI /* for now */
#define API_DFLT 0
#define PROT_DFLT UNIT_PROT
#define ASW_DFLT 017720
#endif
@ -355,7 +361,7 @@ int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
static struct InstHistory hst[HIST_SIZE] = { { 0 } }; /* instruction history */
struct InstHistory *hst = NULL; /* instruction history */
extern int32 sim_int_char;
extern int32 sim_interval;
@ -1510,7 +1516,7 @@ t_stat Ia (int32 ma, int32 *ea, t_bool jmp)
int32 t;
t_stat sta = MM_OK;
if ((ma & B_DAMASK) == 010) { /* autoindex? */
if ((ma & B_DAMASK & ~07) == 010) { /* autoindex? */
Read (ma, &t, DF); /* add 1 before use */
t = (t + 1) & DMASK;
sta = Write (ma, t, DF); }
@ -1588,7 +1594,7 @@ t_stat Ia (int32 ma, int32 *ea, t_bool jmp)
int32 t;
t_stat sta = MM_OK;
if ((ma & B_DAMASK) == 010) { /* autoindex? */
if ((ma & B_DAMASK & ~07) == 010) { /* autoindex? */
ma = ma & 017; /* always in bank 0 */
Read (ma, &t, DF); /* +1 before use */
t = (t + 1) & DMASK;
@ -1799,7 +1805,7 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
if (usmd && (sw & SWMASK ('V'))) {
if (XVM) addr = RelocXVM (addr, REL_C);
else if (RELOC) addr = Reloc15 (addr, REL_C);
if (addr < 0) return STOP_MME; }
if ((int32) addr < 0) return STOP_MME; }
#endif
if (addr >= MEMSIZE) return SCPE_NXM;
if (vptr != NULL) *vptr = M[addr] & DMASK;
@ -1814,7 +1820,7 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
if (usmd && (sw & SWMASK ('V'))) {
if (XVM) addr = RelocXVM (addr, REL_C);
else if (RELOC) addr = Reloc15 (addr, REL_C);
if (addr < 0) return STOP_MME; }
if ((int32) addr < 0) return STOP_MME; }
#endif
if (addr >= MEMSIZE) return SCPE_NXM;
M[addr] = val & DMASK;
@ -1933,11 +1939,20 @@ int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < HIST_SIZE; i++) hst[i].pc = 0;
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_SIZE, &r);
if (r != SCPE_OK) return SCPE_ARG;
hst_lnt = lnt;
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
@ -1952,25 +1967,26 @@ extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
di = hst_p + HIST_SIZE - hst_lnt; /* work forward */
fprintf (st, "PC L AC MQ IR\n\n");
di = hst_p; /* work forward */
for (k = 0; k < hst_lnt; k++) { /* print specified */
h = &hst[(di++) % HIST_SIZE]; /* entry pointer */
if (h->pc == 0) continue; /* filled in? */
if (h->pc & (HIST_API | HIST_PI)) { /* interrupt event? */
h = &hst[(di++) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
l = (h->lac >> 18) & 1; /* link */
fprintf (st, "%06o %o %06o %06o ", h->pc & AMASK, l, h->lac & DMASK, h->mq);
sim_eval[0] = h->ir;
sim_eval[1] = h->ir1;
if ((fprint_sym (st, h->pc & AMASK, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %06o", h->ir);
} /* end else instruction */
else if (h->pc & (HIST_API | HIST_PI)) { /* interrupt event? */
if (h->pc & HIST_PI) /* PI? */
fprintf (st, "%06o PI LVL 0-4 =", h->pc & AMASK);
else fprintf (st, "%06o API %d LVL 0-4 =", h->pc & AMASK, h->mq);
fprintf (st, "%06o PI LVL 0-4 =", h->pc & AMASK);
else fprintf (st, "%06o API %d LVL 0-4 =", h->pc & AMASK, h->mq);
for (j = API_HLVL; j >= 0; j--)
fprintf (st, " %02o", (h->ir >> (j * HIST_V_LVL)) & HIST_M_LVL);
}
else { /* instruction */
l = (h->lac >> 18) & 1; /* link */
fprintf (st, "%06o %o %06o %06o ", h->pc, l, h->lac & DMASK, h->mq);
sim_eval[0] = h->ir;
sim_eval[1] = h->ir1;
if ((fprint_sym (st, h->pc, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %06o", h->ir);
} /* end else instruction */
else continue; /* invalid */
fputc ('\n', st); /* end line */
} /* end for */
return SCPE_OK;
@ -1980,13 +1996,17 @@ return SCPE_OK;
void cpu_inst_hist (int32 addr, int32 inst)
{
hst[hst_p].pc = addr;
t_value word;
hst[hst_p].pc = addr | HIST_PC;
hst[hst_p].ir = inst;
if (cpu_ex (&hst[hst_p].ir1, (addr + 1) & AMASK, &cpu_unit, SWMASK ('V')))
if (cpu_ex (&word, (addr + 1) & AMASK, &cpu_unit, SWMASK ('V')))
hst[hst_p].ir1 = 0;
else hst[hst_p].ir1 = word;
hst[hst_p].lac = LAC;
hst[hst_p].mq = MQ;
hst_p = (hst_p + 1) % HIST_SIZE;
hst_p = (hst_p + 1);
if (hst_p >= hst_lnt) hst_p = 0;
return;
}
@ -2001,6 +2021,7 @@ for (j = 0; j < API_HLVL+1; j++) hst[hst_p].ir =
hst[hst_p].ir1 = 0;
hst[hst_p].lac = 0;
hst[hst_p].mq = lvl;
hst_p = (hst_p + 1) % HIST_SIZE;
hst_p = (hst_p + 1);
if (hst_p >= hst_lnt) hst_p = 0;
return;
}

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.
18-Oct-03 RMS Added DECtape off reel message
18-Jul-03 RMS Added FP15 support
Added XVM support
Added EAE option for PDP-4
@ -110,6 +111,7 @@
#define STOP_NONSTD 6 /* non-std dev num */
#define STOP_MME 7 /* mem mgt error */
#define STOP_FPDIS 8 /* fp inst, fpp disabled */
#define STOP_DTOFF 9 /* DECtape off reel */
/* Peripheral configuration */

View file

@ -154,6 +154,7 @@ The 18b PDP simulators implement several unique stop conditions:
instruction execution
- an FP15 instruction is decoded, the FP15 is disabled,
and register STOP_FPP is set
- a simulated DECtape runs off the end of its real
The PDP-4 and PDP-7 LOAD command supports only "second stage" RIM format
files (alternating DAC address instructions and data):
@ -273,6 +274,16 @@ control registers for the interrupt system.
"addr" signifies the address width of the system (13b for the PDP-4, 15b for
the PDP-7 and PDP-9, 17b for the PDP-15).
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, display length = n
SHOW CPU HISTORY print CPU history
The maximum length for the history is 65536 entries.
2.2 Floating Point Processor (FPP)
The PDP-15 features an optional floating point processor, the FP15 (FPP).
@ -756,7 +767,6 @@ The DECtape controller implements these registers:
9,15 CA 18 current address (memory location 30)
9,15 WC 18 word count (memory location 31)
all LTIME 31 time between lines
all ACTIME 31 time to accelerate to full speed
all DCTIME 31 time to decelerate to a full stop
all SUBSTATE 2 read/write command substate
all POS[0:7] 32 position, in lines, units 0-7
@ -767,8 +777,9 @@ among the DECtape parameters, or the DECtape simulator will fail to
operate correctly.
- LTIME must be at least 6
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
- DCTIME needs to be at least 100 times LTIME
Acceleration time is set to 75% of deceleration time.
2.9 TC59/TU10 Magnetic Tape (MT)

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